From 1dace8c801ac531022bd31a7316a6b4351837617 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 4 Mar 2010 16:10:14 -0500 Subject: [PATCH 001/478] vhost: fix error path in vhost_net_set_backend An error could cause vhost_net_set_backend to exit without unlocking vq->mutex. Fix this. Signed-off-by: Jeff Dike Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index ad37da2b6cb..fcafb6b170f 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -508,12 +508,12 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) /* Verify that ring has been setup correctly. */ if (!vhost_vq_access_ok(vq)) { r = -EFAULT; - goto err; + goto err_vq; } sock = get_socket(fd); if (IS_ERR(sock)) { r = PTR_ERR(sock); - goto err; + goto err_vq; } /* start polling new socket */ @@ -524,12 +524,14 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) vhost_net_disable_vq(n, vq); rcu_assign_pointer(vq->private_data, sock); vhost_net_enable_vq(n, vq); - mutex_unlock(&vq->mutex); done: if (oldsock) { vhost_net_flush_vq(n, index); fput(oldsock->file); } + +err_vq: + mutex_unlock(&vq->mutex); err: mutex_unlock(&n->dev.mutex); return r; From 37000d275721e25af6b49fbb2dbcd04022091276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Thu, 25 Feb 2010 18:53:37 +0000 Subject: [PATCH 002/478] drm/nv50: Remove redundant/incorrect ctxvals initialisation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 11c/004 offset corresponds to PGRAPH reg 0x400828, and is initialised earlier anyway by both our ctxprog generator and blob ctxvals. It's actually incorrect with the generator, since we use different layout on pre-NVA0. Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_graph.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 857a09671a3..08d87b749a5 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -229,10 +229,6 @@ nv50_graph_create_context(struct nouveau_channel *chan) nouveau_grctx_vals_load(dev, ctx); } nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12); - if ((dev_priv->chipset & 0xf0) == 0xa0) - nv_wo32(dev, ctx, 0x00004/4, 0x00000000); - else - nv_wo32(dev, ctx, 0x0011c/4, 0x00000000); dev_priv->engine.instmem.finish_access(dev); return 0; From c82b88d578847909797945824851a6a9a84f9c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Sat, 27 Feb 2010 18:13:35 +0000 Subject: [PATCH 003/478] drm/nouveau: Fix fbcon corruption with font width not divisible by 8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NV50 is nice and has a switch that autoaligns stuff for us. Pre-NV50, we need to align input bitmap width manually. Signed-off-by: Marcin Kościelnicki Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_fbcon.c | 6 +++--- drivers/gpu/drm/nouveau/nv50_fbcon.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 3da90c2c4e6..813b25cec72 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -118,8 +118,8 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) return; } - width = ALIGN(image->width, 32); - dsize = (width * image->height) >> 5; + width = ALIGN(image->width, 8); + dsize = ALIGN(width * image->height, 32) >> 5; if (info->fix.visual == FB_VISUAL_TRUECOLOR || info->fix.visual == FB_VISUAL_DIRECTCOLOR) { @@ -136,8 +136,8 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) ((image->dx + image->width) & 0xffff)); OUT_RING(chan, bg); OUT_RING(chan, fg); - OUT_RING(chan, (image->height << 16) | image->width); OUT_RING(chan, (image->height << 16) | width); + OUT_RING(chan, (image->height << 16) | image->width); OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff)); while (dsize) { diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 993c7126fbd..25a3cd8794f 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -233,7 +233,7 @@ nv50_fbcon_accel_init(struct fb_info *info) BEGIN_RING(chan, NvSub2D, 0x0808, 3); OUT_RING(chan, 0); OUT_RING(chan, 0); - OUT_RING(chan, 0); + OUT_RING(chan, 1); BEGIN_RING(chan, NvSub2D, 0x081c, 1); OUT_RING(chan, 1); BEGIN_RING(chan, NvSub2D, 0x0840, 4); From 3bf777bf0ab112527cea103c3681934a9f41c03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Sun, 28 Feb 2010 23:45:38 +0000 Subject: [PATCH 004/478] drm/nv50: Make ctxprog wait until interrupt handler is done. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will fix races between generated ctxprogs and interrupt handler. Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_grctx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c index d105fcd42ca..9f909abfb5a 100644 --- a/drivers/gpu/drm/nouveau/nv50_grctx.c +++ b/drivers/gpu/drm/nouveau/nv50_grctx.c @@ -64,6 +64,9 @@ #define CP_FLAG_ALWAYS ((2 * 32) + 13) #define CP_FLAG_ALWAYS_FALSE 0 #define CP_FLAG_ALWAYS_TRUE 1 +#define CP_FLAG_INTR ((2 * 32) + 15) +#define CP_FLAG_INTR_NOT_PENDING 0 +#define CP_FLAG_INTR_PENDING 1 #define CP_CTX 0x00100000 #define CP_CTX_COUNT 0x000f0000 @@ -214,6 +217,8 @@ nv50_grctx_init(struct nouveau_grctx *ctx) cp_name(ctx, cp_setup_save); cp_set (ctx, UNK1D, SET); cp_wait(ctx, STATUS, BUSY); + cp_wait(ctx, INTR, PENDING); + cp_bra (ctx, STATUS, BUSY, cp_setup_save); cp_set (ctx, UNK01, SET); cp_set (ctx, SWAP_DIRECTION, SAVE); From 304424e17dd904cef048ef8966d9f54618a915cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Mon, 1 Mar 2010 00:18:39 +0000 Subject: [PATCH 005/478] drm/nv50: Improve PGRAPH interrupt handling. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes nouveau recognise and report more kinds of PGRAPH errors, as well as prevent GPU lockups resulting from some of them. Lots of guesswork was involved and some part of this is probably incorrect. Some potential-lockuop situations are handled by just resetting a whole PGRAPH subunit, which doesn't sound like a "proper" solution, but seems to work just fine... for now. Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 2 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 + drivers/gpu/drm/nouveau/nouveau_irq.c | 609 ++++++++++++++++++++++-- drivers/gpu/drm/nouveau/nouveau_state.c | 5 +- drivers/gpu/drm/nouveau/nv50_fb.c | 32 ++ drivers/gpu/drm/nouveau/nv50_graph.c | 18 + drivers/gpu/drm/nouveau/nv50_grctx.c | 8 +- 7 files changed, 622 insertions(+), 56 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nv50_fb.c diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 32db806f3b5..7f0d807a0d0 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -12,7 +12,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nouveau_dp.o nouveau_grctx.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o nv50_mc.o \ - nv04_fb.o nv10_fb.o nv40_fb.o \ + nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \ nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o \ nv40_graph.o nv50_graph.o \ diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 2f8ce42f072..ad2d75d5dd9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -930,6 +930,10 @@ extern void nv40_fb_takedown(struct drm_device *); extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t, uint32_t, uint32_t); +/* nv50_fb.c */ +extern int nv50_fb_init(struct drm_device *); +extern void nv50_fb_takedown(struct drm_device *); + /* nv04_fifo.c */ extern int nv04_fifo_init(struct drm_device *); extern void nv04_fifo_disable(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 95220ddebb4..2bd59a92fee 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -311,6 +311,31 @@ nouveau_print_bitfield_names_(uint32_t value, #define nouveau_print_bitfield_names(val, namelist) \ nouveau_print_bitfield_names_((val), (namelist), ARRAY_SIZE(namelist)) +struct nouveau_enum_names { + uint32_t value; + const char *name; +}; + +static void +nouveau_print_enum_names_(uint32_t value, + const struct nouveau_enum_names *namelist, + const int namelist_len) +{ + /* + * Caller must have already printed the KERN_* log level for us. + * Also the caller is responsible for adding the newline. + */ + int i; + for (i = 0; i < namelist_len; ++i) { + if (value == namelist[i].value) { + printk("%s", namelist[i].name); + return; + } + } + printk("unknown value 0x%08x", value); +} +#define nouveau_print_enum_names(val, namelist) \ + nouveau_print_enum_names_((val), (namelist), ARRAY_SIZE(namelist)) static int nouveau_graph_chid_from_grctx(struct drm_device *dev) @@ -427,14 +452,16 @@ nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id, struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t nsource = trap->nsource, nstatus = trap->nstatus; - NV_INFO(dev, "%s - nSource:", id); - nouveau_print_bitfield_names(nsource, nsource_names); - printk(", nStatus:"); - if (dev_priv->card_type < NV_10) - nouveau_print_bitfield_names(nstatus, nstatus_names); - else - nouveau_print_bitfield_names(nstatus, nstatus_names_nv10); - printk("\n"); + if (dev_priv->card_type < NV_50) { + NV_INFO(dev, "%s - nSource:", id); + nouveau_print_bitfield_names(nsource, nsource_names); + printk(", nStatus:"); + if (dev_priv->card_type < NV_10) + nouveau_print_bitfield_names(nstatus, nstatus_names); + else + nouveau_print_bitfield_names(nstatus, nstatus_names_nv10); + printk("\n"); + } NV_INFO(dev, "%s - Ch %d/%d Class 0x%04x Mthd 0x%04x " "Data 0x%08x:0x%08x\n", @@ -577,28 +604,503 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); } +static void +nv50_pfb_vm_trap(struct drm_device *dev, int display, const char *name) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t trap[6]; + int i, ch; + uint32_t idx = nv_rd32(dev, 0x100c90); + if (idx & 0x80000000) { + idx &= 0xffffff; + if (display) { + for (i = 0; i < 6; i++) { + nv_wr32(dev, 0x100c90, idx | i << 24); + trap[i] = nv_rd32(dev, 0x100c94); + } + for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) { + struct nouveau_channel *chan = dev_priv->fifos[ch]; + + if (!chan || !chan->ramin) + continue; + + if (trap[1] == chan->ramin->instance >> 12) + break; + } + NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x %08x channel %d\n", + name, (trap[5]&0x100?"read":"write"), + trap[5]&0xff, trap[4]&0xffff, + trap[3]&0xffff, trap[0], trap[2], ch); + } + nv_wr32(dev, 0x100c90, idx | 0x80000000); + } else if (display) { + NV_INFO(dev, "%s - no VM fault?\n", name); + } +} + +static struct nouveau_enum_names nv50_mp_exec_error_names[] = +{ + { 3, "STACK_UNDERFLOW" }, + { 4, "QUADON_ACTIVE" }, + { 8, "TIMEOUT" }, + { 0x10, "INVALID_OPCODE" }, + { 0x40, "BREAKPOINT" }, +}; + +static void +nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t units = nv_rd32(dev, 0x1540); + uint32_t addr, mp10, status, pc, oplow, ophigh; + int i; + int mps = 0; + for (i = 0; i < 4; i++) { + if (!(units & 1 << (i+24))) + continue; + if (dev_priv->chipset < 0xa0) + addr = 0x408200 + (tpid << 12) + (i << 7); + else + addr = 0x408100 + (tpid << 11) + (i << 7); + mp10 = nv_rd32(dev, addr + 0x10); + status = nv_rd32(dev, addr + 0x14); + if (!status) + continue; + if (display) { + nv_rd32(dev, addr + 0x20); + pc = nv_rd32(dev, addr + 0x24); + oplow = nv_rd32(dev, addr + 0x70); + ophigh= nv_rd32(dev, addr + 0x74); + NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - " + "TP %d MP %d: ", tpid, i); + nouveau_print_enum_names(status, + nv50_mp_exec_error_names); + printk(" at %06x warp %d, opcode %08x %08x\n", + pc&0xffffff, pc >> 24, + oplow, ophigh); + } + nv_wr32(dev, addr + 0x10, mp10); + nv_wr32(dev, addr + 0x14, 0); + mps++; + } + if (!mps && display) + NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: " + "No MPs claiming errors?\n", tpid); +} + +static void +nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, + uint32_t ustatus_new, int display, const char *name) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int tps = 0; + uint32_t units = nv_rd32(dev, 0x1540); + int i, r; + uint32_t ustatus_addr, ustatus; + for (i = 0; i < 16; i++) { + if (!(units & (1 << i))) + continue; + if (dev_priv->chipset < 0xa0) + ustatus_addr = ustatus_old + (i << 12); + else + ustatus_addr = ustatus_new + (i << 11); + ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff; + if (!ustatus) + continue; + tps++; + switch (type) { + case 6: /* texture error... unknown for now */ + nv50_pfb_vm_trap(dev, display, name); + if (display) { + NV_ERROR(dev, "magic set %d:\n", i); + for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) + NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, + nv_rd32(dev, r)); + } + break; + case 7: /* MP error */ + if (ustatus & 0x00010000) { + nv50_pgraph_mp_trap(dev, i, display); + ustatus &= ~0x00010000; + } + break; + case 8: /* TPDMA error */ + { + uint32_t e0c = nv_rd32(dev, ustatus_addr + 4); + uint32_t e10 = nv_rd32(dev, ustatus_addr + 8); + uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc); + uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10); + uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); + uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); + uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); + nv50_pfb_vm_trap(dev, display, name); + /* 2d engine destination */ + if (ustatus & 0x00000010) { + if (display) { + NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", + i, e14, e10); + NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + i, e0c, e18, e1c, e20, e24); + } + ustatus &= ~0x00000010; + } + /* Render target */ + if (ustatus & 0x00000040) { + if (display) { + NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", + i, e14, e10); + NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + i, e0c, e18, e1c, e20, e24); + } + ustatus &= ~0x00000040; + } + /* CUDA memory: l[], g[] or stack. */ + if (ustatus & 0x00000080) { + if (display) { + if (e18 & 0x80000000) { + /* g[] read fault? */ + NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n", + i, e14, e10 | ((e18 >> 24) & 0x1f)); + e18 &= ~0x1f000000; + } else if (e18 & 0xc) { + /* g[] write fault? */ + NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", + i, e14, e10 | ((e18 >> 7) & 0x1f)); + e18 &= ~0x00000f80; + } else { + NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", + i, e14, e10); + } + NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + i, e0c, e18, e1c, e20, e24); + } + ustatus &= ~0x00000080; + } + } + break; + } + if (ustatus) { + if (display) + NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); + } + nv_wr32(dev, ustatus_addr, 0xc0000000); + } + + if (!tps && display) + NV_INFO(dev, "%s - No TPs claiming errors?\n", name); +} + +static void +nv50_pgraph_trap_handler(struct drm_device *dev) +{ + struct nouveau_pgraph_trap trap; + uint32_t status = nv_rd32(dev, 0x400108); + uint32_t ustatus; + int display = nouveau_ratelimit(); + + + if (!status && display) { + nouveau_graph_trap_info(dev, &trap); + nouveau_graph_dump_trap_info(dev, "PGRAPH_TRAP", &trap); + NV_INFO(dev, "PGRAPH_TRAP - no units reporting traps?\n"); + } + + /* DISPATCH: Relays commands to other units and handles NOTIFY, + * COND, QUERY. If you get a trap from it, the command is still stuck + * in DISPATCH and you need to do something about it. */ + if (status & 0x001) { + ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff; + if (!ustatus && display) { + NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n"); + } + + /* Known to be triggered by screwed up NOTIFY and COND... */ + if (ustatus & 0x00000001) { + nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT"); + nv_wr32(dev, 0x400500, 0); + if (nv_rd32(dev, 0x400808) & 0x80000000) { + if (display) { + if (nouveau_graph_trapped_channel(dev, &trap.channel)) + trap.channel = -1; + trap.class = nv_rd32(dev, 0x400814); + trap.mthd = nv_rd32(dev, 0x400808) & 0x1ffc; + trap.subc = (nv_rd32(dev, 0x400808) >> 16) & 0x7; + trap.data = nv_rd32(dev, 0x40080c); + trap.data2 = nv_rd32(dev, 0x400810); + nouveau_graph_dump_trap_info(dev, + "PGRAPH_TRAP_DISPATCH_FAULT", &trap); + NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400808: %08x\n", nv_rd32(dev, 0x400808)); + NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400848: %08x\n", nv_rd32(dev, 0x400848)); + } + nv_wr32(dev, 0x400808, 0); + } else if (display) { + NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - No stuck command?\n"); + } + nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3); + nv_wr32(dev, 0x400848, 0); + ustatus &= ~0x00000001; + } + if (ustatus & 0x00000002) { + nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY"); + nv_wr32(dev, 0x400500, 0); + if (nv_rd32(dev, 0x40084c) & 0x80000000) { + if (display) { + if (nouveau_graph_trapped_channel(dev, &trap.channel)) + trap.channel = -1; + trap.class = nv_rd32(dev, 0x400814); + trap.mthd = nv_rd32(dev, 0x40084c) & 0x1ffc; + trap.subc = (nv_rd32(dev, 0x40084c) >> 16) & 0x7; + trap.data = nv_rd32(dev, 0x40085c); + trap.data2 = 0; + nouveau_graph_dump_trap_info(dev, + "PGRAPH_TRAP_DISPATCH_QUERY", &trap); + NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - 40084c: %08x\n", nv_rd32(dev, 0x40084c)); + } + nv_wr32(dev, 0x40084c, 0); + } else if (display) { + NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - No stuck command?\n"); + } + ustatus &= ~0x00000002; + } + if (ustatus && display) + NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - Unhandled ustatus 0x%08x\n", ustatus); + nv_wr32(dev, 0x400804, 0xc0000000); + nv_wr32(dev, 0x400108, 0x001); + status &= ~0x001; + } + + /* TRAPs other than dispatch use the "normal" trap regs. */ + if (status && display) { + nouveau_graph_trap_info(dev, &trap); + nouveau_graph_dump_trap_info(dev, + "PGRAPH_TRAP", &trap); + } + + /* M2MF: Memory to memory copy engine. */ + if (status & 0x002) { + ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff; + if (!ustatus && display) { + NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n"); + } + if (ustatus & 0x00000001) { + nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY"); + ustatus &= ~0x00000001; + } + if (ustatus & 0x00000002) { + nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN"); + ustatus &= ~0x00000002; + } + if (ustatus & 0x00000004) { + nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT"); + ustatus &= ~0x00000004; + } + NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n", + nv_rd32(dev, 0x406804), + nv_rd32(dev, 0x406808), + nv_rd32(dev, 0x40680c), + nv_rd32(dev, 0x406810)); + if (ustatus && display) + NV_INFO(dev, "PGRAPH_TRAP_M2MF - Unhandled ustatus 0x%08x\n", ustatus); + /* No sane way found yet -- just reset the bugger. */ + nv_wr32(dev, 0x400040, 2); + nv_wr32(dev, 0x400040, 0); + nv_wr32(dev, 0x406800, 0xc0000000); + nv_wr32(dev, 0x400108, 0x002); + status &= ~0x002; + } + + /* VFETCH: Fetches data from vertex buffers. */ + if (status & 0x004) { + ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff; + if (!ustatus && display) { + NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n"); + } + if (ustatus & 0x00000001) { + nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT"); + NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n", + nv_rd32(dev, 0x400c00), + nv_rd32(dev, 0x400c08), + nv_rd32(dev, 0x400c0c), + nv_rd32(dev, 0x400c10)); + ustatus &= ~0x00000001; + } + if (ustatus && display) + NV_INFO(dev, "PGRAPH_TRAP_VFETCH - Unhandled ustatus 0x%08x\n", ustatus); + nv_wr32(dev, 0x400c04, 0xc0000000); + nv_wr32(dev, 0x400108, 0x004); + status &= ~0x004; + } + + /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ + if (status & 0x008) { + ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff; + if (!ustatus && display) { + NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n"); + } + if (ustatus & 0x00000001) { + nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT"); + NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n", + nv_rd32(dev, 0x401804), + nv_rd32(dev, 0x401808), + nv_rd32(dev, 0x40180c), + nv_rd32(dev, 0x401810)); + ustatus &= ~0x00000001; + } + if (ustatus && display) + NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - Unhandled ustatus 0x%08x\n", ustatus); + /* No sane way found yet -- just reset the bugger. */ + nv_wr32(dev, 0x400040, 0x80); + nv_wr32(dev, 0x400040, 0); + nv_wr32(dev, 0x401800, 0xc0000000); + nv_wr32(dev, 0x400108, 0x008); + status &= ~0x008; + } + + /* CCACHE: Handles code and c[] caches and fills them. */ + if (status & 0x010) { + ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff; + if (!ustatus && display) { + NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n"); + } + if (ustatus & 0x00000001) { + nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT"); + NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n", + nv_rd32(dev, 0x405800), + nv_rd32(dev, 0x405804), + nv_rd32(dev, 0x405808), + nv_rd32(dev, 0x40580c), + nv_rd32(dev, 0x405810), + nv_rd32(dev, 0x405814), + nv_rd32(dev, 0x40581c)); + ustatus &= ~0x00000001; + } + if (ustatus && display) + NV_INFO(dev, "PGRAPH_TRAP_CCACHE - Unhandled ustatus 0x%08x\n", ustatus); + nv_wr32(dev, 0x405018, 0xc0000000); + nv_wr32(dev, 0x400108, 0x010); + status &= ~0x010; + } + + /* Unknown, not seen yet... 0x402000 is the only trap status reg + * remaining, so try to handle it anyway. Perhaps related to that + * unknown DMA slot on tesla? */ + if (status & 0x20) { + nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04"); + ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff; + if (display) + NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus); + nv_wr32(dev, 0x402000, 0xc0000000); + /* no status modifiction on purpose */ + } + + /* TEXTURE: CUDA texturing units */ + if (status & 0x040) { + nv50_pgraph_tp_trap (dev, 6, 0x408900, 0x408600, display, + "PGRAPH_TRAP_TEXTURE"); + nv_wr32(dev, 0x400108, 0x040); + status &= ~0x040; + } + + /* MP: CUDA execution engines. */ + if (status & 0x080) { + nv50_pgraph_tp_trap (dev, 7, 0x408314, 0x40831c, display, + "PGRAPH_TRAP_MP"); + nv_wr32(dev, 0x400108, 0x080); + status &= ~0x080; + } + + /* TPDMA: Handles TP-initiated uncached memory accesses: + * l[], g[], stack, 2d surfaces, render targets. */ + if (status & 0x100) { + nv50_pgraph_tp_trap (dev, 8, 0x408e08, 0x408708, display, + "PGRAPH_TRAP_TPDMA"); + nv_wr32(dev, 0x400108, 0x100); + status &= ~0x100; + } + + if (status) { + if (display) + NV_INFO(dev, "PGRAPH_TRAP - Unknown trap 0x%08x\n", + status); + nv_wr32(dev, 0x400108, status); + } +} + +/* There must be a *lot* of these. Will take some time to gather them up. */ +static struct nouveau_enum_names nv50_data_error_names[] = +{ + { 4, "INVALID_VALUE" }, + { 5, "INVALID_ENUM" }, + { 8, "INVALID_OBJECT" }, + { 0xc, "INVALID_BITFIELD" }, + { 0x28, "MP_NO_REG_SPACE" }, + { 0x2b, "MP_BLOCK_SIZE_MISMATCH" }, +}; + static void nv50_pgraph_irq_handler(struct drm_device *dev) { + struct nouveau_pgraph_trap trap; + int unhandled = 0; uint32_t status; while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) { - uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); - + /* NOTIFY: You've set a NOTIFY an a command and it's done. */ if (status & 0x00000001) { - nouveau_pgraph_intr_notify(dev, nsource); + nouveau_graph_trap_info(dev, &trap); + if (nouveau_ratelimit()) + nouveau_graph_dump_trap_info(dev, + "PGRAPH_NOTIFY", &trap); status &= ~0x00000001; nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001); } - if (status & 0x00000010) { - nouveau_pgraph_intr_error(dev, nsource | - NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD); + /* COMPUTE_QUERY: Purpose and exact cause unknown, happens + * when you write 0x200 to 0x50c0 method 0x31c. */ + if (status & 0x00000002) { + nouveau_graph_trap_info(dev, &trap); + if (nouveau_ratelimit()) + nouveau_graph_dump_trap_info(dev, + "PGRAPH_COMPUTE_QUERY", &trap); + status &= ~0x00000002; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000002); + } + /* Unknown, never seen: 0x4 */ + + /* ILLEGAL_MTHD: You used a wrong method for this class. */ + if (status & 0x00000010) { + nouveau_graph_trap_info(dev, &trap); + if (nouveau_pgraph_intr_swmthd(dev, &trap)) + unhandled = 1; + if (unhandled && nouveau_ratelimit()) + nouveau_graph_dump_trap_info(dev, + "PGRAPH_ILLEGAL_MTHD", &trap); status &= ~0x00000010; nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010); } + /* ILLEGAL_CLASS: You used a wrong class. */ + if (status & 0x00000020) { + nouveau_graph_trap_info(dev, &trap); + if (nouveau_ratelimit()) + nouveau_graph_dump_trap_info(dev, + "PGRAPH_ILLEGAL_CLASS", &trap); + status &= ~0x00000020; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000020); + } + + /* DOUBLE_NOTIFY: You tried to set a NOTIFY on another NOTIFY. */ + if (status & 0x00000040) { + nouveau_graph_trap_info(dev, &trap); + if (nouveau_ratelimit()) + nouveau_graph_dump_trap_info(dev, + "PGRAPH_DOUBLE_NOTIFY", &trap); + status &= ~0x00000040; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000040); + } + + /* CONTEXT_SWITCH: PGRAPH needs us to load a new context */ if (status & 0x00001000) { nv_wr32(dev, 0x400500, 0x00000000); nv_wr32(dev, NV03_PGRAPH_INTR, @@ -613,49 +1115,59 @@ nv50_pgraph_irq_handler(struct drm_device *dev) status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; } - if (status & 0x00100000) { - nouveau_pgraph_intr_error(dev, nsource | - NV03_PGRAPH_NSOURCE_DATA_ERROR); + /* BUFFER_NOTIFY: Your m2mf transfer finished */ + if (status & 0x00010000) { + nouveau_graph_trap_info(dev, &trap); + if (nouveau_ratelimit()) + nouveau_graph_dump_trap_info(dev, + "PGRAPH_BUFFER_NOTIFY", &trap); + status &= ~0x00010000; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00010000); + } + /* DATA_ERROR: Invalid value for this method, or invalid + * state in current PGRAPH context for this operation */ + if (status & 0x00100000) { + nouveau_graph_trap_info(dev, &trap); + if (nouveau_ratelimit()) { + nouveau_graph_dump_trap_info(dev, + "PGRAPH_DATA_ERROR", &trap); + NV_INFO (dev, "PGRAPH_DATA_ERROR - "); + nouveau_print_enum_names(nv_rd32(dev, 0x400110), + nv50_data_error_names); + printk("\n"); + } status &= ~0x00100000; nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000); } + /* TRAP: Something bad happened in the middle of command + * execution. Has a billion types, subtypes, and even + * subsubtypes. */ if (status & 0x00200000) { - int r; - - nouveau_pgraph_intr_error(dev, nsource | - NV03_PGRAPH_NSOURCE_PROTECTION_ERROR); - - NV_ERROR(dev, "magic set 1:\n"); - for (r = 0x408900; r <= 0x408910; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, - nv_rd32(dev, r)); - nv_wr32(dev, 0x408900, - nv_rd32(dev, 0x408904) | 0xc0000000); - for (r = 0x408e08; r <= 0x408e24; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, - nv_rd32(dev, r)); - nv_wr32(dev, 0x408e08, - nv_rd32(dev, 0x408e08) | 0xc0000000); - - NV_ERROR(dev, "magic set 2:\n"); - for (r = 0x409900; r <= 0x409910; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, - nv_rd32(dev, r)); - nv_wr32(dev, 0x409900, - nv_rd32(dev, 0x409904) | 0xc0000000); - for (r = 0x409e08; r <= 0x409e24; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, - nv_rd32(dev, r)); - nv_wr32(dev, 0x409e08, - nv_rd32(dev, 0x409e08) | 0xc0000000); - + nv50_pgraph_trap_handler(dev); status &= ~0x00200000; - nv_wr32(dev, NV03_PGRAPH_NSOURCE, nsource); nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000); } + /* Unknown, never seen: 0x00400000 */ + + /* SINGLE_STEP: Happens on every method if you turned on + * single stepping in 40008c */ + if (status & 0x01000000) { + nouveau_graph_trap_info(dev, &trap); + if (nouveau_ratelimit()) + nouveau_graph_dump_trap_info(dev, + "PGRAPH_SINGLE_STEP", &trap); + status &= ~0x01000000; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x01000000); + } + + /* 0x02000000 happens when you pause a ctxprog... + * but the only way this can happen that I know is by + * poking the relevant MMIO register, and we don't + * do that. */ + if (status) { NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", status); @@ -672,7 +1184,8 @@ nv50_pgraph_irq_handler(struct drm_device *dev) } nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); - nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); + if (nv_rd32(dev, 0x400824) & (1 << 31)) + nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); } static void diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 516a8d36cb1..f4ea3e61c09 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -34,7 +34,6 @@ #include "nouveau_drm.h" #include "nv50_display.h" -static int nouveau_stub_init(struct drm_device *dev) { return 0; } static void nouveau_stub_takedown(struct drm_device *dev) {} static int nouveau_init_engine_ptrs(struct drm_device *dev) @@ -276,8 +275,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.init = nv04_timer_init; engine->timer.read = nv04_timer_read; engine->timer.takedown = nv04_timer_takedown; - engine->fb.init = nouveau_stub_init; - engine->fb.takedown = nouveau_stub_takedown; + engine->fb.init = nv50_fb_init; + engine->fb.takedown = nv50_fb_takedown; engine->graph.grclass = nv50_graph_grclass; engine->graph.init = nv50_graph_init; engine->graph.takedown = nv50_graph_takedown; diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c new file mode 100644 index 00000000000..a95e6941ba8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv50_fb.c @@ -0,0 +1,32 @@ +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" +#include "nouveau_drm.h" + +int +nv50_fb_init(struct drm_device *dev) +{ + /* This is needed to get meaningful information from 100c90 + * on traps. No idea what these values mean exactly. */ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + switch (dev_priv->chipset) { + case 0x50: + nv_wr32(dev, 0x100c90, 0x0707ff); + break; + case 0xa5: + case 0xa8: + nv_wr32(dev, 0x100c90, 0x0d0fff); + break; + default: + nv_wr32(dev, 0x100c90, 0x1d07ff); + break; + } + + return 0; +} + +void +nv50_fb_takedown(struct drm_device *dev) +{ +} diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 08d87b749a5..c62b33a02f8 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -56,6 +56,10 @@ nv50_graph_init_intr(struct drm_device *dev) static void nv50_graph_init_regs__nv(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t units = nv_rd32(dev, 0x1540); + int i; + NV_DEBUG(dev, "\n"); nv_wr32(dev, 0x400804, 0xc0000000); @@ -65,6 +69,20 @@ nv50_graph_init_regs__nv(struct drm_device *dev) nv_wr32(dev, 0x405018, 0xc0000000); nv_wr32(dev, 0x402000, 0xc0000000); + for (i = 0; i < 16; i++) { + if (units & 1 << i) { + if (dev_priv->chipset < 0xa0) { + nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000); + nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000); + nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000); + } else { + nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000); + nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000); + nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000); + } + } + } + nv_wr32(dev, 0x400108, 0xffffffff); nv_wr32(dev, 0x400824, 0x00004000); diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c index 9f909abfb5a..546b31949a3 100644 --- a/drivers/gpu/drm/nouveau/nv50_grctx.c +++ b/drivers/gpu/drm/nouveau/nv50_grctx.c @@ -274,7 +274,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) int offset, base; uint32_t units = nv_rd32 (ctx->dev, 0x1540); - /* 0800 */ + /* 0800: DISPATCH */ cp_ctx(ctx, 0x400808, 7); gr_def(ctx, 0x400814, 0x00000030); cp_ctx(ctx, 0x400834, 0x32); @@ -305,7 +305,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) gr_def(ctx, 0x400b20, 0x0001629d); } - /* 0C00 */ + /* 0C00: VFETCH */ cp_ctx(ctx, 0x400c08, 0x2); gr_def(ctx, 0x400c08, 0x0000fe0c); @@ -331,7 +331,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) cp_ctx(ctx, 0x401540, 0x5); gr_def(ctx, 0x401550, 0x00001018); - /* 1800 */ + /* 1800: STREAMOUT */ cp_ctx(ctx, 0x401814, 0x1); gr_def(ctx, 0x401814, 0x000000ff); if (dev_priv->chipset == 0x50) { @@ -646,7 +646,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) if (dev_priv->chipset == 0x50) cp_ctx(ctx, 0x4063e0, 0x1); - /* 6800 */ + /* 6800: M2MF */ if (dev_priv->chipset < 0x90) { cp_ctx(ctx, 0x406814, 0x2b); gr_def(ctx, 0x406818, 0x00000f80); From da647d5bf3c0a4b7ad150803910cb1d737ac522e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 4 Mar 2010 12:00:39 +1000 Subject: [PATCH 006/478] drm/nouveau: add option to allow override of dcb connector table types Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 8 +++++++- drivers/gpu/drm/nouveau/nouveau_drv.c | 4 ++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 71247da17da..75388f73cd2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5287,10 +5287,16 @@ parse_dcb_connector_table(struct nvbios *bios) break; default: cte->type = divine_connector_type(bios, cte->index); - NV_WARN(dev, "unknown type, using 0x%02x", cte->type); + NV_WARN(dev, "unknown type, using 0x%02x\n", cte->type); break; } + if (nouveau_override_conntype) { + int type = divine_connector_type(bios, cte->index); + if (type != cte->type) + NV_WARN(dev, " -> type 0x%02x\n", cte->type); + } + } } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 874adf55a43..f7f28f2f864 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -83,6 +83,10 @@ MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration"); int nouveau_nofbaccel = 0; module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400); +MODULE_PARM_DESC(override_conntype, "Ignore DCB connector type"); +int nouveau_override_conntype = 0; +module_param_named(override_conntype, nouveau_override_conntype, int, 0400); + MODULE_PARM_DESC(tv_norm, "Default TV norm.\n" "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n" "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n" diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index ad2d75d5dd9..6238e25a0c6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -689,6 +689,7 @@ extern int nouveau_ctxfw; extern int nouveau_ignorelid; extern int nouveau_nofbaccel; extern int nouveau_noaccel; +extern int nouveau_override_conntype; /* nouveau_state.c */ extern void nouveau_preclose(struct drm_device *dev, struct drm_file *); From 53c44c3a065ac48c4ccb38f811cf7c5d305c9d4e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 4 Mar 2010 12:12:22 +1000 Subject: [PATCH 007/478] drm/nouveau: Gigabyte NX85T connector table lies, it has DVI-I not HDMI Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 75388f73cd2..e5f0ec23d91 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5210,6 +5210,21 @@ divine_connector_type(struct nvbios *bios, int index) return type; } +static void +apply_dcb_connector_quirks(struct nvbios *bios, int idx) +{ + struct dcb_connector_table_entry *cte = &bios->dcb.connector.entry[idx]; + struct drm_device *dev = bios->dev; + + /* Gigabyte NX85T */ + if ((dev->pdev->device == 0x0421) && + (dev->pdev->subsystem_vendor == 0x1458) && + (dev->pdev->subsystem_device == 0x344c)) { + if (cte->type == DCB_CONNECTOR_HDMI_1) + cte->type = DCB_CONNECTOR_DVI_I; + } +} + static void parse_dcb_connector_table(struct nvbios *bios) { @@ -5266,6 +5281,8 @@ parse_dcb_connector_table(struct nvbios *bios) if (cte->type == 0xff) continue; + apply_dcb_connector_quirks(bios, i); + NV_INFO(dev, " %d: 0x%08x: type 0x%02x idx %d tag 0x%02x\n", i, cte->entry, cte->type, cte->index, cte->gpio_tag); From e5ec882cfc18007c6076236ac33a713bcc1d35aa Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 5 Mar 2010 15:15:39 +0100 Subject: [PATCH 008/478] drm/nv04-nv40: Fix up the programmed horizontal sync pulse delay. The calculated values were a little bit off (~16 clocks), the only effect it could have had is a slightly offset image with respect to the blob on analog outputs (bug 26790). Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_crtc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index d2f143ed97c..9986aba1ef2 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -230,9 +230,9 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode) struct drm_framebuffer *fb = crtc->fb; /* Calculate our timings */ - int horizDisplay = (mode->crtc_hdisplay >> 3) - 1; - int horizStart = (mode->crtc_hsync_start >> 3) - 1; - int horizEnd = (mode->crtc_hsync_end >> 3) - 1; + int horizDisplay = (mode->crtc_hdisplay >> 3) - 1; + int horizStart = (mode->crtc_hsync_start >> 3) + 1; + int horizEnd = (mode->crtc_hsync_end >> 3) + 1; int horizTotal = (mode->crtc_htotal >> 3) - 5; int horizBlankStart = (mode->crtc_hdisplay >> 3) - 1; int horizBlankEnd = (mode->crtc_htotal >> 3) - 1; From 81441570c9cbf453891d90f5725adbbfe5a9cc69 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 21 Feb 2010 13:28:35 +0100 Subject: [PATCH 009/478] drm/nouveau: print a message very early during suspend - In case of suspend lockups it's nice to know it happened in nouveau. Signed-off-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index f7f28f2f864..0f7e2d06930 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -158,9 +158,11 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) if (pm_state.event == PM_EVENT_PRETHAW) return 0; + NV_INFO(dev, "Disabling fbcon acceleration...\n"); fbdev_flags = dev_priv->fbdev_info->flags; dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED; + NV_INFO(dev, "Unpinning framebuffer(s)...\n"); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; From ce48fa93a6f5cadd4141a921dfb4129c8850374e Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 25 Feb 2010 20:00:38 +0100 Subject: [PATCH 010/478] drm/nv50: add a memory barrier to pushbuf submission - This is useful for vram pushbuffers that are write combined. - pre-nv50 has one too (in WRITE_PUT). Signed-off-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_dma.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index c8482a108a7..65c441a1999 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -190,6 +190,11 @@ nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo, nouveau_bo_wr32(pb, ip++, upper_32_bits(offset) | length << 8); chan->dma.ib_put = (chan->dma.ib_put + 1) & chan->dma.ib_max; + + DRM_MEMORYBARRIER(); + /* Flush writes. */ + nouveau_bo_rd32(pb, 0); + nvchan_wr32(chan, 0x8c, chan->dma.ib_put); chan->dma.ib_free--; } From d544d623c5ef3ca14407e8bc042fdf938a966b04 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 10 Mar 2010 15:52:43 +1000 Subject: [PATCH 011/478] drm/nv50: fix connector table parsing for some cards The connector table index in the DCB entry for each output type is an index into the connector table, and does *not* necessarily match up with what was previously called "index" in the connector table entries themselves. Not real sure what that index is exactly, renamed to "index2" as we still use it to prevent creating multiple TV connectors. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 3 ++- drivers/gpu/drm/nouveau/nouveau_bios.h | 3 ++- drivers/gpu/drm/nouveau/nv50_display.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e5f0ec23d91..aed6068a6ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5253,13 +5253,14 @@ parse_dcb_connector_table(struct nvbios *bios) entry = conntab + conntab[1]; cte = &ct->entry[0]; for (i = 0; i < conntab[2]; i++, entry += conntab[3], cte++) { + cte->index = i; if (conntab[3] == 2) cte->entry = ROM16(entry[0]); else cte->entry = ROM32(entry[0]); cte->type = (cte->entry & 0x000000ff) >> 0; - cte->index = (cte->entry & 0x00000f00) >> 8; + cte->index2 = (cte->entry & 0x00000f00) >> 8; switch (cte->entry & 0x00033000) { case 0x00001000: cte->gpio_tag = 0x07; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 9f688aa9a65..4f88e6924d2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -72,9 +72,10 @@ enum dcb_connector_type { }; struct dcb_connector_table_entry { + uint8_t index; uint32_t entry; enum dcb_connector_type type; - uint8_t index; + uint8_t index2; uint8_t gpio_tag; }; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 61a89f2dc55..fac6c88a2b1 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -522,8 +522,8 @@ int nv50_display_create(struct drm_device *dev) } for (i = 0 ; i < dcb->connector.entries; i++) { - if (i != 0 && dcb->connector.entry[i].index == - dcb->connector.entry[i - 1].index) + if (i != 0 && dcb->connector.entry[i].index2 == + dcb->connector.entry[i - 1].index2) continue; nouveau_connector_create(dev, &dcb->connector.entry[i]); } From 5c1f96f4cffbdde9e194f3ae5373953f3fa12836 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Wed, 3 Mar 2010 09:16:54 +0100 Subject: [PATCH 012/478] OMAP: DSS2: VRAM: Fix early_param for vram In commit 2b0d8c251b8876d530a6bf671eb5425838fa698a the __early_param is replaced with the generic early_param. This patch fixes the parameter passing for the vram. Signed-off-by: Thomas Weber [tomi.valkeinen@nokia.com: changed the commit prefix] Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/vram.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c index 55a4de5e5d1..b266ffae0bd 100644 --- a/drivers/video/omap2/vram.c +++ b/drivers/video/omap2/vram.c @@ -511,13 +511,14 @@ static u32 omap_vram_sdram_size __initdata; static u32 omap_vram_def_sdram_size __initdata; static u32 omap_vram_def_sdram_start __initdata; -static void __init omap_vram_early_vram(char **p) +static int __init omap_vram_early_vram(char *p) { - omap_vram_def_sdram_size = memparse(*p, p); - if (**p == ',') - omap_vram_def_sdram_start = simple_strtoul((*p) + 1, p, 16); + omap_vram_def_sdram_size = memparse(p, &p); + if (*p == ',') + omap_vram_def_sdram_start = simple_strtoul(p + 1, &p, 16); + return 0; } -__early_param("vram=", omap_vram_early_vram); +early_param("vram", omap_vram_early_vram); /* * Called from map_io. We need to call to this early enough so that we From 0b1adaa031a55e44f5dd942f234bf09d28e8a0d6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 9 Mar 2010 19:45:54 +0100 Subject: [PATCH 013/478] genirq: Prevent oneshot irq thread race Lars-Peter pointed out that the oneshot threaded interrupt handler code has the following race: CPU0 CPU1 hande_level_irq(irq X) mask_ack_irq(irq X) handle_IRQ_event(irq X) wake_up(thread_handler) thread handler(irq X) runs finalize_oneshot(irq X) does not unmask due to !(desc->status & IRQ_MASKED) return from irq does not unmask due to (desc->status & IRQ_ONESHOT) This leaves the interrupt line masked forever. The reason for this is the inconsistent handling of the IRQ_MASKED flag. Instead of setting it in the mask function the oneshot support sets the flag after waking up the irq thread. The solution for this is to set/clear the IRQ_MASKED status whenever we mask/unmask an interrupt line. That's the easy part, but that cleanup opens another race: CPU0 CPU1 hande_level_irq(irq) mask_ack_irq(irq) handle_IRQ_event(irq) wake_up(thread_handler) thread handler(irq) runs finalize_oneshot_irq(irq) unmask(irq) irq triggers again handle_level_irq(irq) mask_ack_irq(irq) return from irq due to IRQ_INPROGRESS return from irq does not unmask due to (desc->status & IRQ_ONESHOT) This requires that we synchronize finalize_oneshot_irq() with the primary handler. If IRQ_INPROGESS is set we wait until the primary handler on the other CPU has returned before unmasking the interrupt line again. We probably have never seen that problem because it does not happen on UP and on SMP the irqbalancer protects us by pinning the primary handler and the thread to the same CPU. Reported-by: Lars-Peter Clausen Signed-off-by: Thomas Gleixner Cc: stable@kernel.org --- kernel/irq/chip.c | 31 ++++++++++++++++++++++--------- kernel/irq/manage.c | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index d70394f12ee..71eba24a39a 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -359,6 +359,23 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) if (desc->chip->ack) desc->chip->ack(irq); } + desc->status |= IRQ_MASKED; +} + +static inline void mask_irq(struct irq_desc *desc, int irq) +{ + if (desc->chip->mask) { + desc->chip->mask(irq); + desc->status |= IRQ_MASKED; + } +} + +static inline void unmask_irq(struct irq_desc *desc, int irq) +{ + if (desc->chip->unmask) { + desc->chip->unmask(irq); + desc->status &= ~IRQ_MASKED; + } } /* @@ -484,10 +501,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) raw_spin_lock(&desc->lock); desc->status &= ~IRQ_INPROGRESS; - if (unlikely(desc->status & IRQ_ONESHOT)) - desc->status |= IRQ_MASKED; - else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) - desc->chip->unmask(irq); + if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT))) + unmask_irq(desc, irq); out_unlock: raw_spin_unlock(&desc->lock); } @@ -524,8 +539,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) action = desc->action; if (unlikely(!action || (desc->status & IRQ_DISABLED))) { desc->status |= IRQ_PENDING; - if (desc->chip->mask) - desc->chip->mask(irq); + mask_irq(desc, irq); goto out; } @@ -593,7 +607,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) irqreturn_t action_ret; if (unlikely(!action)) { - desc->chip->mask(irq); + mask_irq(desc, irq); goto out_unlock; } @@ -605,8 +619,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) if (unlikely((desc->status & (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_MASKED))) { - desc->chip->unmask(irq); - desc->status &= ~IRQ_MASKED; + unmask_irq(desc, irq); } desc->status &= ~IRQ_PENDING; diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index eb6078ca60c..69a3d7b9414 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -483,8 +483,26 @@ static int irq_wait_for_interrupt(struct irqaction *action) */ static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) { +again: chip_bus_lock(irq, desc); raw_spin_lock_irq(&desc->lock); + + /* + * Implausible though it may be we need to protect us against + * the following scenario: + * + * The thread is faster done than the hard interrupt handler + * on the other CPU. If we unmask the irq line then the + * interrupt can come in again and masks the line, leaves due + * to IRQ_INPROGRESS and the irq line is masked forever. + */ + if (unlikely(desc->status & IRQ_INPROGRESS)) { + raw_spin_unlock_irq(&desc->lock); + chip_bus_sync_unlock(irq, desc); + cpu_relax(); + goto again; + } + if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { desc->status &= ~IRQ_MASKED; desc->chip->unmask(irq); From 80a05b9ffa7dc13f6693902dd8999a2b61a3a0d7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Mar 2010 17:34:14 +0100 Subject: [PATCH 014/478] clockevents: Sanitize min_delta_ns adjustment and prevent overflows The current logic which handles clock events programming failures can increase min_delta_ns unlimited and even can cause overflows. Sanitize it by: - prevent zero increase when min_delta_ns == 1 - limiting min_delta_ns to a jiffie - bail out if the jiffie limit is hit - add retries stats for /proc/timer_list so we can gather data Reported-by: Uwe Kleine-Koenig Signed-off-by: Thomas Gleixner --- include/linux/clockchips.h | 2 ++ kernel/time/tick-oneshot.c | 52 +++++++++++++++++++++++++++++--------- kernel/time/timer_list.c | 3 ++- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 0cf725bdd2a..fc53492b6ad 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -73,6 +73,7 @@ enum clock_event_nofitiers { * @list: list head for the management code * @mode: operating mode assigned by the management code * @next_event: local storage for the next event in oneshot mode + * @retries: number of forced programming retries */ struct clock_event_device { const char *name; @@ -93,6 +94,7 @@ struct clock_event_device { struct list_head list; enum clock_event_mode mode; ktime_t next_event; + unsigned long retries; }; /* diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 0a8a213016f..aada0e52680 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c @@ -22,6 +22,29 @@ #include "tick-internal.h" +/* Limit min_delta to a jiffie */ +#define MIN_DELTA_LIMIT (NSEC_PER_SEC / HZ) + +static int tick_increase_min_delta(struct clock_event_device *dev) +{ + /* Nothing to do if we already reached the limit */ + if (dev->min_delta_ns >= MIN_DELTA_LIMIT) + return -ETIME; + + if (dev->min_delta_ns < 5000) + dev->min_delta_ns = 5000; + else + dev->min_delta_ns += dev->min_delta_ns >> 1; + + if (dev->min_delta_ns > MIN_DELTA_LIMIT) + dev->min_delta_ns = MIN_DELTA_LIMIT; + + printk(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n", + dev->name ? dev->name : "?", + (unsigned long long) dev->min_delta_ns); + return 0; +} + /** * tick_program_event internal worker function */ @@ -37,23 +60,28 @@ int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires, if (!ret || !force) return ret; + dev->retries++; /* - * We tried 2 times to program the device with the given - * min_delta_ns. If that's not working then we double it + * We tried 3 times to program the device with the given + * min_delta_ns. If that's not working then we increase it * and emit a warning. */ if (++i > 2) { /* Increase the min. delta and try again */ - if (!dev->min_delta_ns) - dev->min_delta_ns = 5000; - else - dev->min_delta_ns += dev->min_delta_ns >> 1; - - printk(KERN_WARNING - "CE: %s increasing min_delta_ns to %llu nsec\n", - dev->name ? dev->name : "?", - (unsigned long long) dev->min_delta_ns << 1); - + if (tick_increase_min_delta(dev)) { + /* + * Get out of the loop if min_delta_ns + * hit the limit already. That's + * better than staying here forever. + * + * We clear next_event so we have a + * chance that the box survives. + */ + printk(KERN_WARNING + "CE: Reprogramming failure. Giving up\n"); + dev->next_event.tv64 = KTIME_MAX; + return -ETIME; + } i = 0; } diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c index bdfb8dd1050..1a4a7dd7877 100644 --- a/kernel/time/timer_list.c +++ b/kernel/time/timer_list.c @@ -228,6 +228,7 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu) SEQ_printf(m, " event_handler: "); print_name_offset(m, dev->event_handler); SEQ_printf(m, "\n"); + SEQ_printf(m, " retries: %lu\n", dev->retries); } static void timer_list_show_tickdevices(struct seq_file *m) @@ -257,7 +258,7 @@ static int timer_list_show(struct seq_file *m, void *v) u64 now = ktime_to_ns(ktime_get()); int cpu; - SEQ_printf(m, "Timer List Version: v0.5\n"); + SEQ_printf(m, "Timer List Version: v0.6\n"); SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES); SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now); From 829b6c1ef488856c6a46a2f705f5068062d5f34c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 11 Mar 2010 14:04:30 -0800 Subject: [PATCH 015/478] timer stats: Fix del_timer_sync() and try_to_del_timer_sync() These functions forgot to run timer_stats_timer_clear_start_info(). It's unobvious what effect this has and whether it matters much - we won't be printing it out anyway if the timer's detached. Untested, just an Ingo trollpatch. [ Nevertheless correct - tglx ] Signed-off-by: Andrew Morton Cc: Ingo Molnar Cc: johnstul@us.ibm.com Signed-off-by: Thomas Gleixner --- kernel/timer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/timer.c b/kernel/timer.c index c61a7949387..fc965eae0e8 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -880,6 +880,7 @@ int try_to_del_timer_sync(struct timer_list *timer) if (base->running_timer == timer) goto out; + timer_stats_timer_clear_start_info(timer); ret = 0; if (timer_pending(timer)) { detach_timer(timer, 1); From 15365c108ea27598e265f8c13e7051d99ca5b0b9 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 11 Mar 2010 14:04:31 -0800 Subject: [PATCH 016/478] posix-cpu-timers: Reset expire cache when no timer is running When a process deletes cpu timer or a timer expires we do not clear the expiration cache sig->cputimer_expires. As a result the fastpath_timer_check() which prevents us to loop over all threads in case no timer is active is not working and we run the slow path needlessly on every tick. Zero sig->cputimer_expires in stop_process_timers(). Signed-off-by: Stanislaw Gruszka Cc: Ingo Molnar Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Hidetoshi Seto Cc: Spencer Candland Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner --- kernel/posix-cpu-timers.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 438ff452351..edec25a68e9 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -1060,9 +1060,9 @@ static void check_thread_timers(struct task_struct *tsk, } } -static void stop_process_timers(struct task_struct *tsk) +static void stop_process_timers(struct signal_struct *sig) { - struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; + struct thread_group_cputimer *cputimer = &sig->cputimer; unsigned long flags; if (!cputimer->running) @@ -1071,6 +1071,10 @@ static void stop_process_timers(struct task_struct *tsk) spin_lock_irqsave(&cputimer->lock, flags); cputimer->running = 0; spin_unlock_irqrestore(&cputimer->lock, flags); + + sig->cputime_expires.prof_exp = cputime_zero; + sig->cputime_expires.virt_exp = cputime_zero; + sig->cputime_expires.sched_exp = 0; } static u32 onecputick; @@ -1131,7 +1135,7 @@ static void check_process_timers(struct task_struct *tsk, list_empty(&timers[CPUCLOCK_VIRT]) && cputime_eq(sig->it[CPUCLOCK_VIRT].expires, cputime_zero) && list_empty(&timers[CPUCLOCK_SCHED])) { - stop_process_timers(tsk); + stop_process_timers(sig); return; } From d330a5befb88875a9b3d2db62f9b74dadf660b13 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Sun, 14 Mar 2010 18:17:54 -0400 Subject: [PATCH 017/478] ext4: Fix estimate of # of blocks needed to write indirect-mapped files http://bugzilla.kernel.org/show_bug.cgi?id=15420 Signed-off-by: Jan Kara Signed-off-by: "Theodore Ts'o" --- fs/ext4/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 986120f3006..11119e07233 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1035,7 +1035,7 @@ static int ext4_indirect_calc_metadata_amount(struct inode *inode, sector_t lblock) { struct ext4_inode_info *ei = EXT4_I(inode); - int dind_mask = EXT4_ADDR_PER_BLOCK(inode->i_sb) - 1; + sector_t dind_mask = ~((sector_t)EXT4_ADDR_PER_BLOCK(inode->i_sb) - 1); int blk_bits; if (lblock < EXT4_NDIR_BLOCKS) @@ -1050,7 +1050,7 @@ static int ext4_indirect_calc_metadata_amount(struct inode *inode, } ei->i_da_metadata_calc_last_lblock = lblock & dind_mask; ei->i_da_metadata_calc_len = 1; - blk_bits = roundup_pow_of_two(lblock + 1); + blk_bits = order_base_2(lblock); return (blk_bits / EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb)) + 1; } From 338e2b1d571e4873908b199c90d6a31f65137fe3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 3 Mar 2010 13:39:13 -0500 Subject: [PATCH 018/478] drm/radeon: add new RS880 pci id This should go to 2.6.33 stable as well. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- include/drm/drm_pciids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 676104b7818..04a6ebc27b9 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -410,6 +410,7 @@ {0x1002, 0x9712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9714, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9715, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0, 0, 0} #define r128_PCI_IDS \ From c21b0fe6de3912f53087b4f3991942529f03eef6 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 2 Mar 2010 20:37:52 +0100 Subject: [PATCH 019/478] drm/radeon/kms: catch atombios infinite loop and break out of it In somecase the atombios code might lead to infinite loop because the GPU is in broken state, this patch track the jump history and will abort atombios execution if we are stuck executing the same jump for more than 1sec. Note that otherwise in some case we might enter an infinite loop in the kernel context which is bad. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 59 ++++++++++++++++++++++++++++------- drivers/gpu/drm/radeon/atom.h | 2 +- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index d75788feac6..b7fe660985c 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -52,15 +52,17 @@ typedef struct { struct atom_context *ctx; - uint32_t *ps, *ws; int ps_shift; uint16_t start; + unsigned last_jump; + unsigned long last_jump_jiffies; + bool abort; } atom_exec_context; int atom_debug = 0; -static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params); -void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params); +static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params); +int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params); static uint32_t atom_arg_mask[8] = { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, @@ -604,12 +606,17 @@ static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg) static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) { int idx = U8((*ptr)++); + int r = 0; + if (idx < ATOM_TABLE_NAMES_CNT) SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); else SDEBUG(" table: %d\n", idx); if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) - atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift); + r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift); + if (r) { + ctx->abort = true; + } } static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) @@ -673,6 +680,8 @@ static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg) static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) { int execute = 0, target = U16(*ptr); + unsigned long cjiffies; + (*ptr) += 2; switch (arg) { case ATOM_COND_ABOVE: @@ -700,8 +709,25 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) if (arg != ATOM_COND_ALWAYS) SDEBUG(" taken: %s\n", execute ? "yes" : "no"); SDEBUG(" target: 0x%04X\n", target); - if (execute) + if (execute) { + if (ctx->last_jump == (ctx->start + target)) { + cjiffies = jiffies; + if (time_after(cjiffies, ctx->last_jump_jiffies)) { + cjiffies -= ctx->last_jump_jiffies; + if ((jiffies_to_msecs(cjiffies) > 1000)) { + DRM_ERROR("atombios stuck in loop for more than 1sec aborting\n"); + ctx->abort = true; + } + } else { + /* jiffies wrap around we will just wait a little longer */ + ctx->last_jump_jiffies = jiffies; + } + } else { + ctx->last_jump = ctx->start + target; + ctx->last_jump_jiffies = jiffies; + } *ptr = ctx->start + target; + } } static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) @@ -1104,7 +1130,7 @@ static struct { atom_op_shr, ATOM_ARG_MC}, { atom_op_debug, 0},}; -static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params) +static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params) { int base = CU16(ctx->cmd_table + 4 + 2 * index); int len, ws, ps, ptr; @@ -1112,7 +1138,7 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 atom_exec_context ectx; if (!base) - return; + return -EINVAL; len = CU16(base + ATOM_CT_SIZE_PTR); ws = CU8(base + ATOM_CT_WS_PTR); @@ -1125,6 +1151,8 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 ectx.ps_shift = ps / 4; ectx.start = base; ectx.ps = params; + ectx.abort = false; + ectx.last_jump = 0; if (ws) ectx.ws = kzalloc(4 * ws, GFP_KERNEL); else @@ -1137,6 +1165,11 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); else SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1); + if (ectx.abort) { + DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n", + base, len, ws, ps, ptr - 1); + return -EINVAL; + } if (op < ATOM_OP_CNT && op > 0) opcode_table[op].func(&ectx, &ptr, @@ -1152,10 +1185,13 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 if (ws) kfree(ectx.ws); + return 0; } -void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) +int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) { + int r; + mutex_lock(&ctx->mutex); /* reset reg block */ ctx->reg_block = 0; @@ -1163,8 +1199,9 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) ctx->fb_base = 0; /* reset io mode */ ctx->io_mode = ATOM_IO_MM; - atom_execute_table_locked(ctx, index, params); + r = atom_execute_table_locked(ctx, index, params); mutex_unlock(&ctx->mutex); + return r; } static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; @@ -1248,9 +1285,7 @@ int atom_asic_init(struct atom_context *ctx) if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) return 1; - atom_execute_table(ctx, ATOM_CMD_INIT, ps); - - return 0; + return atom_execute_table(ctx, ATOM_CMD_INIT, ps); } void atom_destroy(struct atom_context *ctx) diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h index bc73781423a..1b262631480 100644 --- a/drivers/gpu/drm/radeon/atom.h +++ b/drivers/gpu/drm/radeon/atom.h @@ -140,7 +140,7 @@ struct atom_context { extern int atom_debug; struct atom_context *atom_parse(struct card_info *, void *); -void atom_execute_table(struct atom_context *, int, uint32_t *); +int atom_execute_table(struct atom_context *, int, uint32_t *); int atom_asic_init(struct atom_context *); void atom_destroy(struct atom_context *); void atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start); From 965cf68e8797932e9cd49238a6dd39423ac9b256 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 6 Mar 2010 13:42:45 +0100 Subject: [PATCH 020/478] drm/nouveau: Never evict VRAM buffers to system. VRAM->system is a synchronous operation: it involves scheduling a VRAM->TT DMA transfer and stalling the CPU until it's finished so that we can unbind the new memory from the translation tables. VRAM->TT can always be performed asynchronously, even if TT is already full and we have to move something out of it. Additionally, allowing VRAM->system behaves badly under heavy memory pressure because once we run out of TT, stuff starts to be moved back and forth between VRAM and system, and the TT contents are hardly renewed. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 028719fddf7..026612471c9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -439,8 +439,7 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) switch (bo->mem.mem_type) { case TTM_PL_VRAM: - nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT | - TTM_PL_FLAG_SYSTEM); + nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT); break; default: nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM); From f4053509669f904aec70c51e2ff75563ba7ae823 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 15 Mar 2010 09:43:51 +1000 Subject: [PATCH 021/478] drm/nouveau: add module option to disable TV detection Intended to be used as a workaround in cases where we falsely detect that a TV is connected when it's not. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 2 +- drivers/gpu/drm/nouveau/nouveau_drv.c | 4 ++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 24327f468c4..14afe1e47e5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -302,7 +302,7 @@ nouveau_connector_detect(struct drm_connector *connector) detect_analog: nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); - if (!nv_encoder) + if (!nv_encoder && !nouveau_tv_disable) nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); if (nv_encoder) { struct drm_encoder *encoder = to_drm_encoder(nv_encoder); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 0f7e2d06930..60a709c7f01 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -87,6 +87,10 @@ MODULE_PARM_DESC(override_conntype, "Ignore DCB connector type"); int nouveau_override_conntype = 0; module_param_named(override_conntype, nouveau_override_conntype, int, 0400); +MODULE_PARM_DESC(tv_disable, "Disable TV-out detection\n"); +int nouveau_tv_disable = 0; +module_param_named(tv_disable, nouveau_tv_disable, int, 0400); + MODULE_PARM_DESC(tv_norm, "Default TV norm.\n" "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n" "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n" diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 6238e25a0c6..3b6bbd00d6b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -682,6 +682,7 @@ extern int nouveau_uscript_tmds; extern int nouveau_vram_pushbuf; extern int nouveau_vram_notify; extern int nouveau_fbpercrtc; +extern int nouveau_tv_disable; extern char *nouveau_tv_norm; extern int nouveau_reg_debug; extern char *nouveau_vbios; From b792210e7d1f9fb102061e2016da96cf2ad5cdbd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 6 Mar 2010 10:57:30 -0500 Subject: [PATCH 022/478] drm/radeon/kms/atom: spread spectrum fix The atom spread spectrum table does not always disable ss. Explicitly disable it and then use the atom table to enable later if needed (currently only used for LVDS). Fixes display issues on some systems. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 57 ++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index dd9fdf56061..0c676696a0d 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -353,12 +353,55 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc, atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +static void atombios_disable_ss(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + u32 ss_cntl; + + if (ASIC_IS_DCE4(rdev)) { + switch (radeon_crtc->pll_id) { + case ATOM_PPLL1: + ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL); + ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; + WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl); + break; + case ATOM_PPLL2: + ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL); + ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; + WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl); + break; + case ATOM_DCPLL: + case ATOM_PPLL_INVALID: + return; + } + } else if (ASIC_IS_AVIVO(rdev)) { + switch (radeon_crtc->pll_id) { + case ATOM_PPLL1: + ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); + ss_cntl &= ~1; + WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl); + break; + case ATOM_PPLL2: + ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); + ss_cntl &= ~1; + WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl); + break; + case ATOM_DCPLL: + case ATOM_PPLL_INVALID: + return; + } + } +} + + union atom_enable_ss { ENABLE_LVDS_SS_PARAMETERS legacy; ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; }; -static void atombios_set_ss(struct drm_crtc *crtc, int enable) +static void atombios_enable_ss(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; @@ -387,9 +430,9 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable) step = dig->ss->step; delay = dig->ss->delay; range = dig->ss->range; - } else if (enable) + } else return; - } else if (enable) + } else return; break; } @@ -406,13 +449,13 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable) args.v1.ucSpreadSpectrumDelay = delay; args.v1.ucSpreadSpectrumRange = range; args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; - args.v1.ucEnable = enable; + args.v1.ucEnable = ATOM_ENABLE; } else { args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage); args.legacy.ucSpreadSpectrumType = type; args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2; args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4; - args.legacy.ucEnable = enable; + args.legacy.ucEnable = ATOM_ENABLE; } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } @@ -1086,12 +1129,12 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, /* pick pll */ radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); - atombios_set_ss(crtc, 0); + atombios_disable_ss(crtc); /* always set DCPLL */ if (ASIC_IS_DCE4(rdev)) atombios_crtc_set_dcpll(crtc); atombios_crtc_set_pll(crtc, adjusted_mode); - atombios_set_ss(crtc, 1); + atombios_enable_ss(crtc); if (ASIC_IS_DCE4(rdev)) atombios_set_crtc_dtd_timing(crtc, adjusted_mode); From 86cb2bbfda2cf402aee46779ee90bbb7d915482b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 8 Mar 2010 12:55:16 -0500 Subject: [PATCH 023/478] drm/radeon/kms: use lcd pll limits when available The bios has alternate pll output limits for LCD panels. If available, use these for pll divider calculations. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 1 + drivers/gpu/drm/radeon/radeon_atombios.c | 14 +++++++++ drivers/gpu/drm/radeon/radeon_combios.c | 2 ++ drivers/gpu/drm/radeon/radeon_display.c | 37 ++++++++++++++++++++---- drivers/gpu/drm/radeon/radeon_mode.h | 3 ++ 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 0c676696a0d..a8cd637d92f 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -525,6 +525,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; pll->algo = dig->pll_algo; + pll->flags |= RADEON_PLL_IS_LCD; } } else { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 93783b15c81..e4540b2b859 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -887,6 +887,20 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) p1pll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); + if (crev >= 4) { + p1pll->lcd_pll_out_min = + le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100; + if (p1pll->lcd_pll_out_min == 0) + p1pll->lcd_pll_out_min = p1pll->pll_out_min; + p1pll->lcd_pll_out_max = + le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100; + if (p1pll->lcd_pll_out_max == 0) + p1pll->lcd_pll_out_max = p1pll->pll_out_max; + } else { + p1pll->lcd_pll_out_min = p1pll->pll_out_min; + p1pll->lcd_pll_out_max = p1pll->pll_out_max; + } + if (p1pll->pll_out_min == 0) { if (ASIC_IS_AVIVO(rdev)) p1pll->pll_out_min = 64800; diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 69af81d9f5a..30a84ae5681 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -633,6 +633,8 @@ bool radeon_combios_get_clock_info(struct drm_device *dev) p1pll->reference_div = RBIOS16(pll_info + 0x10); p1pll->pll_out_min = RBIOS32(pll_info + 0x12); p1pll->pll_out_max = RBIOS32(pll_info + 0x16); + p1pll->lcd_pll_out_min = p1pll->pll_out_min; + p1pll->lcd_pll_out_max = p1pll->pll_out_max; if (rev > 9) { p1pll->pll_in_min = RBIOS32(pll_info + 0x36); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index ba8d806dcf3..ff5f09953c0 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -469,10 +469,19 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll, uint32_t best_error = 0xffffffff; uint32_t best_vco_diff = 1; uint32_t post_div; + u32 pll_out_min, pll_out_max; DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div); freq = freq * 1000; + if (pll->flags & RADEON_PLL_IS_LCD) { + pll_out_min = pll->lcd_pll_out_min; + pll_out_max = pll->lcd_pll_out_max; + } else { + pll_out_min = pll->pll_out_min; + pll_out_max = pll->pll_out_max; + } + if (pll->flags & RADEON_PLL_USE_REF_DIV) min_ref_div = max_ref_div = pll->reference_div; else { @@ -536,10 +545,10 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll, tmp = (uint64_t)pll->reference_freq * feedback_div; vco = radeon_div(tmp, ref_div); - if (vco < pll->pll_out_min) { + if (vco < pll_out_min) { min_feed_div = feedback_div + 1; continue; - } else if (vco > pll->pll_out_max) { + } else if (vco > pll_out_max) { max_feed_div = feedback_div; continue; } @@ -675,6 +684,15 @@ calc_fb_ref_div(struct radeon_pll *pll, { fixed20_12 ffreq, max_error, error, pll_out, a; u32 vco; + u32 pll_out_min, pll_out_max; + + if (pll->flags & RADEON_PLL_IS_LCD) { + pll_out_min = pll->lcd_pll_out_min; + pll_out_max = pll->lcd_pll_out_max; + } else { + pll_out_min = pll->pll_out_min; + pll_out_max = pll->pll_out_max; + } ffreq.full = rfixed_const(freq); /* max_error = ffreq * 0.0025; */ @@ -686,7 +704,7 @@ calc_fb_ref_div(struct radeon_pll *pll, vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac)); vco = vco / ((*ref_div) * 10); - if ((vco < pll->pll_out_min) || (vco > pll->pll_out_max)) + if ((vco < pll_out_min) || (vco > pll_out_max)) continue; /* pll_out = vco / post_div; */ @@ -714,6 +732,15 @@ static void radeon_compute_pll_new(struct radeon_pll *pll, { u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0; u32 best_freq = 0, vco_frequency; + u32 pll_out_min, pll_out_max; + + if (pll->flags & RADEON_PLL_IS_LCD) { + pll_out_min = pll->lcd_pll_out_min; + pll_out_max = pll->lcd_pll_out_max; + } else { + pll_out_min = pll->pll_out_min; + pll_out_max = pll->pll_out_max; + } /* freq = freq / 10; */ do_div(freq, 10); @@ -724,7 +751,7 @@ static void radeon_compute_pll_new(struct radeon_pll *pll, goto done; vco_frequency = freq * post_div; - if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max)) + if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max)) goto done; if (pll->flags & RADEON_PLL_USE_REF_DIV) { @@ -749,7 +776,7 @@ static void radeon_compute_pll_new(struct radeon_pll *pll, continue; vco_frequency = freq * post_div; - if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max)) + if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max)) continue; if (pll->flags & RADEON_PLL_USE_REF_DIV) { ref_div = pll->reference_div; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 1702b820aa4..b868ffad8be 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -129,6 +129,7 @@ struct radeon_tmds_pll { #define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10) #define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11) #define RADEON_PLL_USE_POST_DIV (1 << 12) +#define RADEON_PLL_IS_LCD (1 << 13) /* pll algo */ enum radeon_pll_algo { @@ -149,6 +150,8 @@ struct radeon_pll { uint32_t pll_in_max; uint32_t pll_out_min; uint32_t pll_out_max; + uint32_t lcd_pll_out_min; + uint32_t lcd_pll_out_max; uint32_t best_vco; /* divider limits */ From 267364ac17f6474c69b03034340f769b22f46105 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 8 Mar 2010 17:10:41 -0500 Subject: [PATCH 024/478] drm/radeon/kms: further spread spectrum fixes Adjust modeset ordering to fix spread spectrum. The spread spectrum command table relies on the crtc routing to already be set in order to work properly on some asics. Should fix fdo bug 25741. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 8 +++++--- drivers/gpu/drm/radeon/radeon_encoders.c | 25 ++++++++++++++---------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index a8cd637d92f..7c30e2e74c8 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1127,9 +1127,6 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, /* TODO color tiling */ - /* pick pll */ - radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); - atombios_disable_ss(crtc); /* always set DCPLL */ if (ASIC_IS_DCE4(rdev)) @@ -1164,6 +1161,11 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, static void atombios_crtc_prepare(struct drm_crtc *crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + /* pick pll */ + radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); + atombios_lock_crtc(crtc, ATOM_ENABLE); atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); } diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index bc926ea0a53..4eae30cc521 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1216,6 +1216,9 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + /* update scratch regs with new routing */ + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); } static void @@ -1326,19 +1329,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - if (radeon_encoder->active_device & - (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - if (dig) - dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); - } radeon_encoder->pixel_clock = adjusted_mode->clock; - radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); - atombios_set_encoder_crtc_source(encoder); - if (ASIC_IS_AVIVO(rdev)) { if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) atombios_yuv_setup(encoder, true); @@ -1492,8 +1485,20 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->active_device & + (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + if (dig) + dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); + } + radeon_atom_output_lock(encoder, true); radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + + /* this is needed for the pll/ss setup to work correctly in some cases */ + atombios_set_encoder_crtc_source(encoder); } static void radeon_atom_encoder_commit(struct drm_encoder *encoder) From 15f7207761cfcf8f53fb6e5cacffe060478782c3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 10 Mar 2010 18:33:03 -0500 Subject: [PATCH 025/478] drm/radeon/kms: fix pal tv-out support on legacy IGP chips Based on ddx patch by Andrzej Hajda. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_legacy_tv.c | 29 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_tv.c b/drivers/gpu/drm/radeon/radeon_legacy_tv.c index 417684daef4..f2ed27c8055 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_tv.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_tv.c @@ -57,6 +57,10 @@ #define NTSC_TV_PLL_N_14 693 #define NTSC_TV_PLL_P_14 7 +#define PAL_TV_PLL_M_14 19 +#define PAL_TV_PLL_N_14 353 +#define PAL_TV_PLL_P_14 5 + #define VERT_LEAD_IN_LINES 2 #define FRAC_BITS 0xe #define FRAC_MASK 0x3fff @@ -205,9 +209,24 @@ static const struct radeon_tv_mode_constants available_tv_modes[] = { 630627, /* defRestart */ 347, /* crtcPLL_N */ 14, /* crtcPLL_M */ - 8, /* crtcPLL_postDiv */ + 8, /* crtcPLL_postDiv */ 1022, /* pixToTV */ }, + { /* PAL timing for 14 Mhz ref clk */ + 800, /* horResolution */ + 600, /* verResolution */ + TV_STD_PAL, /* standard */ + 1131, /* horTotal */ + 742, /* verTotal */ + 813, /* horStart */ + 840, /* horSyncStart */ + 633, /* verSyncStart */ + 708369, /* defRestart */ + 211, /* crtcPLL_N */ + 9, /* crtcPLL_M */ + 8, /* crtcPLL_postDiv */ + 759, /* pixToTV */ + }, }; #define N_AVAILABLE_MODES ARRAY_SIZE(available_tv_modes) @@ -242,7 +261,7 @@ static const struct radeon_tv_mode_constants *radeon_legacy_tv_get_std_mode(stru if (pll->reference_freq == 2700) const_ptr = &available_tv_modes[1]; else - const_ptr = &available_tv_modes[1]; /* FIX ME */ + const_ptr = &available_tv_modes[3]; } return const_ptr; } @@ -685,9 +704,9 @@ void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, n = PAL_TV_PLL_N_27; p = PAL_TV_PLL_P_27; } else { - m = PAL_TV_PLL_M_27; - n = PAL_TV_PLL_N_27; - p = PAL_TV_PLL_P_27; + m = PAL_TV_PLL_M_14; + n = PAL_TV_PLL_N_14; + p = PAL_TV_PLL_P_14; } } From ae08819c2a4729444676f1bb55e5e28263f6f5a1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 11 Mar 2010 13:28:14 -0500 Subject: [PATCH 026/478] drm/radeon/kms: fix for hw i2c use the i2c pads to drive SDA Possible fix for fdo bug 26430 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_i2c.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 4ae50c19589..5d93418f9fc 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -291,6 +291,7 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap, prescale = radeon_get_i2c_prescale(rdev); reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) | + RADEON_I2C_DRIVE_EN | RADEON_I2C_START | RADEON_I2C_STOP | RADEON_I2C_GO); From 96a4c8d50de20da865296a380b996f73204d6b34 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 12 Mar 2010 12:55:34 -0500 Subject: [PATCH 027/478] drm/radeon/kms: fix i2c prescale calc on older radeons Should fix fdo bug 26430 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_i2c.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 5d93418f9fc..f007fcb1191 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -183,11 +183,10 @@ static void set_data(void *i2c_priv, int data) static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) { - struct radeon_pll *spll = &rdev->clock.spll; u32 sclk = radeon_get_engine_clock(rdev); u32 prescale = 0; - u32 n, m; - u8 loop; + u32 nm; + u8 n, m, loop; int i2c_clock; switch (rdev->family) { @@ -203,13 +202,15 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) case CHIP_R300: case CHIP_R350: case CHIP_RV350: - n = (spll->reference_freq) / (4 * 6); + i2c_clock = 60; + nm = (sclk * 10) / (i2c_clock * 4); for (loop = 1; loop < 255; loop++) { - if ((loop * (loop - 1)) > n) + if ((nm / loop) < loop) break; } - m = loop - 1; - prescale = m | (loop << 8); + n = loop - 1; + m = loop - 2; + prescale = m | (n << 8); break; case CHIP_RV380: case CHIP_RS400: @@ -217,7 +218,6 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) case CHIP_R420: case CHIP_R423: case CHIP_RV410: - sclk = radeon_get_engine_clock(rdev); prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128; break; case CHIP_RS600: @@ -232,7 +232,6 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) case CHIP_RV570: case CHIP_R580: i2c_clock = 50; - sclk = radeon_get_engine_clock(rdev); if (rdev->family == CHIP_R520) prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock)); else From b28ea41164dc36110dafcdc63783e9b7fb865784 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 12 Mar 2010 13:30:49 -0500 Subject: [PATCH 028/478] drm/radeon/kms/r1xx: enable hw i2c fixing the i2c prescale in the last patch gets it working on r1xx. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 30a84ae5681..6d87e70a505 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -531,10 +531,7 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde case CHIP_RS300: switch (ddc_line) { case RADEON_GPIO_DVI_DDC: - /* in theory this should be hw capable, - * but it doesn't seem to work - */ - i2c.hw_capable = false; + i2c.hw_capable = true; break; default: i2c.hw_capable = false; From d805f50aa1d9eef63fec356b2be557e2da3cd643 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 11 Mar 2010 10:38:07 -0500 Subject: [PATCH 029/478] drm/radeon/kms/rs4xx: make sure crtcs are enabled when setting timing based on ddx patch from Matthias Hopf. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index df23d6a01d0..88865e38fe3 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -603,6 +603,10 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod ? RADEON_CRTC2_INTERLACE_EN : 0)); + /* rs4xx chips seem to like to have the crtc enabled when the timing is set */ + if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480)) + crtc2_gen_cntl |= RADEON_CRTC2_EN; + disp2_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; @@ -630,6 +634,10 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod ? RADEON_CRTC_INTERLACE_EN : 0)); + /* rs4xx chips seem to like to have the crtc enabled when the timing is set */ + if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480)) + crtc_gen_cntl |= RADEON_CRTC_EN; + crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); crtc_ext_cntl |= (RADEON_XCRT_CNT_EN | RADEON_CRTC_VSYNC_DIS | From 808032ee296ee7b37a6df090be40a330e09ae30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 6 Mar 2010 13:03:33 +0000 Subject: [PATCH 030/478] drm/radeon/kms: clean HDMI definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already know same offsets are used for different encoders/transmitters, so just numeric them instead naming incorrectly. Additionaly we found additional registers needed for RV770+ Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_hdmi.c | 10 +++++----- drivers/gpu/drm/radeon/r600_reg.h | 10 +++++++--- drivers/gpu/drm/radeon/radeon_mode.h | 1 + 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index fcc949df0e5..4d09973ad6a 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -470,27 +470,27 @@ void r600_hdmi_init(struct drm_encoder *encoder) case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - radeon_encoder->hdmi_offset = R600_HDMI_TMDS1; + radeon_encoder->hdmi_offset = R600_HDMI_BLOCK1; break; case ENCODER_OBJECT_ID_INTERNAL_LVTM1: switch (r600_audio_tmds_index(encoder)) { case 0: - radeon_encoder->hdmi_offset = R600_HDMI_TMDS1; + radeon_encoder->hdmi_offset = R600_HDMI_BLOCK1; break; case 1: - radeon_encoder->hdmi_offset = R600_HDMI_TMDS2; + radeon_encoder->hdmi_offset = R600_HDMI_BLOCK2; break; default: radeon_encoder->hdmi_offset = 0; break; } case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - radeon_encoder->hdmi_offset = R600_HDMI_TMDS2; + radeon_encoder->hdmi_offset = R600_HDMI_BLOCK2; break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - radeon_encoder->hdmi_offset = R600_HDMI_DIG; + radeon_encoder->hdmi_offset = R600_HDMI_BLOCK3; break; default: diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h index d0e28ffdeda..7b1d22370f6 100644 --- a/drivers/gpu/drm/radeon/r600_reg.h +++ b/drivers/gpu/drm/radeon/r600_reg.h @@ -152,9 +152,9 @@ #define R600_AUDIO_STATUS_BITS 0x73d8 /* HDMI base register addresses */ -#define R600_HDMI_TMDS1 0x7400 -#define R600_HDMI_TMDS2 0x7700 -#define R600_HDMI_DIG 0x7800 +#define R600_HDMI_BLOCK1 0x7400 +#define R600_HDMI_BLOCK2 0x7700 +#define R600_HDMI_BLOCK3 0x7800 /* HDMI registers */ #define R600_HDMI_ENABLE 0x00 @@ -185,4 +185,8 @@ #define R600_HDMI_AUDIO_DEBUG_2 0xe8 #define R600_HDMI_AUDIO_DEBUG_3 0xec +/* HDMI additional config base register addresses */ +#define R600_HDMI_CONFIG1 0x7600 +#define R600_HDMI_CONFIG2 0x7a00 + #endif diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index b868ffad8be..55a41757eed 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -345,6 +345,7 @@ struct radeon_encoder { struct drm_display_mode native_mode; void *enc_priv; int hdmi_offset; + int hdmi_config_offset; int hdmi_audio_workaround; int hdmi_buffer_status; }; From 2cd6218cb8043ef4360b561e726cd081f8a380cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 8 Mar 2010 22:14:01 +0000 Subject: [PATCH 031/478] drm/radeon/kms: clean assigning HDMI blocks to encoders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We almost always used first HDMI block for first encoder and second for sencod. Exception was KLDSCP_LVTMA. Analyzing code picking DIG encoder shows the same behaviour. It shows HDMI block are related to DIGs, which relation we now use. Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_audio.c | 7 +- drivers/gpu/drm/radeon/r600_hdmi.c | 118 ++++++++++------------- drivers/gpu/drm/radeon/radeon.h | 3 +- drivers/gpu/drm/radeon/radeon_encoders.c | 10 +- 4 files changed, 64 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index db928016d03..baf222faf15 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -224,6 +224,7 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; int base_rate = 48000; switch (radeon_encoder->encoder_id) { @@ -245,7 +246,7 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) return; } - switch (r600_audio_tmds_index(encoder)) { + switch (dig->dig_encoder) { case 0: WREG32(R600_AUDIO_PLL1_MUL, base_rate*50); WREG32(R600_AUDIO_PLL1_DIV, clock*100); @@ -257,6 +258,10 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) WREG32(R600_AUDIO_PLL2_DIV, clock*100); WREG32(R600_AUDIO_CLK_SRCSEL, 1); break; + default: + dev_err(rdev->dev, "Unsupported DIG on encoder 0x%02X\n", + radeon_encoder->encoder_id); + return; } } diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 4d09973ad6a..5275a81b1df 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -417,90 +417,74 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000); } -/* - * enable/disable the HDMI engine - */ -void r600_hdmi_enable(struct drm_encoder *encoder, int enable) +static void r600_hdmi_assign_block(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - if (!offset) + if (!dig) { + dev_err(rdev->dev, "Enabling HDMI on non-dig encoder\n"); return; + } - DRM_DEBUG("%s HDMI interface @ 0x%04X\n", enable ? "Enabling" : "Disabling", offset); - - /* some version of atombios ignore the enable HDMI flag - * so enabling/disabling HDMI was moved here for TMDS1+2 */ - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - WREG32_P(AVIVO_TMDSA_CNTL, enable ? 0x4 : 0x0, ~0x4); - WREG32(offset+R600_HDMI_ENABLE, enable ? 0x101 : 0x0); - break; - - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - WREG32_P(AVIVO_LVTMA_CNTL, enable ? 0x4 : 0x0, ~0x4); - WREG32(offset+R600_HDMI_ENABLE, enable ? 0x105 : 0x0); - break; - - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - /* This part is doubtfull in my opinion */ - WREG32(offset+R600_HDMI_ENABLE, enable ? 0x110 : 0x0); - break; - - default: - DRM_ERROR("unknown HDMI output type\n"); - break; + if (ASIC_IS_DCE4(rdev)) { + /* TODO */ + } else if (ASIC_IS_DCE3(rdev)) { + radeon_encoder->hdmi_offset = dig->dig_encoder ? + R600_HDMI_BLOCK3 : R600_HDMI_BLOCK1; + if (ASIC_IS_DCE32(rdev)) + radeon_encoder->hdmi_config_offset = dig->dig_encoder ? + R600_HDMI_CONFIG2 : R600_HDMI_CONFIG1; } } /* - * determin at which register offset the HDMI encoder is + * enable the HDMI engine */ -void r600_hdmi_init(struct drm_encoder *encoder) +void r600_hdmi_enable(struct drm_encoder *encoder) { + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - radeon_encoder->hdmi_offset = R600_HDMI_BLOCK1; - break; - - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - switch (r600_audio_tmds_index(encoder)) { - case 0: - radeon_encoder->hdmi_offset = R600_HDMI_BLOCK1; - break; - case 1: - radeon_encoder->hdmi_offset = R600_HDMI_BLOCK2; - break; - default: - radeon_encoder->hdmi_offset = 0; - break; + if (!radeon_encoder->hdmi_offset) { + r600_hdmi_assign_block(encoder); + if (!radeon_encoder->hdmi_offset) { + dev_warn(rdev->dev, "Could not find HDMI block for " + "0x%x encoder\n", radeon_encoder->encoder_id); + return; } - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - radeon_encoder->hdmi_offset = R600_HDMI_BLOCK2; - break; - - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - radeon_encoder->hdmi_offset = R600_HDMI_BLOCK3; - break; - - default: - radeon_encoder->hdmi_offset = 0; - break; } - DRM_DEBUG("using HDMI engine at offset 0x%04X for encoder 0x%x\n", - radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); + if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) + WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1); - /* TODO: make this configureable */ - radeon_encoder->hdmi_audio_workaround = 0; + DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", + radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); +} + +/* + * disable the HDMI engine + */ +void r600_hdmi_disable(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (!radeon_encoder->hdmi_offset) { + dev_err(rdev->dev, "Disabling not enabled HDMI\n"); + return; + } + + DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", + radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); + + if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) + WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1); + + radeon_encoder->hdmi_offset = 0; + radeon_encoder->hdmi_config_offset = 0; } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 829e26e8a4b..ba93e5a20b2 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1322,7 +1322,8 @@ extern int r600_audio_tmds_index(struct drm_encoder *encoder); extern void r600_audio_set_clock(struct drm_encoder *encoder, int clock); extern void r600_audio_fini(struct radeon_device *rdev); extern void r600_hdmi_init(struct drm_encoder *encoder); -extern void r600_hdmi_enable(struct drm_encoder *encoder, int enable); +extern void r600_hdmi_enable(struct drm_encoder *encoder); +extern void r600_hdmi_disable(struct drm_encoder *encoder); extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); extern int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder); extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 4eae30cc521..a236c75496c 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -593,7 +593,6 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - r600_hdmi_enable(encoder, hdmi_detected); } int @@ -1389,9 +1388,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } atombios_apply_encoder_quirks(encoder, adjusted_mode); - /* XXX */ - if (!ASIC_IS_DCE4(rdev)) + if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { + r600_hdmi_enable(encoder); r600_hdmi_setmode(encoder, adjusted_mode); + } } static bool @@ -1514,6 +1514,8 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); if (radeon_encoder_is_digital(encoder)) { + if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) + r600_hdmi_disable(encoder); dig = radeon_encoder->enc_priv; dig->dig_encoder = -1; } @@ -1664,6 +1666,4 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); break; } - - r600_hdmi_init(encoder); } From 5715f67cecee3617c7a6ff84ee44da46d525559e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 6 Mar 2010 13:03:35 +0000 Subject: [PATCH 032/478] drm/radeon/kms: add HDMI code for pre-DCE3 R6xx GPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Older GPUs are little different, HDMI blocks are not hard-wired, but routable. We should just find some free HDMI block and route it to choosen encoder. In case of RS6x0 there is only one HDMI block, we don't enable HDMI on RS6x00 yet however. Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_hdmi.c | 71 +++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 5275a81b1df..8fbfc73170f 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -417,6 +417,39 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000); } +static int r600_hdmi_find_free_block(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + bool free_blocks[3] = { true, true, true }; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + radeon_encoder = to_radeon_encoder(encoder); + switch (radeon_encoder->hdmi_offset) { + case R600_HDMI_BLOCK1: + free_blocks[0] = false; + break; + case R600_HDMI_BLOCK2: + free_blocks[1] = false; + break; + case R600_HDMI_BLOCK3: + free_blocks[2] = false; + break; + } + } + + if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690) { + return free_blocks[0] ? R600_HDMI_BLOCK1 : 0; + } else if (rdev->family >= CHIP_R600) { + if (free_blocks[0]) + return R600_HDMI_BLOCK1; + else if (free_blocks[1]) + return R600_HDMI_BLOCK2; + } + return 0; +} + static void r600_hdmi_assign_block(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; @@ -437,6 +470,8 @@ static void r600_hdmi_assign_block(struct drm_encoder *encoder) if (ASIC_IS_DCE32(rdev)) radeon_encoder->hdmi_config_offset = dig->dig_encoder ? R600_HDMI_CONFIG2 : R600_HDMI_CONFIG1; + } else if (rdev->family >= CHIP_R600) { + radeon_encoder->hdmi_offset = r600_hdmi_find_free_block(dev); } } @@ -458,8 +493,24 @@ void r600_hdmi_enable(struct drm_encoder *encoder) } } - if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) + if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) { WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1); + } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { + int offset = radeon_encoder->hdmi_offset; + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + WREG32_P(AVIVO_TMDSA_CNTL, 0x4, ~0x4); + WREG32(offset + R600_HDMI_ENABLE, 0x101); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + WREG32_P(AVIVO_LVTMA_CNTL, 0x4, ~0x4); + WREG32(offset + R600_HDMI_ENABLE, 0x105); + break; + default: + dev_err(rdev->dev, "Unknown HDMI output type\n"); + break; + } + } DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); @@ -482,8 +533,24 @@ void r600_hdmi_disable(struct drm_encoder *encoder) DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); - if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) + if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) { WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1); + } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { + int offset = radeon_encoder->hdmi_offset; + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + WREG32_P(AVIVO_TMDSA_CNTL, 0, ~0x4); + WREG32(offset + R600_HDMI_ENABLE, 0); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + WREG32_P(AVIVO_LVTMA_CNTL, 0, ~0x4); + WREG32(offset + R600_HDMI_ENABLE, 0); + break; + default: + dev_err(rdev->dev, "Unknown HDMI output type\n"); + break; + } + } radeon_encoder->hdmi_offset = 0; radeon_encoder->hdmi_config_offset = 0; From 8a8c6e7cfb63cc5e04d5c247ab8d6253200fd425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 6 Mar 2010 13:03:36 +0000 Subject: [PATCH 033/478] drm/radeon/kms: enable audio engine on DCE32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/rv770.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 37887dee12a..8f0c9253c5b 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1013,6 +1013,13 @@ int rv770_resume(struct radeon_device *rdev) DRM_ERROR("radeon: failled testing IB (%d).\n", r); return r; } + + r = r600_audio_init(rdev); + if (r) { + dev_err(rdev->dev, "radeon: audio init failed\n"); + return r; + } + return r; } @@ -1021,6 +1028,7 @@ int rv770_suspend(struct radeon_device *rdev) { int r; + r600_audio_fini(rdev); /* FIXME: we should wait for ring to be empty */ r700_cp_stop(rdev); rdev->cp.ready = false; @@ -1144,6 +1152,13 @@ int rv770_init(struct radeon_device *rdev) } } } + + r = r600_audio_init(rdev); + if (r) { + dev_err(rdev->dev, "radeon: audio init failed\n"); + return r; + } + return 0; } From 0a7d934e6022a12e3f428b2adcb4b531e86170dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 6 Mar 2010 13:03:37 +0000 Subject: [PATCH 034/478] drm/radeon/kms: remove dead audio/HDMI code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_audio.c | 35 ----------------------------- 1 file changed, 35 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index baf222faf15..dddb9e5e0c6 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -181,41 +181,6 @@ int r600_audio_init(struct radeon_device *rdev) return 0; } -/* - * determin how the encoders and audio interface is wired together - */ -int r600_audio_tmds_index(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *other; - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - return 0; - - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - /* special case check if an TMDS1 is present */ - list_for_each_entry(other, &dev->mode_config.encoder_list, head) { - if (to_radeon_encoder(other)->encoder_id == - ENCODER_OBJECT_ID_INTERNAL_TMDS1) - return 1; - } - return 0; - - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - return 1; - - default: - DRM_ERROR("Unsupported encoder type 0x%02X\n", - radeon_encoder->encoder_id); - return -1; - } -} - /* * atach the audio codec to the clock source of the encoder */ From 3fe373d98cdb35c494517b0954b76f8094f4c59d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 6 Mar 2010 13:03:38 +0000 Subject: [PATCH 035/478] drm/radeon/kms: improve coding style a little MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We still have many magic numbers in HDMI/audio to define Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_audio.c | 10 ++++------ drivers/gpu/drm/radeon/r600_hdmi.c | 18 +++++++++--------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index dddb9e5e0c6..dac7042b797 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -197,14 +197,12 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) case ENCODER_OBJECT_ID_INTERNAL_LVTM1: WREG32_P(R600_AUDIO_TIMING, 0, ~0x301); break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301); break; - default: DRM_ERROR("Unsupported encoder type 0x%02X\n", radeon_encoder->encoder_id); @@ -213,14 +211,14 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) switch (dig->dig_encoder) { case 0: - WREG32(R600_AUDIO_PLL1_MUL, base_rate*50); - WREG32(R600_AUDIO_PLL1_DIV, clock*100); + WREG32(R600_AUDIO_PLL1_MUL, base_rate * 50); + WREG32(R600_AUDIO_PLL1_DIV, clock * 100); WREG32(R600_AUDIO_CLK_SRCSEL, 0); break; case 1: - WREG32(R600_AUDIO_PLL2_MUL, base_rate*50); - WREG32(R600_AUDIO_PLL2_DIV, clock*100); + WREG32(R600_AUDIO_PLL2_MUL, base_rate * 50); + WREG32(R600_AUDIO_PLL2_DIV, clock * 100); WREG32(R600_AUDIO_CLK_SRCSEL, 1); break; default: diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 8fbfc73170f..029fa1406d1 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -42,13 +42,13 @@ enum r600_hdmi_color_format { */ enum r600_hdmi_iec_status_bits { AUDIO_STATUS_DIG_ENABLE = 0x01, - AUDIO_STATUS_V = 0x02, - AUDIO_STATUS_VCFG = 0x04, + AUDIO_STATUS_V = 0x02, + AUDIO_STATUS_VCFG = 0x04, AUDIO_STATUS_EMPHASIS = 0x08, AUDIO_STATUS_COPYRIGHT = 0x10, AUDIO_STATUS_NONAUDIO = 0x20, AUDIO_STATUS_PROFESSIONAL = 0x40, - AUDIO_STATUS_LEVEL = 0x80 + AUDIO_STATUS_LEVEL = 0x80 }; struct { @@ -85,7 +85,7 @@ struct { static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq) { if (*CTS == 0) - *CTS = clock*N/(128*freq)*1000; + *CTS = clock * N / (128 * freq) * 1000; DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n", N, *CTS, freq); } @@ -131,11 +131,11 @@ static void r600_hdmi_infoframe_checksum(uint8_t packetType, uint8_t length, uint8_t *frame) { - int i; - frame[0] = packetType + versionNumber + length; - for (i = 1; i <= length; i++) - frame[0] += frame[i]; - frame[0] = 0x100 - frame[0]; + int i; + frame[0] = packetType + versionNumber + length; + for (i = 1; i <= length; i++) + frame[0] += frame[i]; + frame[0] = 0x100 - frame[0]; } /* From 65388342d66a63a29c76058e94a00d7bc0c6423b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 5 Mar 2010 19:22:24 -0500 Subject: [PATCH 036/478] drm/radeon/r600: add missing license and comments to r600_blit_shaders.c R6xx+ cards need to use the 3D engine to blit data which requires quite a bit of hw state setup. Rather than pull the whole 3D driver (which normally generates the 3D state) into the DRM, we opt to use statically generated state tables. The regsiter state and shaders were hand generated to support blitting functionality. See the 3D driver or documentation for descriptions of the registers and shader instructions. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_blit_shaders.c | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.c b/drivers/gpu/drm/radeon/r600_blit_shaders.c index a112c59f9d8..0271b53fa2d 100644 --- a/drivers/gpu/drm/radeon/r600_blit_shaders.c +++ b/drivers/gpu/drm/radeon/r600_blit_shaders.c @@ -1,7 +1,42 @@ +/* + * Copyright 2009 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Alex Deucher + */ #include #include +/* + * R6xx+ cards need to use the 3D engine to blit data which requires + * quite a bit of hw state setup. Rather than pull the whole 3D driver + * (which normally generates the 3D state) into the DRM, we opt to use + * statically generated state tables. The regsiter state and shaders + * were hand generated to support blitting functionality. See the 3D + * driver or documentation for descriptions of the registers and + * shader instructions. + */ + const u32 r6xx_default_state[] = { 0xc0002400, From 839461d3b0e3082eb382f17a3e3899372f28649a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 2 Mar 2010 22:06:51 +0100 Subject: [PATCH 037/478] drm/radeon/kms: switch to condition waiting for reclocking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We tried to implement interruptible waiting with timeout (it was broken anyway) which was not a good idea as explained by Andrew. It's possible to avoid using additional variable but actually it inroduces using more complex in-kernel tools. So simply add one variable for condition. Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 2 ++ drivers/gpu/drm/radeon/r600.c | 2 ++ drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 8 +++++--- drivers/gpu/drm/radeon/rs600.c | 2 ++ 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 91eb762eb3f..73f9a79ed64 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -312,10 +312,12 @@ int r100_irq_process(struct radeon_device *rdev) /* Vertical blank interrupts */ if (status & RADEON_CRTC_VBLANK_STAT) { drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } if (status & RADEON_CRTC2_VBLANK_STAT) { drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } if (status & RADEON_FP_DETECT_STAT) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c5229019729..5b56a1b3902 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2765,6 +2765,7 @@ restart_ih: case 0: /* D1 vblank */ if (disp_int & LB_D1_VBLANK_INTERRUPT) { drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); disp_int &= ~LB_D1_VBLANK_INTERRUPT; DRM_DEBUG("IH: D1 vblank\n"); @@ -2786,6 +2787,7 @@ restart_ih: case 0: /* D2 vblank */ if (disp_int & LB_D2_VBLANK_INTERRUPT) { drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); disp_int &= ~LB_D2_VBLANK_INTERRUPT; DRM_DEBUG("IH: D2 vblank\n"); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index ba93e5a20b2..b54d4f36c4d 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -687,6 +687,7 @@ struct radeon_pm { bool downclocked; int active_crtcs; int req_vblank; + bool vblank_sync; fixed20_12 max_bandwidth; fixed20_12 igp_sideport_mclk; fixed20_12 igp_system_mclk; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index d4d1c39a0e9..d800b86af4d 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -353,10 +353,12 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) rdev->pm.req_vblank |= (1 << 1); drm_vblank_get(rdev->ddev, 1); } - if (rdev->pm.active_crtcs) - wait_event_interruptible_timeout( - rdev->irq.vblank_queue, 0, + if (rdev->pm.active_crtcs) { + rdev->pm.vblank_sync = false; + wait_event_timeout( + rdev->irq.vblank_queue, rdev->pm.vblank_sync, msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); + } if (rdev->pm.req_vblank & (1 << 0)) { rdev->pm.req_vblank &= ~(1 << 0); drm_vblank_put(rdev->ddev, 0); diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 47f046b78c6..ac7c27adfb7 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -392,10 +392,12 @@ int rs600_irq_process(struct radeon_device *rdev) /* Vertical blank interrupts */ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) { drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) { drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) { From d0d6cb81e7eb34d83461070ca3e919fba1db437c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 2 Mar 2010 22:06:52 +0100 Subject: [PATCH 038/478] drm/radeon/kms: prepare for more reclocking operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 39 ++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index d800b86af4d..4f37b524de7 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -28,6 +28,7 @@ #define RADEON_RECLOCK_DELAY_MS 200 #define RADEON_WAIT_VBLANK_TIMEOUT 200 +static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); static void radeon_pm_set_clocks(struct radeon_device *rdev); static void radeon_pm_idle_work_handler(struct work_struct *work); @@ -179,6 +180,16 @@ static void radeon_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state->non_clock_info.pcie_lanes); } +static inline void radeon_sync_with_vblank(struct radeon_device *rdev) +{ + if (rdev->pm.active_crtcs) { + rdev->pm.vblank_sync = false; + wait_event_timeout( + rdev->irq.vblank_queue, rdev->pm.vblank_sync, + msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); + } +} + static void radeon_set_power_state(struct radeon_device *rdev) { /* if *_clock_mode are the same, *_power_state are as well */ @@ -189,11 +200,28 @@ static void radeon_set_power_state(struct radeon_device *rdev) rdev->pm.requested_clock_mode->sclk, rdev->pm.requested_clock_mode->mclk, rdev->pm.requested_power_state->non_clock_info.pcie_lanes); + /* set pcie lanes */ + /* TODO */ + /* set voltage */ + /* TODO */ + /* set engine clock */ + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + +#if 0 /* set memory clock */ + if (rdev->asic->set_memory_clock) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + } +#endif rdev->pm.current_power_state = rdev->pm.requested_power_state; rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; @@ -333,10 +361,7 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) break; } - /* check if we are in vblank */ - radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_power_state(rdev); - radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.planned_action = PM_ACTION_NONE; } @@ -353,12 +378,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) rdev->pm.req_vblank |= (1 << 1); drm_vblank_get(rdev->ddev, 1); } - if (rdev->pm.active_crtcs) { - rdev->pm.vblank_sync = false; - wait_event_timeout( - rdev->irq.vblank_queue, rdev->pm.vblank_sync, - msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); - } + radeon_pm_set_clocks_locked(rdev); if (rdev->pm.req_vblank & (1 << 0)) { rdev->pm.req_vblank &= ~(1 << 0); drm_vblank_put(rdev->ddev, 0); @@ -368,7 +388,6 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) drm_vblank_put(rdev->ddev, 1); } - radeon_pm_set_clocks_locked(rdev); mutex_unlock(&rdev->cp.mutex); } From 72e942dd846f98e2d35aad5436d77a878ef05c5e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 9 Mar 2010 06:33:26 +0000 Subject: [PATCH 039/478] drm/ttm: use drm calloc large and free large Now that the drm core can do this, lets just use it, split the code out so TTM doesn't have to drag all of drmP.h in. Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_tt.c | 23 ++---------- include/drm/drmP.h | 34 +---------------- include/drm/drm_mem_util.h | 65 +++++++++++++++++++++++++++++++++ include/drm/ttm/ttm_bo_driver.h | 1 - 4 files changed, 69 insertions(+), 54 deletions(-) create mode 100644 include/drm/drm_mem_util.h diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index a759170763b..bab6cd8d8a1 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -28,13 +28,13 @@ * Authors: Thomas Hellstrom */ -#include #include #include #include #include #include #include "drm_cache.h" +#include "drm_mem_util.h" #include "ttm/ttm_module.h" #include "ttm/ttm_bo_driver.h" #include "ttm/ttm_placement.h" @@ -43,32 +43,15 @@ static int ttm_tt_swapin(struct ttm_tt *ttm); /** * Allocates storage for pointers to the pages that back the ttm. - * - * Uses kmalloc if possible. Otherwise falls back to vmalloc. */ static void ttm_tt_alloc_page_directory(struct ttm_tt *ttm) { - unsigned long size = ttm->num_pages * sizeof(*ttm->pages); - ttm->pages = NULL; - - if (size <= PAGE_SIZE) - ttm->pages = kzalloc(size, GFP_KERNEL); - - if (!ttm->pages) { - ttm->pages = vmalloc_user(size); - if (ttm->pages) - ttm->page_flags |= TTM_PAGE_FLAG_VMALLOC; - } + ttm->pages = drm_calloc_large(ttm->num_pages, sizeof(*ttm->pages)); } static void ttm_tt_free_page_directory(struct ttm_tt *ttm) { - if (ttm->page_flags & TTM_PAGE_FLAG_VMALLOC) { - vfree(ttm->pages); - ttm->page_flags &= ~TTM_PAGE_FLAG_VMALLOC; - } else { - kfree(ttm->pages); - } + drm_free_large(ttm->pages); ttm->pages = NULL; } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 4a3c4e44102..de2f82efb15 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1545,39 +1545,7 @@ static __inline__ void drm_core_dropmap(struct drm_local_map *map) { } - -static __inline__ void *drm_calloc_large(size_t nmemb, size_t size) -{ - if (size != 0 && nmemb > ULONG_MAX / size) - return NULL; - - if (size * nmemb <= PAGE_SIZE) - return kcalloc(nmemb, size, GFP_KERNEL); - - return __vmalloc(size * nmemb, - GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); -} - -/* Modeled after cairo's malloc_ab, it's like calloc but without the zeroing. */ -static __inline__ void *drm_malloc_ab(size_t nmemb, size_t size) -{ - if (size != 0 && nmemb > ULONG_MAX / size) - return NULL; - - if (size * nmemb <= PAGE_SIZE) - return kmalloc(nmemb * size, GFP_KERNEL); - - return __vmalloc(size * nmemb, - GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); -} - -static __inline void drm_free_large(void *ptr) -{ - if (!is_vmalloc_addr(ptr)) - return kfree(ptr); - - vfree(ptr); -} +#include "drm_mem_util.h" /*@}*/ #endif /* __KERNEL__ */ diff --git a/include/drm/drm_mem_util.h b/include/drm/drm_mem_util.h new file mode 100644 index 00000000000..6bd325fedc8 --- /dev/null +++ b/include/drm/drm_mem_util.h @@ -0,0 +1,65 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Jesse Barnes + * + */ +#ifndef _DRM_MEM_UTIL_H_ +#define _DRM_MEM_UTIL_H_ + +#include + +static __inline__ void *drm_calloc_large(size_t nmemb, size_t size) +{ + if (size != 0 && nmemb > ULONG_MAX / size) + return NULL; + + if (size * nmemb <= PAGE_SIZE) + return kcalloc(nmemb, size, GFP_KERNEL); + + return __vmalloc(size * nmemb, + GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); +} + +/* Modeled after cairo's malloc_ab, it's like calloc but without the zeroing. */ +static __inline__ void *drm_malloc_ab(size_t nmemb, size_t size) +{ + if (size != 0 && nmemb > ULONG_MAX / size) + return NULL; + + if (size * nmemb <= PAGE_SIZE) + return kmalloc(nmemb * size, GFP_KERNEL); + + return __vmalloc(size * nmemb, + GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); +} + +static __inline void drm_free_large(void *ptr) +{ + if (!is_vmalloc_addr(ptr)) + return kfree(ptr); + + vfree(ptr); +} + +#endif diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index e3f1b4a4b60..e929c27ede2 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -115,7 +115,6 @@ struct ttm_backend { struct ttm_backend_func *func; }; -#define TTM_PAGE_FLAG_VMALLOC (1 << 0) #define TTM_PAGE_FLAG_USER (1 << 1) #define TTM_PAGE_FLAG_USER_DIRTY (1 << 2) #define TTM_PAGE_FLAG_WRITE (1 << 3) From b642ed06f2fccf62534f5269358776e0cba28f3c Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Sat, 13 Mar 2010 10:36:32 +0000 Subject: [PATCH 040/478] drm: "kobject_init/kobject_add" -> "kobject_init_and_add". Replace sequential calls to kobject_init() and kobject_add() with the combo wrapper kobject_init_and_add(), which provides the same semantics. Signed-off-by: Robert P. J. Day Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 4 ++-- drivers/gpu/drm/ttm/ttm_memory.c | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index c7320ce4567..9db02bb3e3f 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1425,8 +1425,8 @@ int ttm_bo_global_init(struct ttm_global_reference *ref) atomic_set(&glob->bo_count, 0); - kobject_init(&glob->kobj, &ttm_bo_glob_kobj_type); - ret = kobject_add(&glob->kobj, ttm_get_kobj(), "buffer_objects"); + ret = kobject_init_and_add( + &glob->kobj, &ttm_bo_glob_kobj_type, ttm_get_kobj(), "buffer_objects"); if (unlikely(ret != 0)) kobject_put(&glob->kobj); return ret; diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c index f5245c02b8f..f9d6b35c3b8 100644 --- a/drivers/gpu/drm/ttm/ttm_memory.c +++ b/drivers/gpu/drm/ttm/ttm_memory.c @@ -260,8 +260,8 @@ static int ttm_mem_init_kernel_zone(struct ttm_mem_global *glob, zone->used_mem = 0; zone->glob = glob; glob->zone_kernel = zone; - kobject_init(&zone->kobj, &ttm_mem_zone_kobj_type); - ret = kobject_add(&zone->kobj, &glob->kobj, zone->name); + ret = kobject_init_and_add( + &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name); if (unlikely(ret != 0)) { kobject_put(&zone->kobj); return ret; @@ -296,8 +296,8 @@ static int ttm_mem_init_highmem_zone(struct ttm_mem_global *glob, zone->used_mem = 0; zone->glob = glob; glob->zone_highmem = zone; - kobject_init(&zone->kobj, &ttm_mem_zone_kobj_type); - ret = kobject_add(&zone->kobj, &glob->kobj, zone->name); + ret = kobject_init_and_add( + &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name); if (unlikely(ret != 0)) { kobject_put(&zone->kobj); return ret; @@ -343,8 +343,8 @@ static int ttm_mem_init_dma32_zone(struct ttm_mem_global *glob, zone->used_mem = 0; zone->glob = glob; glob->zone_dma32 = zone; - kobject_init(&zone->kobj, &ttm_mem_zone_kobj_type); - ret = kobject_add(&zone->kobj, &glob->kobj, zone->name); + ret = kobject_init_and_add( + &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name); if (unlikely(ret != 0)) { kobject_put(&zone->kobj); return ret; @@ -365,10 +365,8 @@ int ttm_mem_global_init(struct ttm_mem_global *glob) glob->swap_queue = create_singlethread_workqueue("ttm_swap"); INIT_WORK(&glob->work, ttm_shrink_work); init_waitqueue_head(&glob->queue); - kobject_init(&glob->kobj, &ttm_mem_glob_kobj_type); - ret = kobject_add(&glob->kobj, - ttm_get_kobj(), - "memory_accounting"); + ret = kobject_init_and_add( + &glob->kobj, &ttm_mem_glob_kobj_type, ttm_get_kobj(), "memory_accounting"); if (unlikely(ret != 0)) { kobject_put(&glob->kobj); return ret; From ae6445ac7475ff0526b019560793e50bad9cf78d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 11 Mar 2010 22:01:39 +0000 Subject: [PATCH 041/478] drm/vmwgfx: depends on FB vmwfgx uses framebuffer interfaces, so it should depend on FB. Otherwise it has these build errors (e.g., when CONFIG_FB=m): drivers/built-in.o: In function `vmw_fb_close': (.text+0x97713): undefined reference to `unregister_framebuffer' drivers/built-in.o: In function `vmw_fb_close': (.text+0x97754): undefined reference to `framebuffer_release' drivers/built-in.o: In function `vmw_fb_init': (.text+0x97e1c): undefined reference to `framebuffer_alloc' drivers/built-in.o: In function `vmw_fb_init': (.text+0x9838d): undefined reference to `register_framebuffer' drivers/built-in.o: In function `vmw_fb_init': (.text+0x9842a): undefined reference to `framebuffer_release' Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Acked-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig index f20b8bcbef3..30ad13344f7 100644 --- a/drivers/gpu/drm/vmwgfx/Kconfig +++ b/drivers/gpu/drm/vmwgfx/Kconfig @@ -1,6 +1,6 @@ config DRM_VMWGFX tristate "DRM driver for VMware Virtual GPU" - depends on DRM && PCI + depends on DRM && PCI && FB select FB_DEFERRED_IO select FB_CFB_FILLRECT select FB_CFB_COPYAREA From 725398322d05486109375fbb85c3404108881e17 Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Thu, 4 Mar 2010 08:25:55 +0000 Subject: [PATCH 042/478] drm: remove the EDID blob stored in the EDID property when it is disconnected Now the EDID property will be updated when the corresponding EDID can be obtained from the external display device. But after the external device is plugged-out, the EDID property is not updated. In such case we still get the corresponding EDID property although it is already detected as disconnected. https://bugs.freedesktop.org/show_bug.cgi?id=26743 Signed-off-by: Zhao Yakui Signed-off-by: Zhenyu Wang Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index f2aaf39be39..51103aa469f 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -104,6 +104,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (connector->status == connector_status_disconnected) { DRM_DEBUG_KMS("%s is disconnected\n", drm_get_connector_name(connector)); + drm_mode_connector_update_edid_property(connector, NULL); goto prune; } From 44fef22416886a04d432043f741a6faf2c6ffefd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 18 Feb 2010 09:12:09 +1000 Subject: [PATCH 043/478] drm/edid: allow certain bogus edids to hit a fixup path rather than fail Signed-off-by: Ben Skeggs Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_edid.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index f97e7c42ac8..7e608f4a0df 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -707,15 +707,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->vsync_end = mode->vsync_start + vsync_pulse_width; mode->vtotal = mode->vdisplay + vblank; - /* perform the basic check for the detailed timing */ - if (mode->hsync_end > mode->htotal || - mode->vsync_end > mode->vtotal) { - drm_mode_destroy(dev, mode); - DRM_DEBUG_KMS("Incorrect detailed timing. " - "Sync is beyond the blank.\n"); - return NULL; - } - /* Some EDIDs have bogus h/vtotal values */ if (mode->hsync_end > mode->htotal) mode->htotal = mode->hsync_end + 1; From 0a10c85129c2d53cfd6db81677628e2fe58b5928 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Mar 2010 21:19:14 +0000 Subject: [PATCH 044/478] drm/radeon: create radeon_asic.c And move asic init plus a few related functions from radeon_device.c to it. This file will hold all the asic structures in the future, but atm they're still stuck in radeon_asic.h. Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/Makefile | 2 +- drivers/gpu/drm/radeon/radeon.h | 6 + drivers/gpu/drm/radeon/radeon_asic.c | 236 +++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_device.c | 199 --------------------- 4 files changed, 243 insertions(+), 200 deletions(-) create mode 100644 drivers/gpu/drm/radeon/radeon_asic.c diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index ed38262d998..3c91312dea9 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -50,7 +50,7 @@ $(obj)/r600_cs.o: $(obj)/r600_reg_safe.h radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o \ radeon_irq.o r300_cmdbuf.o r600_cp.o # add KMS driver -radeon-y += radeon_device.o radeon_kms.o \ +radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ radeon_atombios.o radeon_agp.o atombios_crtc.o radeon_combios.o \ atom.o radeon_fence.o radeon_ttm.o radeon_object.o radeon_gart.o \ radeon_legacy_crtc.o radeon_legacy_encoders.o radeon_connectors.o \ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b54d4f36c4d..67f3c576ab7 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -863,6 +863,12 @@ union radeon_asic_config { struct rv770_asic rv770; }; +/* + * asic initizalization from radeon_asic.c + */ +void radeon_agp_disable(struct radeon_device *rdev); +int radeon_asic_init(struct radeon_device *rdev); + /* * IOCTL. diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c new file mode 100644 index 00000000000..9dffaedccc6 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -0,0 +1,236 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ + +#include +#include +#include +#include +#include +#include +#include "radeon_reg.h" +#include "radeon.h" +#include "radeon_asic.h" +#include "atom.h" + +/* + * Registers accessors functions. + */ +static uint32_t radeon_invalid_rreg(struct radeon_device *rdev, uint32_t reg) +{ + DRM_ERROR("Invalid callback to read register 0x%04X\n", reg); + BUG_ON(1); + return 0; +} + +static void radeon_invalid_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + DRM_ERROR("Invalid callback to write register 0x%04X with 0x%08X\n", + reg, v); + BUG_ON(1); +} + +static void radeon_register_accessor_init(struct radeon_device *rdev) +{ + rdev->mc_rreg = &radeon_invalid_rreg; + rdev->mc_wreg = &radeon_invalid_wreg; + rdev->pll_rreg = &radeon_invalid_rreg; + rdev->pll_wreg = &radeon_invalid_wreg; + rdev->pciep_rreg = &radeon_invalid_rreg; + rdev->pciep_wreg = &radeon_invalid_wreg; + + /* Don't change order as we are overridding accessor. */ + if (rdev->family < CHIP_RV515) { + rdev->pcie_reg_mask = 0xff; + } else { + rdev->pcie_reg_mask = 0x7ff; + } + /* FIXME: not sure here */ + if (rdev->family <= CHIP_R580) { + rdev->pll_rreg = &r100_pll_rreg; + rdev->pll_wreg = &r100_pll_wreg; + } + if (rdev->family >= CHIP_R420) { + rdev->mc_rreg = &r420_mc_rreg; + rdev->mc_wreg = &r420_mc_wreg; + } + if (rdev->family >= CHIP_RV515) { + rdev->mc_rreg = &rv515_mc_rreg; + rdev->mc_wreg = &rv515_mc_wreg; + } + if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) { + rdev->mc_rreg = &rs400_mc_rreg; + rdev->mc_wreg = &rs400_mc_wreg; + } + if (rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { + rdev->mc_rreg = &rs690_mc_rreg; + rdev->mc_wreg = &rs690_mc_wreg; + } + if (rdev->family == CHIP_RS600) { + rdev->mc_rreg = &rs600_mc_rreg; + rdev->mc_wreg = &rs600_mc_wreg; + } + if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_RV740)) { + rdev->pciep_rreg = &r600_pciep_rreg; + rdev->pciep_wreg = &r600_pciep_wreg; + } +} + + +/* helper to disable agp */ +void radeon_agp_disable(struct radeon_device *rdev) +{ + rdev->flags &= ~RADEON_IS_AGP; + if (rdev->family >= CHIP_R600) { + DRM_INFO("Forcing AGP to PCIE mode\n"); + rdev->flags |= RADEON_IS_PCIE; + } else if (rdev->family >= CHIP_RV515 || + rdev->family == CHIP_RV380 || + rdev->family == CHIP_RV410 || + rdev->family == CHIP_R423) { + DRM_INFO("Forcing AGP to PCIE mode\n"); + rdev->flags |= RADEON_IS_PCIE; + rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; + } else { + DRM_INFO("Forcing AGP to PCI mode\n"); + rdev->flags |= RADEON_IS_PCI; + rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush; + rdev->asic->gart_set_page = &r100_pci_gart_set_page; + } + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; +} + +/* + * ASIC + */ +int radeon_asic_init(struct radeon_device *rdev) +{ + radeon_register_accessor_init(rdev); + switch (rdev->family) { + case CHIP_R100: + case CHIP_RV100: + case CHIP_RS100: + case CHIP_RV200: + case CHIP_RS200: + rdev->asic = &r100_asic; + break; + case CHIP_R200: + case CHIP_RV250: + case CHIP_RS300: + case CHIP_RV280: + rdev->asic = &r200_asic; + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_RV350: + case CHIP_RV380: + if (rdev->flags & RADEON_IS_PCIE) + rdev->asic = &r300_asic_pcie; + else + rdev->asic = &r300_asic; + break; + case CHIP_R420: + case CHIP_R423: + case CHIP_RV410: + rdev->asic = &r420_asic; + break; + case CHIP_RS400: + case CHIP_RS480: + rdev->asic = &rs400_asic; + break; + case CHIP_RS600: + rdev->asic = &rs600_asic; + break; + case CHIP_RS690: + case CHIP_RS740: + rdev->asic = &rs690_asic; + break; + case CHIP_RV515: + rdev->asic = &rv515_asic; + break; + case CHIP_R520: + case CHIP_RV530: + case CHIP_RV560: + case CHIP_RV570: + case CHIP_R580: + rdev->asic = &r520_asic; + break; + case CHIP_R600: + case CHIP_RV610: + case CHIP_RV630: + case CHIP_RV620: + case CHIP_RV635: + case CHIP_RV670: + case CHIP_RS780: + case CHIP_RS880: + rdev->asic = &r600_asic; + break; + case CHIP_RV770: + case CHIP_RV730: + case CHIP_RV710: + case CHIP_RV740: + rdev->asic = &rv770_asic; + break; + case CHIP_CEDAR: + case CHIP_REDWOOD: + case CHIP_JUNIPER: + case CHIP_CYPRESS: + case CHIP_HEMLOCK: + rdev->asic = &evergreen_asic; + break; + default: + /* FIXME: not supported yet */ + return -EINVAL; + } + + if (rdev->flags & RADEON_IS_IGP) { + rdev->asic->get_memory_clock = NULL; + rdev->asic->set_memory_clock = NULL; + } + + return 0; +} + +/* + * Wrapper around modesetting bits. Move to radeon_clocks.c? + */ +int radeon_clocks_init(struct radeon_device *rdev) +{ + int r; + + r = radeon_static_clocks_init(rdev->ddev); + if (r) { + return r; + } + DRM_INFO("Clocks initialized !\n"); + return 0; +} + +void radeon_clocks_fini(struct radeon_device *rdev) +{ +} diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index e28e4ed5f72..581b75ad6ce 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -33,7 +33,6 @@ #include #include "radeon_reg.h" #include "radeon.h" -#include "radeon_asic.h" #include "atom.h" /* @@ -288,181 +287,6 @@ void radeon_dummy_page_fini(struct radeon_device *rdev) } -/* - * Registers accessors functions. - */ -uint32_t radeon_invalid_rreg(struct radeon_device *rdev, uint32_t reg) -{ - DRM_ERROR("Invalid callback to read register 0x%04X\n", reg); - BUG_ON(1); - return 0; -} - -void radeon_invalid_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) -{ - DRM_ERROR("Invalid callback to write register 0x%04X with 0x%08X\n", - reg, v); - BUG_ON(1); -} - -void radeon_register_accessor_init(struct radeon_device *rdev) -{ - rdev->mc_rreg = &radeon_invalid_rreg; - rdev->mc_wreg = &radeon_invalid_wreg; - rdev->pll_rreg = &radeon_invalid_rreg; - rdev->pll_wreg = &radeon_invalid_wreg; - rdev->pciep_rreg = &radeon_invalid_rreg; - rdev->pciep_wreg = &radeon_invalid_wreg; - - /* Don't change order as we are overridding accessor. */ - if (rdev->family < CHIP_RV515) { - rdev->pcie_reg_mask = 0xff; - } else { - rdev->pcie_reg_mask = 0x7ff; - } - /* FIXME: not sure here */ - if (rdev->family <= CHIP_R580) { - rdev->pll_rreg = &r100_pll_rreg; - rdev->pll_wreg = &r100_pll_wreg; - } - if (rdev->family >= CHIP_R420) { - rdev->mc_rreg = &r420_mc_rreg; - rdev->mc_wreg = &r420_mc_wreg; - } - if (rdev->family >= CHIP_RV515) { - rdev->mc_rreg = &rv515_mc_rreg; - rdev->mc_wreg = &rv515_mc_wreg; - } - if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) { - rdev->mc_rreg = &rs400_mc_rreg; - rdev->mc_wreg = &rs400_mc_wreg; - } - if (rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { - rdev->mc_rreg = &rs690_mc_rreg; - rdev->mc_wreg = &rs690_mc_wreg; - } - if (rdev->family == CHIP_RS600) { - rdev->mc_rreg = &rs600_mc_rreg; - rdev->mc_wreg = &rs600_mc_wreg; - } - if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_RV740)) { - rdev->pciep_rreg = &r600_pciep_rreg; - rdev->pciep_wreg = &r600_pciep_wreg; - } -} - - -/* - * ASIC - */ -int radeon_asic_init(struct radeon_device *rdev) -{ - radeon_register_accessor_init(rdev); - switch (rdev->family) { - case CHIP_R100: - case CHIP_RV100: - case CHIP_RS100: - case CHIP_RV200: - case CHIP_RS200: - rdev->asic = &r100_asic; - break; - case CHIP_R200: - case CHIP_RV250: - case CHIP_RS300: - case CHIP_RV280: - rdev->asic = &r200_asic; - break; - case CHIP_R300: - case CHIP_R350: - case CHIP_RV350: - case CHIP_RV380: - if (rdev->flags & RADEON_IS_PCIE) - rdev->asic = &r300_asic_pcie; - else - rdev->asic = &r300_asic; - break; - case CHIP_R420: - case CHIP_R423: - case CHIP_RV410: - rdev->asic = &r420_asic; - break; - case CHIP_RS400: - case CHIP_RS480: - rdev->asic = &rs400_asic; - break; - case CHIP_RS600: - rdev->asic = &rs600_asic; - break; - case CHIP_RS690: - case CHIP_RS740: - rdev->asic = &rs690_asic; - break; - case CHIP_RV515: - rdev->asic = &rv515_asic; - break; - case CHIP_R520: - case CHIP_RV530: - case CHIP_RV560: - case CHIP_RV570: - case CHIP_R580: - rdev->asic = &r520_asic; - break; - case CHIP_R600: - case CHIP_RV610: - case CHIP_RV630: - case CHIP_RV620: - case CHIP_RV635: - case CHIP_RV670: - case CHIP_RS780: - case CHIP_RS880: - rdev->asic = &r600_asic; - break; - case CHIP_RV770: - case CHIP_RV730: - case CHIP_RV710: - case CHIP_RV740: - rdev->asic = &rv770_asic; - break; - case CHIP_CEDAR: - case CHIP_REDWOOD: - case CHIP_JUNIPER: - case CHIP_CYPRESS: - case CHIP_HEMLOCK: - rdev->asic = &evergreen_asic; - break; - default: - /* FIXME: not supported yet */ - return -EINVAL; - } - - if (rdev->flags & RADEON_IS_IGP) { - rdev->asic->get_memory_clock = NULL; - rdev->asic->set_memory_clock = NULL; - } - - return 0; -} - - -/* - * Wrapper around modesetting bits. - */ -int radeon_clocks_init(struct radeon_device *rdev) -{ - int r; - - r = radeon_static_clocks_init(rdev->ddev); - if (r) { - return r; - } - DRM_INFO("Clocks initialized !\n"); - return 0; -} - -void radeon_clocks_fini(struct radeon_device *rdev) -{ -} - /* ATOM accessor methods */ static uint32_t cail_pll_read(struct card_info *info, uint32_t reg) { @@ -567,29 +391,6 @@ static unsigned int radeon_vga_set_decode(void *cookie, bool state) return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; } -void radeon_agp_disable(struct radeon_device *rdev) -{ - rdev->flags &= ~RADEON_IS_AGP; - if (rdev->family >= CHIP_R600) { - DRM_INFO("Forcing AGP to PCIE mode\n"); - rdev->flags |= RADEON_IS_PCIE; - } else if (rdev->family >= CHIP_RV515 || - rdev->family == CHIP_RV380 || - rdev->family == CHIP_RV410 || - rdev->family == CHIP_R423) { - DRM_INFO("Forcing AGP to PCIE mode\n"); - rdev->flags |= RADEON_IS_PCIE; - rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; - rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; - } else { - DRM_INFO("Forcing AGP to PCI mode\n"); - rdev->flags |= RADEON_IS_PCI; - rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush; - rdev->asic->gart_set_page = &r100_pci_gart_set_page; - } - rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; -} - void radeon_check_arguments(struct radeon_device *rdev) { /* vramlimit must be a power of two */ From 48e7a5f19fe0c10ebb35be7acf383366d139ee0a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Mar 2010 21:19:15 +0000 Subject: [PATCH 045/478] drm/radeon: move asic structs to radeon_asic.c With these static structs gone, radeon_asic.h is a real header file and can be used as such. Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_asic.c | 487 ++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_asic.h | 489 --------------------------- 2 files changed, 487 insertions(+), 489 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 9dffaedccc6..6d2a5457c2c 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -128,6 +128,493 @@ void radeon_agp_disable(struct radeon_device *rdev) /* * ASIC */ +static struct radeon_asic r100_asic = { + .init = &r100_init, + .fini = &r100_fini, + .suspend = &r100_suspend, + .resume = &r100_resume, + .vga_set_state = &r100_vga_set_state, + .gpu_reset = &r100_gpu_reset, + .gart_tlb_flush = &r100_pci_gart_tlb_flush, + .gart_set_page = &r100_pci_gart_set_page, + .cp_commit = &r100_cp_commit, + .ring_start = &r100_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .get_vblank_counter = &r100_get_vblank_counter, + .fence_ring_emit = &r100_fence_ring_emit, + .cs_parse = &r100_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = NULL, + .copy = &r100_copy_blit, + .get_engine_clock = &radeon_legacy_get_engine_clock, + .set_engine_clock = &radeon_legacy_set_engine_clock, + .get_memory_clock = &radeon_legacy_get_memory_clock, + .set_memory_clock = NULL, + .get_pcie_lanes = NULL, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_legacy_set_clock_gating, + .set_surface_reg = r100_set_surface_reg, + .clear_surface_reg = r100_clear_surface_reg, + .bandwidth_update = &r100_bandwidth_update, + .hpd_init = &r100_hpd_init, + .hpd_fini = &r100_hpd_fini, + .hpd_sense = &r100_hpd_sense, + .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, +}; + +static struct radeon_asic r200_asic = { + .init = &r100_init, + .fini = &r100_fini, + .suspend = &r100_suspend, + .resume = &r100_resume, + .vga_set_state = &r100_vga_set_state, + .gpu_reset = &r100_gpu_reset, + .gart_tlb_flush = &r100_pci_gart_tlb_flush, + .gart_set_page = &r100_pci_gart_set_page, + .cp_commit = &r100_cp_commit, + .ring_start = &r100_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .get_vblank_counter = &r100_get_vblank_counter, + .fence_ring_emit = &r100_fence_ring_emit, + .cs_parse = &r100_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r200_copy_dma, + .copy = &r100_copy_blit, + .get_engine_clock = &radeon_legacy_get_engine_clock, + .set_engine_clock = &radeon_legacy_set_engine_clock, + .get_memory_clock = &radeon_legacy_get_memory_clock, + .set_memory_clock = NULL, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_legacy_set_clock_gating, + .set_surface_reg = r100_set_surface_reg, + .clear_surface_reg = r100_clear_surface_reg, + .bandwidth_update = &r100_bandwidth_update, + .hpd_init = &r100_hpd_init, + .hpd_fini = &r100_hpd_fini, + .hpd_sense = &r100_hpd_sense, + .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, +}; + +static struct radeon_asic r300_asic = { + .init = &r300_init, + .fini = &r300_fini, + .suspend = &r300_suspend, + .resume = &r300_resume, + .vga_set_state = &r100_vga_set_state, + .gpu_reset = &r300_gpu_reset, + .gart_tlb_flush = &r100_pci_gart_tlb_flush, + .gart_set_page = &r100_pci_gart_set_page, + .cp_commit = &r100_cp_commit, + .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .get_vblank_counter = &r100_get_vblank_counter, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r200_copy_dma, + .copy = &r100_copy_blit, + .get_engine_clock = &radeon_legacy_get_engine_clock, + .set_engine_clock = &radeon_legacy_set_engine_clock, + .get_memory_clock = &radeon_legacy_get_memory_clock, + .set_memory_clock = NULL, + .get_pcie_lanes = &rv370_get_pcie_lanes, + .set_pcie_lanes = &rv370_set_pcie_lanes, + .set_clock_gating = &radeon_legacy_set_clock_gating, + .set_surface_reg = r100_set_surface_reg, + .clear_surface_reg = r100_clear_surface_reg, + .bandwidth_update = &r100_bandwidth_update, + .hpd_init = &r100_hpd_init, + .hpd_fini = &r100_hpd_fini, + .hpd_sense = &r100_hpd_sense, + .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, +}; + +static struct radeon_asic r300_asic_pcie = { + .init = &r300_init, + .fini = &r300_fini, + .suspend = &r300_suspend, + .resume = &r300_resume, + .vga_set_state = &r100_vga_set_state, + .gpu_reset = &r300_gpu_reset, + .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, + .gart_set_page = &rv370_pcie_gart_set_page, + .cp_commit = &r100_cp_commit, + .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .get_vblank_counter = &r100_get_vblank_counter, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r200_copy_dma, + .copy = &r100_copy_blit, + .get_engine_clock = &radeon_legacy_get_engine_clock, + .set_engine_clock = &radeon_legacy_set_engine_clock, + .get_memory_clock = &radeon_legacy_get_memory_clock, + .set_memory_clock = NULL, + .set_pcie_lanes = &rv370_set_pcie_lanes, + .set_clock_gating = &radeon_legacy_set_clock_gating, + .set_surface_reg = r100_set_surface_reg, + .clear_surface_reg = r100_clear_surface_reg, + .bandwidth_update = &r100_bandwidth_update, + .hpd_init = &r100_hpd_init, + .hpd_fini = &r100_hpd_fini, + .hpd_sense = &r100_hpd_sense, + .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, +}; + +static struct radeon_asic r420_asic = { + .init = &r420_init, + .fini = &r420_fini, + .suspend = &r420_suspend, + .resume = &r420_resume, + .vga_set_state = &r100_vga_set_state, + .gpu_reset = &r300_gpu_reset, + .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, + .gart_set_page = &rv370_pcie_gart_set_page, + .cp_commit = &r100_cp_commit, + .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .get_vblank_counter = &r100_get_vblank_counter, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r200_copy_dma, + .copy = &r100_copy_blit, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = &radeon_atom_get_memory_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .get_pcie_lanes = &rv370_get_pcie_lanes, + .set_pcie_lanes = &rv370_set_pcie_lanes, + .set_clock_gating = &radeon_atom_set_clock_gating, + .set_surface_reg = r100_set_surface_reg, + .clear_surface_reg = r100_clear_surface_reg, + .bandwidth_update = &r100_bandwidth_update, + .hpd_init = &r100_hpd_init, + .hpd_fini = &r100_hpd_fini, + .hpd_sense = &r100_hpd_sense, + .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, +}; + +static struct radeon_asic rs400_asic = { + .init = &rs400_init, + .fini = &rs400_fini, + .suspend = &rs400_suspend, + .resume = &rs400_resume, + .vga_set_state = &r100_vga_set_state, + .gpu_reset = &r300_gpu_reset, + .gart_tlb_flush = &rs400_gart_tlb_flush, + .gart_set_page = &rs400_gart_set_page, + .cp_commit = &r100_cp_commit, + .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .get_vblank_counter = &r100_get_vblank_counter, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r200_copy_dma, + .copy = &r100_copy_blit, + .get_engine_clock = &radeon_legacy_get_engine_clock, + .set_engine_clock = &radeon_legacy_set_engine_clock, + .get_memory_clock = &radeon_legacy_get_memory_clock, + .set_memory_clock = NULL, + .get_pcie_lanes = NULL, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_legacy_set_clock_gating, + .set_surface_reg = r100_set_surface_reg, + .clear_surface_reg = r100_clear_surface_reg, + .bandwidth_update = &r100_bandwidth_update, + .hpd_init = &r100_hpd_init, + .hpd_fini = &r100_hpd_fini, + .hpd_sense = &r100_hpd_sense, + .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, +}; + +static struct radeon_asic rs600_asic = { + .init = &rs600_init, + .fini = &rs600_fini, + .suspend = &rs600_suspend, + .resume = &rs600_resume, + .vga_set_state = &r100_vga_set_state, + .gpu_reset = &r300_gpu_reset, + .gart_tlb_flush = &rs600_gart_tlb_flush, + .gart_set_page = &rs600_gart_set_page, + .cp_commit = &r100_cp_commit, + .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .irq_set = &rs600_irq_set, + .irq_process = &rs600_irq_process, + .get_vblank_counter = &rs600_get_vblank_counter, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r200_copy_dma, + .copy = &r100_copy_blit, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = &radeon_atom_get_memory_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .get_pcie_lanes = NULL, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_atom_set_clock_gating, + .set_surface_reg = r100_set_surface_reg, + .clear_surface_reg = r100_clear_surface_reg, + .bandwidth_update = &rs600_bandwidth_update, + .hpd_init = &rs600_hpd_init, + .hpd_fini = &rs600_hpd_fini, + .hpd_sense = &rs600_hpd_sense, + .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, +}; + +static struct radeon_asic rs690_asic = { + .init = &rs690_init, + .fini = &rs690_fini, + .suspend = &rs690_suspend, + .resume = &rs690_resume, + .vga_set_state = &r100_vga_set_state, + .gpu_reset = &r300_gpu_reset, + .gart_tlb_flush = &rs400_gart_tlb_flush, + .gart_set_page = &rs400_gart_set_page, + .cp_commit = &r100_cp_commit, + .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .irq_set = &rs600_irq_set, + .irq_process = &rs600_irq_process, + .get_vblank_counter = &rs600_get_vblank_counter, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r200_copy_dma, + .copy = &r200_copy_dma, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = &radeon_atom_get_memory_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .get_pcie_lanes = NULL, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_atom_set_clock_gating, + .set_surface_reg = r100_set_surface_reg, + .clear_surface_reg = r100_clear_surface_reg, + .bandwidth_update = &rs690_bandwidth_update, + .hpd_init = &rs600_hpd_init, + .hpd_fini = &rs600_hpd_fini, + .hpd_sense = &rs600_hpd_sense, + .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, +}; + +static struct radeon_asic rv515_asic = { + .init = &rv515_init, + .fini = &rv515_fini, + .suspend = &rv515_suspend, + .resume = &rv515_resume, + .vga_set_state = &r100_vga_set_state, + .gpu_reset = &rv515_gpu_reset, + .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, + .gart_set_page = &rv370_pcie_gart_set_page, + .cp_commit = &r100_cp_commit, + .ring_start = &rv515_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .irq_set = &rs600_irq_set, + .irq_process = &rs600_irq_process, + .get_vblank_counter = &rs600_get_vblank_counter, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r200_copy_dma, + .copy = &r100_copy_blit, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = &radeon_atom_get_memory_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .get_pcie_lanes = &rv370_get_pcie_lanes, + .set_pcie_lanes = &rv370_set_pcie_lanes, + .set_clock_gating = &radeon_atom_set_clock_gating, + .set_surface_reg = r100_set_surface_reg, + .clear_surface_reg = r100_clear_surface_reg, + .bandwidth_update = &rv515_bandwidth_update, + .hpd_init = &rs600_hpd_init, + .hpd_fini = &rs600_hpd_fini, + .hpd_sense = &rs600_hpd_sense, + .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, +}; + +static struct radeon_asic r520_asic = { + .init = &r520_init, + .fini = &rv515_fini, + .suspend = &rv515_suspend, + .resume = &r520_resume, + .vga_set_state = &r100_vga_set_state, + .gpu_reset = &rv515_gpu_reset, + .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, + .gart_set_page = &rv370_pcie_gart_set_page, + .cp_commit = &r100_cp_commit, + .ring_start = &rv515_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .irq_set = &rs600_irq_set, + .irq_process = &rs600_irq_process, + .get_vblank_counter = &rs600_get_vblank_counter, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r200_copy_dma, + .copy = &r100_copy_blit, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = &radeon_atom_get_memory_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .get_pcie_lanes = &rv370_get_pcie_lanes, + .set_pcie_lanes = &rv370_set_pcie_lanes, + .set_clock_gating = &radeon_atom_set_clock_gating, + .set_surface_reg = r100_set_surface_reg, + .clear_surface_reg = r100_clear_surface_reg, + .bandwidth_update = &rv515_bandwidth_update, + .hpd_init = &rs600_hpd_init, + .hpd_fini = &rs600_hpd_fini, + .hpd_sense = &rs600_hpd_sense, + .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, +}; + +static struct radeon_asic r600_asic = { + .init = &r600_init, + .fini = &r600_fini, + .suspend = &r600_suspend, + .resume = &r600_resume, + .cp_commit = &r600_cp_commit, + .vga_set_state = &r600_vga_set_state, + .gpu_reset = &r600_gpu_reset, + .gart_tlb_flush = &r600_pcie_gart_tlb_flush, + .gart_set_page = &rs600_gart_set_page, + .ring_test = &r600_ring_test, + .ring_ib_execute = &r600_ring_ib_execute, + .irq_set = &r600_irq_set, + .irq_process = &r600_irq_process, + .get_vblank_counter = &rs600_get_vblank_counter, + .fence_ring_emit = &r600_fence_ring_emit, + .cs_parse = &r600_cs_parse, + .copy_blit = &r600_copy_blit, + .copy_dma = &r600_copy_blit, + .copy = &r600_copy_blit, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = &radeon_atom_get_memory_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .get_pcie_lanes = &rv370_get_pcie_lanes, + .set_pcie_lanes = NULL, + .set_clock_gating = NULL, + .set_surface_reg = r600_set_surface_reg, + .clear_surface_reg = r600_clear_surface_reg, + .bandwidth_update = &rv515_bandwidth_update, + .hpd_init = &r600_hpd_init, + .hpd_fini = &r600_hpd_fini, + .hpd_sense = &r600_hpd_sense, + .hpd_set_polarity = &r600_hpd_set_polarity, + .ioctl_wait_idle = r600_ioctl_wait_idle, +}; + +static struct radeon_asic rv770_asic = { + .init = &rv770_init, + .fini = &rv770_fini, + .suspend = &rv770_suspend, + .resume = &rv770_resume, + .cp_commit = &r600_cp_commit, + .gpu_reset = &rv770_gpu_reset, + .vga_set_state = &r600_vga_set_state, + .gart_tlb_flush = &r600_pcie_gart_tlb_flush, + .gart_set_page = &rs600_gart_set_page, + .ring_test = &r600_ring_test, + .ring_ib_execute = &r600_ring_ib_execute, + .irq_set = &r600_irq_set, + .irq_process = &r600_irq_process, + .get_vblank_counter = &rs600_get_vblank_counter, + .fence_ring_emit = &r600_fence_ring_emit, + .cs_parse = &r600_cs_parse, + .copy_blit = &r600_copy_blit, + .copy_dma = &r600_copy_blit, + .copy = &r600_copy_blit, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = &radeon_atom_get_memory_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .get_pcie_lanes = &rv370_get_pcie_lanes, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_atom_set_clock_gating, + .set_surface_reg = r600_set_surface_reg, + .clear_surface_reg = r600_clear_surface_reg, + .bandwidth_update = &rv515_bandwidth_update, + .hpd_init = &r600_hpd_init, + .hpd_fini = &r600_hpd_fini, + .hpd_sense = &r600_hpd_sense, + .hpd_set_polarity = &r600_hpd_set_polarity, + .ioctl_wait_idle = r600_ioctl_wait_idle, +}; + +static struct radeon_asic evergreen_asic = { + .init = &evergreen_init, + .fini = &evergreen_fini, + .suspend = &evergreen_suspend, + .resume = &evergreen_resume, + .cp_commit = NULL, + .gpu_reset = &evergreen_gpu_reset, + .vga_set_state = &r600_vga_set_state, + .gart_tlb_flush = &r600_pcie_gart_tlb_flush, + .gart_set_page = &rs600_gart_set_page, + .ring_test = NULL, + .ring_ib_execute = NULL, + .irq_set = NULL, + .irq_process = NULL, + .get_vblank_counter = NULL, + .fence_ring_emit = NULL, + .cs_parse = NULL, + .copy_blit = NULL, + .copy_dma = NULL, + .copy = NULL, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = &radeon_atom_get_memory_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .set_pcie_lanes = NULL, + .set_clock_gating = NULL, + .set_surface_reg = r600_set_surface_reg, + .clear_surface_reg = r600_clear_surface_reg, + .bandwidth_update = &evergreen_bandwidth_update, + .hpd_init = &evergreen_hpd_init, + .hpd_fini = &evergreen_hpd_fini, + .hpd_sense = &evergreen_hpd_sense, + .hpd_set_polarity = &evergreen_hpd_set_polarity, +}; + int radeon_asic_init(struct radeon_device *rdev) { radeon_register_accessor_init(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index d3a157b2bcb..2bc26232dc9 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -83,44 +83,6 @@ bool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void r100_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); -static struct radeon_asic r100_asic = { - .init = &r100_init, - .fini = &r100_fini, - .suspend = &r100_suspend, - .resume = &r100_resume, - .vga_set_state = &r100_vga_set_state, - .gpu_reset = &r100_gpu_reset, - .gart_tlb_flush = &r100_pci_gart_tlb_flush, - .gart_set_page = &r100_pci_gart_set_page, - .cp_commit = &r100_cp_commit, - .ring_start = &r100_ring_start, - .ring_test = &r100_ring_test, - .ring_ib_execute = &r100_ring_ib_execute, - .irq_set = &r100_irq_set, - .irq_process = &r100_irq_process, - .get_vblank_counter = &r100_get_vblank_counter, - .fence_ring_emit = &r100_fence_ring_emit, - .cs_parse = &r100_cs_parse, - .copy_blit = &r100_copy_blit, - .copy_dma = NULL, - .copy = &r100_copy_blit, - .get_engine_clock = &radeon_legacy_get_engine_clock, - .set_engine_clock = &radeon_legacy_set_engine_clock, - .get_memory_clock = &radeon_legacy_get_memory_clock, - .set_memory_clock = NULL, - .get_pcie_lanes = NULL, - .set_pcie_lanes = NULL, - .set_clock_gating = &radeon_legacy_set_clock_gating, - .set_surface_reg = r100_set_surface_reg, - .clear_surface_reg = r100_clear_surface_reg, - .bandwidth_update = &r100_bandwidth_update, - .hpd_init = &r100_hpd_init, - .hpd_fini = &r100_hpd_fini, - .hpd_sense = &r100_hpd_sense, - .hpd_set_polarity = &r100_hpd_set_polarity, - .ioctl_wait_idle = NULL, -}; - /* * r200,rv250,rs300,rv280 */ @@ -129,43 +91,6 @@ extern int r200_copy_dma(struct radeon_device *rdev, uint64_t dst_offset, unsigned num_pages, struct radeon_fence *fence); -static struct radeon_asic r200_asic = { - .init = &r100_init, - .fini = &r100_fini, - .suspend = &r100_suspend, - .resume = &r100_resume, - .vga_set_state = &r100_vga_set_state, - .gpu_reset = &r100_gpu_reset, - .gart_tlb_flush = &r100_pci_gart_tlb_flush, - .gart_set_page = &r100_pci_gart_set_page, - .cp_commit = &r100_cp_commit, - .ring_start = &r100_ring_start, - .ring_test = &r100_ring_test, - .ring_ib_execute = &r100_ring_ib_execute, - .irq_set = &r100_irq_set, - .irq_process = &r100_irq_process, - .get_vblank_counter = &r100_get_vblank_counter, - .fence_ring_emit = &r100_fence_ring_emit, - .cs_parse = &r100_cs_parse, - .copy_blit = &r100_copy_blit, - .copy_dma = &r200_copy_dma, - .copy = &r100_copy_blit, - .get_engine_clock = &radeon_legacy_get_engine_clock, - .set_engine_clock = &radeon_legacy_set_engine_clock, - .get_memory_clock = &radeon_legacy_get_memory_clock, - .set_memory_clock = NULL, - .set_pcie_lanes = NULL, - .set_clock_gating = &radeon_legacy_set_clock_gating, - .set_surface_reg = r100_set_surface_reg, - .clear_surface_reg = r100_clear_surface_reg, - .bandwidth_update = &r100_bandwidth_update, - .hpd_init = &r100_hpd_init, - .hpd_fini = &r100_hpd_fini, - .hpd_sense = &r100_hpd_sense, - .hpd_set_polarity = &r100_hpd_set_polarity, - .ioctl_wait_idle = NULL, -}; - /* * r300,r350,rv350,rv380 @@ -186,82 +111,6 @@ extern void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes); extern int rv370_get_pcie_lanes(struct radeon_device *rdev); -static struct radeon_asic r300_asic = { - .init = &r300_init, - .fini = &r300_fini, - .suspend = &r300_suspend, - .resume = &r300_resume, - .vga_set_state = &r100_vga_set_state, - .gpu_reset = &r300_gpu_reset, - .gart_tlb_flush = &r100_pci_gart_tlb_flush, - .gart_set_page = &r100_pci_gart_set_page, - .cp_commit = &r100_cp_commit, - .ring_start = &r300_ring_start, - .ring_test = &r100_ring_test, - .ring_ib_execute = &r100_ring_ib_execute, - .irq_set = &r100_irq_set, - .irq_process = &r100_irq_process, - .get_vblank_counter = &r100_get_vblank_counter, - .fence_ring_emit = &r300_fence_ring_emit, - .cs_parse = &r300_cs_parse, - .copy_blit = &r100_copy_blit, - .copy_dma = &r200_copy_dma, - .copy = &r100_copy_blit, - .get_engine_clock = &radeon_legacy_get_engine_clock, - .set_engine_clock = &radeon_legacy_set_engine_clock, - .get_memory_clock = &radeon_legacy_get_memory_clock, - .set_memory_clock = NULL, - .get_pcie_lanes = &rv370_get_pcie_lanes, - .set_pcie_lanes = &rv370_set_pcie_lanes, - .set_clock_gating = &radeon_legacy_set_clock_gating, - .set_surface_reg = r100_set_surface_reg, - .clear_surface_reg = r100_clear_surface_reg, - .bandwidth_update = &r100_bandwidth_update, - .hpd_init = &r100_hpd_init, - .hpd_fini = &r100_hpd_fini, - .hpd_sense = &r100_hpd_sense, - .hpd_set_polarity = &r100_hpd_set_polarity, - .ioctl_wait_idle = NULL, -}; - - -static struct radeon_asic r300_asic_pcie = { - .init = &r300_init, - .fini = &r300_fini, - .suspend = &r300_suspend, - .resume = &r300_resume, - .vga_set_state = &r100_vga_set_state, - .gpu_reset = &r300_gpu_reset, - .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, - .gart_set_page = &rv370_pcie_gart_set_page, - .cp_commit = &r100_cp_commit, - .ring_start = &r300_ring_start, - .ring_test = &r100_ring_test, - .ring_ib_execute = &r100_ring_ib_execute, - .irq_set = &r100_irq_set, - .irq_process = &r100_irq_process, - .get_vblank_counter = &r100_get_vblank_counter, - .fence_ring_emit = &r300_fence_ring_emit, - .cs_parse = &r300_cs_parse, - .copy_blit = &r100_copy_blit, - .copy_dma = &r200_copy_dma, - .copy = &r100_copy_blit, - .get_engine_clock = &radeon_legacy_get_engine_clock, - .set_engine_clock = &radeon_legacy_set_engine_clock, - .get_memory_clock = &radeon_legacy_get_memory_clock, - .set_memory_clock = NULL, - .set_pcie_lanes = &rv370_set_pcie_lanes, - .set_clock_gating = &radeon_legacy_set_clock_gating, - .set_surface_reg = r100_set_surface_reg, - .clear_surface_reg = r100_clear_surface_reg, - .bandwidth_update = &r100_bandwidth_update, - .hpd_init = &r100_hpd_init, - .hpd_fini = &r100_hpd_fini, - .hpd_sense = &r100_hpd_sense, - .hpd_set_polarity = &r100_hpd_set_polarity, - .ioctl_wait_idle = NULL, -}; - /* * r420,r423,rv410 */ @@ -269,44 +118,6 @@ extern int r420_init(struct radeon_device *rdev); extern void r420_fini(struct radeon_device *rdev); extern int r420_suspend(struct radeon_device *rdev); extern int r420_resume(struct radeon_device *rdev); -static struct radeon_asic r420_asic = { - .init = &r420_init, - .fini = &r420_fini, - .suspend = &r420_suspend, - .resume = &r420_resume, - .vga_set_state = &r100_vga_set_state, - .gpu_reset = &r300_gpu_reset, - .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, - .gart_set_page = &rv370_pcie_gart_set_page, - .cp_commit = &r100_cp_commit, - .ring_start = &r300_ring_start, - .ring_test = &r100_ring_test, - .ring_ib_execute = &r100_ring_ib_execute, - .irq_set = &r100_irq_set, - .irq_process = &r100_irq_process, - .get_vblank_counter = &r100_get_vblank_counter, - .fence_ring_emit = &r300_fence_ring_emit, - .cs_parse = &r300_cs_parse, - .copy_blit = &r100_copy_blit, - .copy_dma = &r200_copy_dma, - .copy = &r100_copy_blit, - .get_engine_clock = &radeon_atom_get_engine_clock, - .set_engine_clock = &radeon_atom_set_engine_clock, - .get_memory_clock = &radeon_atom_get_memory_clock, - .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = &rv370_get_pcie_lanes, - .set_pcie_lanes = &rv370_set_pcie_lanes, - .set_clock_gating = &radeon_atom_set_clock_gating, - .set_surface_reg = r100_set_surface_reg, - .clear_surface_reg = r100_clear_surface_reg, - .bandwidth_update = &r100_bandwidth_update, - .hpd_init = &r100_hpd_init, - .hpd_fini = &r100_hpd_fini, - .hpd_sense = &r100_hpd_sense, - .hpd_set_polarity = &r100_hpd_set_polarity, - .ioctl_wait_idle = NULL, -}; - /* * rs400,rs480 @@ -319,44 +130,6 @@ void rs400_gart_tlb_flush(struct radeon_device *rdev); int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); -static struct radeon_asic rs400_asic = { - .init = &rs400_init, - .fini = &rs400_fini, - .suspend = &rs400_suspend, - .resume = &rs400_resume, - .vga_set_state = &r100_vga_set_state, - .gpu_reset = &r300_gpu_reset, - .gart_tlb_flush = &rs400_gart_tlb_flush, - .gart_set_page = &rs400_gart_set_page, - .cp_commit = &r100_cp_commit, - .ring_start = &r300_ring_start, - .ring_test = &r100_ring_test, - .ring_ib_execute = &r100_ring_ib_execute, - .irq_set = &r100_irq_set, - .irq_process = &r100_irq_process, - .get_vblank_counter = &r100_get_vblank_counter, - .fence_ring_emit = &r300_fence_ring_emit, - .cs_parse = &r300_cs_parse, - .copy_blit = &r100_copy_blit, - .copy_dma = &r200_copy_dma, - .copy = &r100_copy_blit, - .get_engine_clock = &radeon_legacy_get_engine_clock, - .set_engine_clock = &radeon_legacy_set_engine_clock, - .get_memory_clock = &radeon_legacy_get_memory_clock, - .set_memory_clock = NULL, - .get_pcie_lanes = NULL, - .set_pcie_lanes = NULL, - .set_clock_gating = &radeon_legacy_set_clock_gating, - .set_surface_reg = r100_set_surface_reg, - .clear_surface_reg = r100_clear_surface_reg, - .bandwidth_update = &r100_bandwidth_update, - .hpd_init = &r100_hpd_init, - .hpd_fini = &r100_hpd_fini, - .hpd_sense = &r100_hpd_sense, - .hpd_set_polarity = &r100_hpd_set_polarity, - .ioctl_wait_idle = NULL, -}; - /* * rs600. @@ -379,45 +152,6 @@ bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void rs600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); -static struct radeon_asic rs600_asic = { - .init = &rs600_init, - .fini = &rs600_fini, - .suspend = &rs600_suspend, - .resume = &rs600_resume, - .vga_set_state = &r100_vga_set_state, - .gpu_reset = &r300_gpu_reset, - .gart_tlb_flush = &rs600_gart_tlb_flush, - .gart_set_page = &rs600_gart_set_page, - .cp_commit = &r100_cp_commit, - .ring_start = &r300_ring_start, - .ring_test = &r100_ring_test, - .ring_ib_execute = &r100_ring_ib_execute, - .irq_set = &rs600_irq_set, - .irq_process = &rs600_irq_process, - .get_vblank_counter = &rs600_get_vblank_counter, - .fence_ring_emit = &r300_fence_ring_emit, - .cs_parse = &r300_cs_parse, - .copy_blit = &r100_copy_blit, - .copy_dma = &r200_copy_dma, - .copy = &r100_copy_blit, - .get_engine_clock = &radeon_atom_get_engine_clock, - .set_engine_clock = &radeon_atom_set_engine_clock, - .get_memory_clock = &radeon_atom_get_memory_clock, - .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = NULL, - .set_pcie_lanes = NULL, - .set_clock_gating = &radeon_atom_set_clock_gating, - .set_surface_reg = r100_set_surface_reg, - .clear_surface_reg = r100_clear_surface_reg, - .bandwidth_update = &rs600_bandwidth_update, - .hpd_init = &rs600_hpd_init, - .hpd_fini = &rs600_hpd_fini, - .hpd_sense = &rs600_hpd_sense, - .hpd_set_polarity = &rs600_hpd_set_polarity, - .ioctl_wait_idle = NULL, -}; - - /* * rs690,rs740 */ @@ -428,44 +162,6 @@ int rs690_suspend(struct radeon_device *rdev); uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rs690_bandwidth_update(struct radeon_device *rdev); -static struct radeon_asic rs690_asic = { - .init = &rs690_init, - .fini = &rs690_fini, - .suspend = &rs690_suspend, - .resume = &rs690_resume, - .vga_set_state = &r100_vga_set_state, - .gpu_reset = &r300_gpu_reset, - .gart_tlb_flush = &rs400_gart_tlb_flush, - .gart_set_page = &rs400_gart_set_page, - .cp_commit = &r100_cp_commit, - .ring_start = &r300_ring_start, - .ring_test = &r100_ring_test, - .ring_ib_execute = &r100_ring_ib_execute, - .irq_set = &rs600_irq_set, - .irq_process = &rs600_irq_process, - .get_vblank_counter = &rs600_get_vblank_counter, - .fence_ring_emit = &r300_fence_ring_emit, - .cs_parse = &r300_cs_parse, - .copy_blit = &r100_copy_blit, - .copy_dma = &r200_copy_dma, - .copy = &r200_copy_dma, - .get_engine_clock = &radeon_atom_get_engine_clock, - .set_engine_clock = &radeon_atom_set_engine_clock, - .get_memory_clock = &radeon_atom_get_memory_clock, - .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = NULL, - .set_pcie_lanes = NULL, - .set_clock_gating = &radeon_atom_set_clock_gating, - .set_surface_reg = r100_set_surface_reg, - .clear_surface_reg = r100_clear_surface_reg, - .bandwidth_update = &rs690_bandwidth_update, - .hpd_init = &rs600_hpd_init, - .hpd_fini = &rs600_hpd_fini, - .hpd_sense = &rs600_hpd_sense, - .hpd_set_polarity = &rs600_hpd_set_polarity, - .ioctl_wait_idle = NULL, -}; - /* * rv515 @@ -481,87 +177,12 @@ void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rv515_bandwidth_update(struct radeon_device *rdev); int rv515_resume(struct radeon_device *rdev); int rv515_suspend(struct radeon_device *rdev); -static struct radeon_asic rv515_asic = { - .init = &rv515_init, - .fini = &rv515_fini, - .suspend = &rv515_suspend, - .resume = &rv515_resume, - .vga_set_state = &r100_vga_set_state, - .gpu_reset = &rv515_gpu_reset, - .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, - .gart_set_page = &rv370_pcie_gart_set_page, - .cp_commit = &r100_cp_commit, - .ring_start = &rv515_ring_start, - .ring_test = &r100_ring_test, - .ring_ib_execute = &r100_ring_ib_execute, - .irq_set = &rs600_irq_set, - .irq_process = &rs600_irq_process, - .get_vblank_counter = &rs600_get_vblank_counter, - .fence_ring_emit = &r300_fence_ring_emit, - .cs_parse = &r300_cs_parse, - .copy_blit = &r100_copy_blit, - .copy_dma = &r200_copy_dma, - .copy = &r100_copy_blit, - .get_engine_clock = &radeon_atom_get_engine_clock, - .set_engine_clock = &radeon_atom_set_engine_clock, - .get_memory_clock = &radeon_atom_get_memory_clock, - .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = &rv370_get_pcie_lanes, - .set_pcie_lanes = &rv370_set_pcie_lanes, - .set_clock_gating = &radeon_atom_set_clock_gating, - .set_surface_reg = r100_set_surface_reg, - .clear_surface_reg = r100_clear_surface_reg, - .bandwidth_update = &rv515_bandwidth_update, - .hpd_init = &rs600_hpd_init, - .hpd_fini = &rs600_hpd_fini, - .hpd_sense = &rs600_hpd_sense, - .hpd_set_polarity = &rs600_hpd_set_polarity, - .ioctl_wait_idle = NULL, -}; - /* * r520,rv530,rv560,rv570,r580 */ int r520_init(struct radeon_device *rdev); int r520_resume(struct radeon_device *rdev); -static struct radeon_asic r520_asic = { - .init = &r520_init, - .fini = &rv515_fini, - .suspend = &rv515_suspend, - .resume = &r520_resume, - .vga_set_state = &r100_vga_set_state, - .gpu_reset = &rv515_gpu_reset, - .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, - .gart_set_page = &rv370_pcie_gart_set_page, - .cp_commit = &r100_cp_commit, - .ring_start = &rv515_ring_start, - .ring_test = &r100_ring_test, - .ring_ib_execute = &r100_ring_ib_execute, - .irq_set = &rs600_irq_set, - .irq_process = &rs600_irq_process, - .get_vblank_counter = &rs600_get_vblank_counter, - .fence_ring_emit = &r300_fence_ring_emit, - .cs_parse = &r300_cs_parse, - .copy_blit = &r100_copy_blit, - .copy_dma = &r200_copy_dma, - .copy = &r100_copy_blit, - .get_engine_clock = &radeon_atom_get_engine_clock, - .set_engine_clock = &radeon_atom_set_engine_clock, - .get_memory_clock = &radeon_atom_get_memory_clock, - .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = &rv370_get_pcie_lanes, - .set_pcie_lanes = &rv370_set_pcie_lanes, - .set_clock_gating = &radeon_atom_set_clock_gating, - .set_surface_reg = r100_set_surface_reg, - .clear_surface_reg = r100_clear_surface_reg, - .bandwidth_update = &rv515_bandwidth_update, - .hpd_init = &rs600_hpd_init, - .hpd_fini = &rs600_hpd_fini, - .hpd_sense = &rs600_hpd_sense, - .hpd_set_polarity = &rs600_hpd_set_polarity, - .ioctl_wait_idle = NULL, -}; /* * r600,rv610,rv630,rv620,rv635,rv670,rs780,rs880 @@ -604,43 +225,6 @@ void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); -static struct radeon_asic r600_asic = { - .init = &r600_init, - .fini = &r600_fini, - .suspend = &r600_suspend, - .resume = &r600_resume, - .cp_commit = &r600_cp_commit, - .vga_set_state = &r600_vga_set_state, - .gpu_reset = &r600_gpu_reset, - .gart_tlb_flush = &r600_pcie_gart_tlb_flush, - .gart_set_page = &rs600_gart_set_page, - .ring_test = &r600_ring_test, - .ring_ib_execute = &r600_ring_ib_execute, - .irq_set = &r600_irq_set, - .irq_process = &r600_irq_process, - .get_vblank_counter = &rs600_get_vblank_counter, - .fence_ring_emit = &r600_fence_ring_emit, - .cs_parse = &r600_cs_parse, - .copy_blit = &r600_copy_blit, - .copy_dma = &r600_copy_blit, - .copy = &r600_copy_blit, - .get_engine_clock = &radeon_atom_get_engine_clock, - .set_engine_clock = &radeon_atom_set_engine_clock, - .get_memory_clock = &radeon_atom_get_memory_clock, - .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = &rv370_get_pcie_lanes, - .set_pcie_lanes = NULL, - .set_clock_gating = NULL, - .set_surface_reg = r600_set_surface_reg, - .clear_surface_reg = r600_clear_surface_reg, - .bandwidth_update = &rv515_bandwidth_update, - .hpd_init = &r600_hpd_init, - .hpd_fini = &r600_hpd_fini, - .hpd_sense = &r600_hpd_sense, - .hpd_set_polarity = &r600_hpd_set_polarity, - .ioctl_wait_idle = r600_ioctl_wait_idle, -}; - /* * rv770,rv730,rv710,rv740 */ @@ -650,43 +234,6 @@ int rv770_suspend(struct radeon_device *rdev); int rv770_resume(struct radeon_device *rdev); int rv770_gpu_reset(struct radeon_device *rdev); -static struct radeon_asic rv770_asic = { - .init = &rv770_init, - .fini = &rv770_fini, - .suspend = &rv770_suspend, - .resume = &rv770_resume, - .cp_commit = &r600_cp_commit, - .gpu_reset = &rv770_gpu_reset, - .vga_set_state = &r600_vga_set_state, - .gart_tlb_flush = &r600_pcie_gart_tlb_flush, - .gart_set_page = &rs600_gart_set_page, - .ring_test = &r600_ring_test, - .ring_ib_execute = &r600_ring_ib_execute, - .irq_set = &r600_irq_set, - .irq_process = &r600_irq_process, - .get_vblank_counter = &rs600_get_vblank_counter, - .fence_ring_emit = &r600_fence_ring_emit, - .cs_parse = &r600_cs_parse, - .copy_blit = &r600_copy_blit, - .copy_dma = &r600_copy_blit, - .copy = &r600_copy_blit, - .get_engine_clock = &radeon_atom_get_engine_clock, - .set_engine_clock = &radeon_atom_set_engine_clock, - .get_memory_clock = &radeon_atom_get_memory_clock, - .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = &rv370_get_pcie_lanes, - .set_pcie_lanes = NULL, - .set_clock_gating = &radeon_atom_set_clock_gating, - .set_surface_reg = r600_set_surface_reg, - .clear_surface_reg = r600_clear_surface_reg, - .bandwidth_update = &rv515_bandwidth_update, - .hpd_init = &r600_hpd_init, - .hpd_fini = &r600_hpd_fini, - .hpd_sense = &r600_hpd_sense, - .hpd_set_polarity = &r600_hpd_set_polarity, - .ioctl_wait_idle = r600_ioctl_wait_idle, -}; - /* * evergreen */ @@ -701,40 +248,4 @@ void evergreen_hpd_fini(struct radeon_device *rdev); bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void evergreen_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); - -static struct radeon_asic evergreen_asic = { - .init = &evergreen_init, - .fini = &evergreen_fini, - .suspend = &evergreen_suspend, - .resume = &evergreen_resume, - .cp_commit = NULL, - .gpu_reset = &evergreen_gpu_reset, - .vga_set_state = &r600_vga_set_state, - .gart_tlb_flush = &r600_pcie_gart_tlb_flush, - .gart_set_page = &rs600_gart_set_page, - .ring_test = NULL, - .ring_ib_execute = NULL, - .irq_set = NULL, - .irq_process = NULL, - .get_vblank_counter = NULL, - .fence_ring_emit = NULL, - .cs_parse = NULL, - .copy_blit = NULL, - .copy_dma = NULL, - .copy = NULL, - .get_engine_clock = &radeon_atom_get_engine_clock, - .set_engine_clock = &radeon_atom_set_engine_clock, - .get_memory_clock = &radeon_atom_get_memory_clock, - .set_memory_clock = &radeon_atom_set_memory_clock, - .set_pcie_lanes = NULL, - .set_clock_gating = NULL, - .set_surface_reg = r600_set_surface_reg, - .clear_surface_reg = r600_clear_surface_reg, - .bandwidth_update = &evergreen_bandwidth_update, - .hpd_init = &evergreen_hpd_init, - .hpd_fini = &evergreen_hpd_fini, - .hpd_sense = &evergreen_hpd_sense, - .hpd_set_polarity = &evergreen_hpd_set_polarity, -}; - #endif From 9479c54f0dfa63dad1ecfca897f51693c7c2fa65 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Mar 2010 21:19:16 +0000 Subject: [PATCH 046/478] drm/radeon: unconfuse return value of radeon_asic->clear_surface_reg No one cares about it, so set it to void. Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 2 +- drivers/gpu/drm/radeon/radeon_asic.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 67f3c576ab7..a8552eec064 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -783,7 +783,7 @@ struct radeon_asic { int (*set_surface_reg)(struct radeon_device *rdev, int reg, uint32_t tiling_flags, uint32_t pitch, uint32_t offset, uint32_t obj_size); - int (*clear_surface_reg)(struct radeon_device *rdev, int reg); + void (*clear_surface_reg)(struct radeon_device *rdev, int reg); void (*bandwidth_update)(struct radeon_device *rdev); void (*hpd_init)(struct radeon_device *rdev); void (*hpd_fini)(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 2bc26232dc9..4c0d3dab794 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -73,7 +73,7 @@ int r100_copy_blit(struct radeon_device *rdev, int r100_set_surface_reg(struct radeon_device *rdev, int reg, uint32_t tiling_flags, uint32_t pitch, uint32_t offset, uint32_t obj_size); -int r100_clear_surface_reg(struct radeon_device *rdev, int reg); +void r100_clear_surface_reg(struct radeon_device *rdev, int reg); void r100_bandwidth_update(struct radeon_device *rdev); void r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int r100_ring_test(struct radeon_device *rdev); @@ -212,7 +212,7 @@ int r600_gpu_reset(struct radeon_device *rdev); int r600_set_surface_reg(struct radeon_device *rdev, int reg, uint32_t tiling_flags, uint32_t pitch, uint32_t offset, uint32_t obj_size); -int r600_clear_surface_reg(struct radeon_device *rdev, int reg); +void r600_clear_surface_reg(struct radeon_device *rdev, int reg); void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int r600_ring_test(struct radeon_device *rdev); int r600_copy_blit(struct radeon_device *rdev, From e6990375ef4ec449994991034238f1ffab8a3a1a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Mar 2010 21:19:17 +0000 Subject: [PATCH 047/478] drm/radeon: include radeon_asic.h in the asic specific files In essence this creates a home for all asic specific declarations in radeon_asic.h Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 1 + drivers/gpu/drm/radeon/r100.c | 1 + drivers/gpu/drm/radeon/r200.c | 1 + drivers/gpu/drm/radeon/r300.c | 1 + drivers/gpu/drm/radeon/r420.c | 1 + drivers/gpu/drm/radeon/r520.c | 1 + drivers/gpu/drm/radeon/r600.c | 1 + drivers/gpu/drm/radeon/rs400.c | 1 + drivers/gpu/drm/radeon/rs600.c | 1 + drivers/gpu/drm/radeon/rs690.c | 1 + drivers/gpu/drm/radeon/rv515.c | 1 + drivers/gpu/drm/radeon/rv770.c | 1 + 12 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index bd2e7aa85c1..9d6283e26e8 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -25,6 +25,7 @@ #include #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "radeon_drm.h" #include "rv770d.h" #include "atom.h" diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 73f9a79ed64..ea5ebfefd5e 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -31,6 +31,7 @@ #include "radeon_drm.h" #include "radeon_reg.h" #include "radeon.h" +#include "radeon_asic.h" #include "r100d.h" #include "rs100d.h" #include "rv200d.h" diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c index 1146c9909c2..85617c31121 100644 --- a/drivers/gpu/drm/radeon/r200.c +++ b/drivers/gpu/drm/radeon/r200.c @@ -30,6 +30,7 @@ #include "radeon_drm.h" #include "radeon_reg.h" #include "radeon.h" +#include "radeon_asic.h" #include "r100d.h" #include "r200_reg_safe.h" diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 4cef90cd74e..1042cead4a6 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -30,6 +30,7 @@ #include "drm.h" #include "radeon_reg.h" #include "radeon.h" +#include "radeon_asic.h" #include "radeon_drm.h" #include "r100_track.h" #include "r300d.h" diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index c7593b8f58e..2ab35ff41ec 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -29,6 +29,7 @@ #include "drmP.h" #include "radeon_reg.h" #include "radeon.h" +#include "radeon_asic.h" #include "atom.h" #include "r100d.h" #include "r420d.h" diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 2b8a5dd1351..f6d8541ebb9 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -27,6 +27,7 @@ */ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "atom.h" #include "r520d.h" diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 5b56a1b3902..5b00d5e86b8 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -31,6 +31,7 @@ #include "drmP.h" #include "radeon_drm.h" #include "radeon.h" +#include "radeon_asic.h" #include "radeon_mode.h" #include "r600d.h" #include "atom.h" diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 626d51891ee..1240e7d9f77 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -28,6 +28,7 @@ #include #include #include "radeon.h" +#include "radeon_asic.h" #include "rs400d.h" /* This files gather functions specifics to : rs400,rs480 */ diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index ac7c27adfb7..e3410c90bd3 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -37,6 +37,7 @@ */ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "atom.h" #include "rs600d.h" diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 83b9174f76f..c39cb50377f 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -27,6 +27,7 @@ */ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "atom.h" #include "rs690d.h" diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index bea747da123..26108b49e98 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -29,6 +29,7 @@ #include "drmP.h" #include "rv515d.h" #include "radeon.h" +#include "radeon_asic.h" #include "atom.h" #include "rv515_reg_safe.h" diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 8f0c9253c5b..1484d06aad6 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -29,6 +29,7 @@ #include #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "radeon_drm.h" #include "rv770d.h" #include "atom.h" From 2b497502b7cef167288a08737403a5a6cec697f0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Mar 2010 21:19:18 +0000 Subject: [PATCH 048/478] drm/radeon: collect r100 asic related declarations in radeon_asic.h This just an example to show what radeon_asic.h might be good for. Before Jerome kills it ;) Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 47 ------------------------- drivers/gpu/drm/radeon/radeon_asic.h | 52 +++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a8552eec064..bd63f537070 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -730,8 +730,6 @@ int radeon_debugfs_add_files(struct radeon_device *rdev, struct drm_info_list *files, unsigned nfiles); int radeon_debugfs_fence_init(struct radeon_device *rdev); -int r100_debugfs_rbbm_init(struct radeon_device *rdev); -int r100_debugfs_cp_init(struct radeon_device *rdev); /* @@ -1195,51 +1193,6 @@ extern int radeon_resume_kms(struct drm_device *dev); extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state); /* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ -struct r100_mc_save { - u32 GENMO_WT; - u32 CRTC_EXT_CNTL; - u32 CRTC_GEN_CNTL; - u32 CRTC2_GEN_CNTL; - u32 CUR_OFFSET; - u32 CUR2_OFFSET; -}; -extern void r100_cp_disable(struct radeon_device *rdev); -extern int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); -extern void r100_cp_fini(struct radeon_device *rdev); -extern void r100_pci_gart_tlb_flush(struct radeon_device *rdev); -extern int r100_pci_gart_init(struct radeon_device *rdev); -extern void r100_pci_gart_fini(struct radeon_device *rdev); -extern int r100_pci_gart_enable(struct radeon_device *rdev); -extern void r100_pci_gart_disable(struct radeon_device *rdev); -extern int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); -extern int r100_debugfs_mc_info_init(struct radeon_device *rdev); -extern int r100_gui_wait_for_idle(struct radeon_device *rdev); -extern void r100_ib_fini(struct radeon_device *rdev); -extern int r100_ib_init(struct radeon_device *rdev); -extern void r100_irq_disable(struct radeon_device *rdev); -extern int r100_irq_set(struct radeon_device *rdev); -extern void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save); -extern void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save); -extern void r100_vram_init_sizes(struct radeon_device *rdev); -extern void r100_wb_disable(struct radeon_device *rdev); -extern void r100_wb_fini(struct radeon_device *rdev); -extern int r100_wb_init(struct radeon_device *rdev); -extern void r100_hdp_reset(struct radeon_device *rdev); -extern int r100_rb2d_reset(struct radeon_device *rdev); -extern int r100_cp_reset(struct radeon_device *rdev); -extern void r100_vga_render_disable(struct radeon_device *rdev); -extern int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, - struct radeon_cs_packet *pkt, - struct radeon_bo *robj); -extern int r100_cs_parse_packet0(struct radeon_cs_parser *p, - struct radeon_cs_packet *pkt, - const unsigned *auth, unsigned n, - radeon_packet0_check_t check); -extern int r100_cs_packet_parse(struct radeon_cs_parser *p, - struct radeon_cs_packet *pkt, - unsigned idx); -extern void r100_enable_bm(struct radeon_device *rdev); -extern void r100_set_common_regs(struct radeon_device *rdev); /* rv200,rv250,rv280 */ extern void r200_set_safe_registers(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 4c0d3dab794..a0b8280663d 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -45,10 +45,18 @@ void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); /* * r100,rv100,rs100,rv200,rs200 */ -extern int r100_init(struct radeon_device *rdev); -extern void r100_fini(struct radeon_device *rdev); -extern int r100_suspend(struct radeon_device *rdev); -extern int r100_resume(struct radeon_device *rdev); +struct r100_mc_save { + u32 GENMO_WT; + u32 CRTC_EXT_CNTL; + u32 CRTC_GEN_CNTL; + u32 CRTC2_GEN_CNTL; + u32 CUR_OFFSET; + u32 CUR2_OFFSET; +}; +int r100_init(struct radeon_device *rdev); +void r100_fini(struct radeon_device *rdev); +int r100_suspend(struct radeon_device *rdev); +int r100_resume(struct radeon_device *rdev); uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg); void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void r100_vga_set_state(struct radeon_device *rdev, bool state); @@ -82,6 +90,42 @@ void r100_hpd_fini(struct radeon_device *rdev); bool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void r100_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); +int r100_debugfs_rbbm_init(struct radeon_device *rdev); +int r100_debugfs_cp_init(struct radeon_device *rdev); +void r100_cp_disable(struct radeon_device *rdev); +int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); +void r100_cp_fini(struct radeon_device *rdev); +int r100_pci_gart_init(struct radeon_device *rdev); +void r100_pci_gart_fini(struct radeon_device *rdev); +int r100_pci_gart_enable(struct radeon_device *rdev); +void r100_pci_gart_disable(struct radeon_device *rdev); +int r100_debugfs_mc_info_init(struct radeon_device *rdev); +int r100_gui_wait_for_idle(struct radeon_device *rdev); +void r100_ib_fini(struct radeon_device *rdev); +int r100_ib_init(struct radeon_device *rdev); +void r100_irq_disable(struct radeon_device *rdev); +void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save); +void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save); +void r100_vram_init_sizes(struct radeon_device *rdev); +void r100_wb_disable(struct radeon_device *rdev); +void r100_wb_fini(struct radeon_device *rdev); +int r100_wb_init(struct radeon_device *rdev); +void r100_hdp_reset(struct radeon_device *rdev); +int r100_rb2d_reset(struct radeon_device *rdev); +int r100_cp_reset(struct radeon_device *rdev); +void r100_vga_render_disable(struct radeon_device *rdev); +int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + struct radeon_bo *robj); +int r100_cs_parse_packet0(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + const unsigned *auth, unsigned n, + radeon_packet0_check_t check); +int r100_cs_packet_parse(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx); +void r100_enable_bm(struct radeon_device *rdev); +void r100_set_common_regs(struct radeon_device *rdev); /* * r200,rv250,rs300,rv280 From cd3d8031eb4311e516329aee03c79a08333141f1 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Fri, 12 Mar 2010 16:15:36 +0900 Subject: [PATCH 049/478] sched: sched_getaffinity(): Allow less than NR_CPUS length [ Note, this commit changes the syscall ABI for > 1024 CPUs systems. ] Recently, some distro decided to use NR_CPUS=4096 for mysterious reasons. Unfortunately, glibc sched interface has the following definition: # define __CPU_SETSIZE 1024 # define __NCPUBITS (8 * sizeof (__cpu_mask)) typedef unsigned long int __cpu_mask; typedef struct { __cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS]; } cpu_set_t; It mean, if NR_CPUS is bigger than 1024, cpu_set_t makes an ABI issue ... More recently, Sharyathi Nagesh reported following test program makes misterious syscall failure: ----------------------------------------------------------------------- #define _GNU_SOURCE #include #include #include int main() { cpu_set_t set; if (sched_getaffinity(0, sizeof(cpu_set_t), &set) < 0) printf("\n Call is failing with:%d", errno); } ----------------------------------------------------------------------- Because the kernel assumes len argument of sched_getaffinity() is bigger than NR_CPUS. But now it is not correct. Now we are faced with the following annoying dilemma, due to the limitations of the glibc interface built in years ago: (1) if we change glibc's __CPU_SETSIZE definition, we lost binary compatibility of _all_ application. (2) if we don't change it, we also lost binary compatibility of Sharyathi's use case. Then, I would propse to change the rule of the len argument of sched_getaffinity(). Old: len should be bigger than NR_CPUS New: len should be bigger than maximum possible cpu id This creates the following behavior: (A) In the real 4096 cpus machine, the above test program still return -EINVAL. (B) NR_CPUS=4096 but the machine have less than 1024 cpus (almost all machines in the world), the above can run successfully. Fortunatelly, BIG SGI machine is mainly used for HPC use case. It means they can rebuild their programs. IOW we hope they are not annoyed by this issue ... Reported-by: Sharyathi Nagesh Signed-off-by: KOSAKI Motohiro Acked-by: Ulrich Drepper Acked-by: Peter Zijlstra Cc: Linus Torvalds Cc: Andrew Morton Cc: Jack Steiner Cc: Russ Anderson Cc: Mike Travis LKML-Reference: <20100312161316.9520.A69D9226@jp.fujitsu.com> Signed-off-by: Ingo Molnar --- kernel/sched.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 9ab3cd7858d..6eaef3df2d1 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4902,7 +4902,9 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len, int ret; cpumask_var_t mask; - if (len < cpumask_size()) + if (len < nr_cpu_ids) + return -EINVAL; + if (len & (sizeof(unsigned long)-1)) return -EINVAL; if (!alloc_cpumask_var(&mask, GFP_KERNEL)) @@ -4910,10 +4912,12 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len, ret = sched_getaffinity(pid, mask); if (ret == 0) { - if (copy_to_user(user_mask_ptr, mask, cpumask_size())) + int retlen = min(len, cpumask_size()); + + if (copy_to_user(user_mask_ptr, mask, retlen)) ret = -EFAULT; else - ret = cpumask_size(); + ret = retlen; } free_cpumask_var(mask); From ce619e1fb86d68f125e0e6d10a5484f67a6d97b3 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 12 Mar 2010 12:46:05 +0200 Subject: [PATCH 050/478] OMAP: DSS2: initialize dss clk sources properly Clk sources were not initialized, leading to kernel crash, or possibly to strange behaviour if DSI was compiled in. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 8254a4232a5..54344184dd7 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -590,6 +590,9 @@ int dss_init(bool skip_init) } } + dss.dsi_clk_source = DSS_SRC_DSS1_ALWON_FCLK; + dss.dispc_clk_source = DSS_SRC_DSS1_ALWON_FCLK; + dss_save_context(); rev = dss_read_reg(DSS_REVISION); From 8871d54b5e1558bd59baad02eb7a80f86d49f4a1 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 4 Mar 2010 17:52:43 +0200 Subject: [PATCH 051/478] OMAP: DSS2: panel-generic: re-implement mode changing Mode changing code was left out with the DSS driver remodeling. Add the code back. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-generic.c | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c index c59e4baed8b..300eff5de1b 100644 --- a/drivers/video/omap2/displays/panel-generic.c +++ b/drivers/video/omap2/displays/panel-generic.c @@ -116,6 +116,24 @@ static int generic_panel_resume(struct omap_dss_device *dssdev) return 0; } +static void generic_panel_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + dpi_set_timings(dssdev, timings); +} + +static void generic_panel_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + *timings = dssdev->panel.timings; +} + +static int generic_panel_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + return dpi_check_timings(dssdev, timings); +} + static struct omap_dss_driver generic_driver = { .probe = generic_panel_probe, .remove = generic_panel_remove, @@ -125,6 +143,10 @@ static struct omap_dss_driver generic_driver = { .suspend = generic_panel_suspend, .resume = generic_panel_resume, + .set_timings = generic_panel_set_timings, + .get_timings = generic_panel_get_timings, + .check_timings = generic_panel_check_timings, + .driver = { .name = "generic_panel", .owner = THIS_MODULE, From cf36df6bfb49fd265a39f676bfc9718029fef160 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 15 Mar 2010 13:20:32 +0100 Subject: [PATCH 052/478] firewire: core: fw_iso_resource_manage: fix error handling If the bandwidth allocation fails, the error must be returned in *channel regardless of whether the channel allocation succeeded. Checking for c >= 0 is not correct if no channel allocation was requested, in which case this part of the code is reached with c == -EINVAL. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/core-iso.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 1c0b504a42f..99c20f1b613 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -331,8 +331,9 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, if (ret < 0) *bandwidth = 0; - if (allocate && ret < 0 && c >= 0) { - deallocate_channel(card, irm_id, generation, c, buffer); + if (allocate && ret < 0) { + if (c >= 0) + deallocate_channel(card, irm_id, generation, c, buffer); *channel = ret; } } From 36e9e1eab777e077f7484d309ff676d0568e27d1 Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Mon, 15 Mar 2010 14:33:06 -0800 Subject: [PATCH 053/478] x86: Handle legacy PIC interrupts on all the cpu's Ingo Molnar reported that with the recent changes of not statically blocking IRQ0_VECTOR..IRQ15_VECTOR's on all the cpu's, broke an AMD platform (with Nvidia chipset) boot when "noapic" boot option is used. On this platform, legacy PIC interrupts are getting delivered to all the cpu's instead of just the boot cpu. Thus not initializing the vector to irq mapping for the legacy irq's resulted in not handling certain interrupts causing boot hang. Fix this by initializing the vector to irq mapping on all the logical cpu's, if the legacy IRQ is handled by the legacy PIC. Reported-by: Ingo Molnar Signed-off-by: Suresh Siddha [ -v2: io-apic-enabled improvement ] Acked-by: Yinghai Lu Cc: Eric W. Biederman LKML-Reference: <1268692386.3296.43.camel@sbs-t61.sc.intel.com> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/hw_irq.h | 1 + arch/x86/kernel/apic/io_apic.c | 8 ++++++++ arch/x86/kernel/irqinit.c | 22 ++++++++++++++++++++++ arch/x86/kernel/smpboot.c | 2 +- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index a929c9ede33..46c0fe05f23 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -133,6 +133,7 @@ extern void (*__initconst interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void); typedef int vector_irq_t[NR_VECTORS]; DECLARE_PER_CPU(vector_irq_t, vector_irq); +extern void setup_vector_irq(int cpu); #ifdef CONFIG_X86_IO_APIC extern void lock_vector_lock(void); diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index e4e0ddcb154..463de9a858a 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1268,6 +1268,14 @@ void __setup_vector_irq(int cpu) /* Mark the inuse vectors */ for_each_irq_desc(irq, desc) { cfg = desc->chip_data; + + /* + * If it is a legacy IRQ handled by the legacy PIC, this cpu + * will be part of the irq_cfg's domain. + */ + if (irq < legacy_pic->nr_legacy_irqs && !IO_APIC_IRQ(irq)) + cpumask_set_cpu(cpu, cfg->domain); + if (!cpumask_test_cpu(cpu, cfg->domain)) continue; vector = cfg->vector; diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index ef257fc2921..f01d390f9c5 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c @@ -141,6 +141,28 @@ void __init init_IRQ(void) x86_init.irqs.intr_init(); } +/* + * Setup the vector to irq mappings. + */ +void setup_vector_irq(int cpu) +{ +#ifndef CONFIG_X86_IO_APIC + int irq; + + /* + * On most of the platforms, legacy PIC delivers the interrupts on the + * boot cpu. But there are certain platforms where PIC interrupts are + * delivered to multiple cpu's. If the legacy IRQ is handled by the + * legacy PIC, for the new cpu that is coming online, setup the static + * legacy vector to irq mapping: + */ + for (irq = 0; irq < legacy_pic->nr_legacy_irqs; irq++) + per_cpu(vector_irq, cpu)[IRQ0_VECTOR + irq] = irq; +#endif + + __setup_vector_irq(cpu); +} + static void __init smp_intr_init(void) { #ifdef CONFIG_SMP diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index a02e80c3c54..06d98ae5a80 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -247,7 +247,7 @@ static void __cpuinit smp_callin(void) /* * Need to setup vector mappings before we enable interrupts. */ - __setup_vector_irq(smp_processor_id()); + setup_vector_irq(smp_processor_id()); /* * Get our bogomips. * From e3818b8dce2a934cd1521dbc4827e5238d8f45d8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 15 Mar 2010 17:03:43 -0700 Subject: [PATCH 054/478] rcu: Make rcu_read_lock_bh_held() allow for disabled BH Disabling BH can stand in for rcu_read_lock_bh(), and this patch updates rcu_read_lock_bh_held() to allow for this. In order to avoid include-file hell, this function is moved out of line to kernel/rcupdate.c. This fixes a false positive RCU warning. Reported-by: Arnd Bergmann Reported-by: Eric Dumazet Signed-off-by: Paul E. McKenney Acked-by: Lai Jiangshan Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <20100316000343.GA25857@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar --- include/linux/rcupdate.h | 19 ++++--------------- kernel/rcupdate.c | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 3024050c82a..e1bdc4bfd27 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -123,22 +123,11 @@ static inline int rcu_read_lock_held(void) return lock_is_held(&rcu_lock_map); } -/** - * rcu_read_lock_bh_held - might we be in RCU-bh read-side critical section? - * - * If CONFIG_PROVE_LOCKING is selected and enabled, returns nonzero iff in - * an RCU-bh read-side critical section. In absence of CONFIG_PROVE_LOCKING, - * this assumes we are in an RCU-bh read-side critical section unless it can - * prove otherwise. - * - * Check rcu_scheduler_active to prevent false positives during boot. +/* + * rcu_read_lock_bh_held() is defined out of line to avoid #include-file + * hell. */ -static inline int rcu_read_lock_bh_held(void) -{ - if (!debug_lockdep_rcu_enabled()) - return 1; - return lock_is_held(&rcu_bh_lock_map); -} +extern int rcu_read_lock_bh_held(void); /** * rcu_read_lock_sched_held - might we be in RCU-sched read-side critical section? diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index f1125c1a632..63fe2543398 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -45,6 +45,7 @@ #include #include #include +#include #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key rcu_lock_key; @@ -66,6 +67,28 @@ EXPORT_SYMBOL_GPL(rcu_sched_lock_map); int rcu_scheduler_active __read_mostly; EXPORT_SYMBOL_GPL(rcu_scheduler_active); +#ifdef CONFIG_DEBUG_LOCK_ALLOC + +/** + * rcu_read_lock_bh_held - might we be in RCU-bh read-side critical section? + * + * Check for bottom half being disabled, which covers both the + * CONFIG_PROVE_RCU and not cases. Note that if someone uses + * rcu_read_lock_bh(), but then later enables BH, lockdep (if enabled) + * will show the situation. + * + * Check debug_lockdep_rcu_enabled() to prevent false positives during boot. + */ +int rcu_read_lock_bh_held(void) +{ + if (!debug_lockdep_rcu_enabled()) + return 1; + return in_softirq(); +} +EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held); + +#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ + /* * This function is invoked towards the end of the scheduler's initialization * process. Before this is called, the idle task might contain From 7f5b774275df8c76a959eae7488128b637fcbfc8 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 16 Mar 2010 17:00:29 +0800 Subject: [PATCH 055/478] rcu: Fix tracepoints & lockdep false positive tracepoint.h uses rcu_dereference(), which triggers this warning: [ 0.701161] =================================================== [ 0.702211] [ INFO: suspicious rcu_dereference_check() usage. ] [ 0.702716] --------------------------------------------------- [ 0.703203] include/trace/events/workqueue.h:68 invoked rcu_dereference_check() without protection! [ 0.703971] [ 0.703990] other info that might help us debug this: [ 0.703993] [ 0.705590] [ 0.705604] rcu_scheduler_active = 1, debug_locks = 0 [ 0.706712] 1 lock held by swapper/1: [ 0.707229] #0: (cpu_add_remove_lock){+.+.+.}, at: [] cpu_maps_update_begin+0x14/0x20 [ 0.710097] [ 0.710106] stack backtrace: [ 0.712602] Pid: 1, comm: swapper Not tainted 2.6.34-rc1-tip-01613-g72662bb #168 [ 0.713231] Call Trace: [ 0.713997] [] lockdep_rcu_dereference+0x9d/0xb0 [ 0.714746] [] create_workqueue_thread+0x107/0x110 [ 0.715353] [] ? worker_thread+0x0/0x340 [ 0.715845] [] __create_workqueue_key+0x138/0x240 [ 0.716427] [] ? cpu_maps_update_done+0x12/0x20 [ 0.717012] [] init_workqueues+0x6f/0x80 [ 0.717530] [] kernel_init+0x102/0x1f0 [ 0.717570] [] ? kernel_init+0x0/0x1f0 [ 0.718944] [] kernel_thread_helper+0x6/0x10 Signed-off-by: Lai Jiangshan Cc: Paul E. McKenney Cc: Mathieu Desnoyers Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4B9F48AD.4000404@cn.fujitsu.com> Signed-off-by: Ingo Molnar --- include/linux/tracepoint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index f59604ed0ec..78b4bd3be49 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -49,7 +49,7 @@ struct tracepoint { void **it_func; \ \ rcu_read_lock_sched_notrace(); \ - it_func = rcu_dereference((tp)->funcs); \ + it_func = rcu_dereference_sched((tp)->funcs); \ if (it_func) { \ do { \ ((void(*)(proto))(*it_func))(args); \ From c890692bf37671b5b78a1870d55d6d87e1c8a509 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 11 Mar 2010 14:08:43 -0800 Subject: [PATCH 056/478] kernel/sched.c: Suppress unused var warning On UP: kernel/sched.c: In function 'wake_up_new_task': kernel/sched.c:2631: warning: unused variable 'cpu' Signed-off-by: Andrew Morton Cc: Peter Zijlstra Signed-off-by: Ingo Molnar --- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched.c b/kernel/sched.c index 6eaef3df2d1..82975b5b42f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2650,7 +2650,7 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) { unsigned long flags; struct rq *rq; - int cpu = get_cpu(); + int cpu __maybe_unused = get_cpu(); #ifdef CONFIG_SMP /* From ff30a0543e9a6cd732582063e7cae951cdb7acf2 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 15 Mar 2010 10:11:15 +0000 Subject: [PATCH 057/478] x86: Fix placement of FIX_OHCI1394_BASE Ever for 32-bit with sufficiently high NR_CPUS, and starting with commit 789d03f584484af85dbdc64935270c8e45f36ef7 also for 64-bit, the statically allocated early fixmap page tables were not covering FIX_OHCI1394_BASE, leading to a boot time crash when "ohci1394_dma=early" was used. Despite this entry not being a permanently used one, it needs to be moved into the permanent range since it has to be close to FIX_DBGP_BASE and FIX_EARLYCON_MEM_BASE. Reported-bisected-and-tested-by: Justin P. Mattock Fixes-bug: http://bugzilla.kernel.org/show_bug.cgi?id=14487 Signed-off-by: Jan Beulich Cc: # [as far back as long as it still applies] LKML-Reference: <4B9E15D30200007800034D23@vpn.id2.novell.com> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/fixmap.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 635f03bb499..d07b44f7d1d 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -82,6 +82,9 @@ enum fixed_addresses { #endif FIX_DBGP_BASE, FIX_EARLYCON_MEM_BASE, +#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT + FIX_OHCI1394_BASE, +#endif #ifdef CONFIG_X86_LOCAL_APIC FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ #endif @@ -132,9 +135,6 @@ enum fixed_addresses { (__end_of_permanent_fixed_addresses & (TOTAL_FIX_BTMAPS - 1)) : __end_of_permanent_fixed_addresses, FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1, -#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT - FIX_OHCI1394_BASE, -#endif #ifdef CONFIG_X86_32 FIX_WP_TEST, #endif From 3f60ebc9d6291863652d564bacc430629271e6a9 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Thu, 11 Mar 2010 17:45:26 +0200 Subject: [PATCH 058/478] wl1251: fix potential crash In case debugfs does not init for some reason (or is disabled on older kernels) driver does not allocate stats.fw_stats structure, but tries to clear it later and trips on a NULL pointer: Unable to handle kernel NULL pointer dereference at virtual address 00000000 PC is at __memzero+0x24/0x80 Backtrace: [] (wl1251_debugfs_reset+0x0/0x30 [wl1251]) [] (wl1251_op_stop+0x0/0x12c [wl1251]) [] (ieee80211_stop_device+0x0/0x74 [mac80211]) [] (ieee80211_stop+0x0/0x4ac [mac80211]) [] (dev_close+0x0/0xb4) [] (dev_change_flags+0x0/0x184) [] (devinet_ioctl+0x0/0x704) [] (inet_ioctl+0x0/0x100) Add a NULL pointer check to fix this. Signed-off-by: Grazvydas Ignotas Acked-by: Kalle Valo Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_debugfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c index 0ccba57fb9f..05e4d68eb4c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -466,7 +466,8 @@ out: void wl1251_debugfs_reset(struct wl1251 *wl) { - memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); + if (wl->stats.fw_stats != NULL) + memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); wl->stats.retry_count = 0; wl->stats.excessive_retries = 0; } From 4fdec031b9169b3c17938b9c4168f099f457169c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 12 Mar 2010 04:02:43 +0100 Subject: [PATCH 059/478] ath9k: fix BUG_ON triggered by PAE frames When I initially stumbled upon sequence number problems with PAE frames in ath9k, I submitted a patch to remove all special cases for PAE frames and let them go through the normal transmit path. Out of concern about crypto incompatibility issues, this change was merged instead: commit 6c8afef551fef87a3bf24f8a74c69a7f2f72fc82 Author: Sujith Date: Tue Feb 9 10:07:00 2010 +0530 ath9k: Fix sequence numbers for PAE frames After a lot of testing, I'm able to reliably trigger a driver crash on rekeying with current versions with this change in place. It seems that the driver does not support sending out regular MPDUs with the same TID while an A-MPDU session is active. This leads to duplicate entries in the TID Tx buffer, which hits the following BUG_ON in ath_tx_addto_baw(): index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno); cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); BUG_ON(tid->tx_buf[cindex] != NULL); I believe until we actually have a reproducible case of an incompatibility with another AP using no PAE special cases, we should simply get rid of this mess. This patch completely fixes my crash issues in STA mode and makes it stay connected without throughput drops or connectivity issues even when the AP is configured to a very short group rekey interval. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b2c8207f7bc..294b486bc3e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1353,25 +1353,6 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) return htype; } -static bool is_pae(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - if (ieee80211_is_data(fc)) { - if (ieee80211_is_nullfunc(fc) || - /* Port Access Entity (IEEE 802.1X) */ - (skb->protocol == cpu_to_be16(ETH_P_PAE))) { - return true; - } - } - - return false; -} - static int get_hw_crypto_keytype(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -1696,7 +1677,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, goto tx_done; } - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && !is_pae(skb)) { + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { /* * Try aggregation if it's a unicast data frame * and the destination is HT capable. From c8406ea8fa1adde8dc5400127281d497bbcdb84a Mon Sep 17 00:00:00 2001 From: Adel Gadllah Date: Sun, 14 Mar 2010 19:16:25 +0100 Subject: [PATCH 060/478] iwlwifi: Silence tfds_in_queue message Commit a239a8b47cc0e5e6d7416a89f340beac06d5edaa introduced a noisy message, that fills up the log very fast. The error seems not to be fatal (the connection is stable and performance is ok), so make it IWL_DEBUG_TX rather than IWL_ERR. Signed-off-by: Adel Gadllah Cc: stable@kernel.org Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 1ed5206721e..8c12311dbb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -124,7 +124,7 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv, if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; else { - IWL_ERR(priv, "free more than tfds_in_queue (%u:%d)\n", + IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n", priv->stations[sta_id].tid[tid].tfds_in_queue, freed); priv->stations[sta_id].tid[tid].tfds_in_queue = 0; From 8bc037fb89bb3104b9ae290d18c877624cd7d9cc Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Wed, 17 Mar 2010 09:36:58 +0900 Subject: [PATCH 061/478] sched: Use proper type in sched_getaffinity() Using the proper type fixes the following compiler warning: kernel/sched.c:4850: warning: comparison of distinct pointer types lacks a cast Signed-off-by: KOSAKI Motohiro Cc: torvalds@linux-foundation.org Cc: travis@sgi.com Cc: peterz@infradead.org Cc: drepper@redhat.com Cc: rja@sgi.com Cc: sharyath@in.ibm.com Cc: steiner@sgi.com LKML-Reference: <20100317090046.4C79.A69D9226@jp.fujitsu.com> Signed-off-by: Ingo Molnar --- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched.c b/kernel/sched.c index 82975b5b42f..49d2fa7b687 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4912,7 +4912,7 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len, ret = sched_getaffinity(pid, mask); if (ret == 0) { - int retlen = min(len, cpumask_size()); + size_t retlen = min_t(size_t, len, cpumask_size()); if (copy_to_user(user_mask_ptr, mask, retlen)) ret = -EFAULT; From 0e255572121180c900e24e33b87047abd8153cce Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 8 Mar 2010 23:24:22 +0200 Subject: [PATCH 062/478] vhost: fix interrupt mitigation with raw sockets A thinko in code means we never trigger interrupt mitigation. Fix this. Reported-by: Juan Quintela Reported-by: Unai Uribarri Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index fcafb6b170f..a6a88dfd502 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -125,7 +125,7 @@ static void handle_tx(struct vhost_net *net) mutex_lock(&vq->mutex); vhost_disable_notify(vq); - if (wmem < sock->sk->sk_sndbuf * 2) + if (wmem < sock->sk->sk_sndbuf / 2) tx_poll_stop(net); hdr_size = vq->hdr_size; From ee860b6a650360c91f5d5f9a94262aad9be90015 Mon Sep 17 00:00:00 2001 From: Sachin Prabhu Date: Wed, 10 Mar 2010 10:28:40 -0500 Subject: [PATCH 063/478] [PATCH] Skip check for mandatory locks when unlocking ocfs2_lock() will skip locks on file which has mode set to 02666. This is a problem in cases where the mode of the file is changed after a process has obtained a lock on the file. ocfs2_lock() should skip the check for mandatory locks when unlocking a file. Signed-off-by: Sachin Prabhu Signed-off-by: Joel Becker --- fs/ocfs2/locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ocfs2/locks.c b/fs/ocfs2/locks.c index 544ac624517..b5cb3ede940 100644 --- a/fs/ocfs2/locks.c +++ b/fs/ocfs2/locks.c @@ -133,7 +133,7 @@ int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl) if (!(fl->fl_flags & FL_POSIX)) return -ENOLCK; - if (__mandatory_lock(inode)) + if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) return -ENOLCK; return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl); From 78c37eb0d5e6a9727b12ea0f1821795ffaa66cfe Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Wed, 3 Mar 2010 11:26:27 +0800 Subject: [PATCH 064/478] ocfs2: Change bg_chain check for ocfs2_validate_gd_parent. In ocfs2_validate_gd_parent, we check bg_chain against the cl_next_free_rec of the dinode. Actually in resize, we have the chance of bg_chain == cl_next_free_rec. So add some additional condition check for it. I also rename paramter "clean_error" to "resize", since the old one is not clearly enough to indicate that we should only meet with this case in resize. btw, the correpsonding bug is http://oss.oracle.com/bugzilla/show_bug.cgi?id=1230. Signed-off-by: Tao Ma Signed-off-by: Joel Becker --- fs/ocfs2/suballoc.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index c3c60bc3e07..0016503d83e 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -152,7 +152,7 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl) #define do_error(fmt, ...) \ do{ \ - if (clean_error) \ + if (resize) \ mlog(ML_ERROR, fmt "\n", ##__VA_ARGS__); \ else \ ocfs2_error(sb, fmt, ##__VA_ARGS__); \ @@ -160,7 +160,7 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl) static int ocfs2_validate_gd_self(struct super_block *sb, struct buffer_head *bh, - int clean_error) + int resize) { struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data; @@ -211,7 +211,7 @@ static int ocfs2_validate_gd_self(struct super_block *sb, static int ocfs2_validate_gd_parent(struct super_block *sb, struct ocfs2_dinode *di, struct buffer_head *bh, - int clean_error) + int resize) { unsigned int max_bits; struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data; @@ -233,8 +233,11 @@ static int ocfs2_validate_gd_parent(struct super_block *sb, return -EINVAL; } - if (le16_to_cpu(gd->bg_chain) >= - le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) { + /* In resize, we may meet the case bg_chain == cl_next_free_rec. */ + if ((le16_to_cpu(gd->bg_chain) > + le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) || + ((le16_to_cpu(gd->bg_chain) == + le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) && !resize)) { do_error("Group descriptor #%llu has bad chain %u", (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_chain)); From 6527f8f848ec84b9daf1cb07601266126b8507ab Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Wed, 10 Mar 2010 09:56:52 +0800 Subject: [PATCH 065/478] ocfs2: Update i_blocks in reflink operations. In reflink, we need to upate i_blocks for the target inode. Reported-by: Jie Liu Signed-off-by: Tao Ma Signed-off-by: Joel Becker --- fs/ocfs2/refcounttree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 9e96921dffd..29405f2ff61 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -4075,6 +4075,7 @@ static int ocfs2_complete_reflink(struct inode *s_inode, OCFS2_I(t_inode)->ip_dyn_features = OCFS2_I(s_inode)->ip_dyn_features; spin_unlock(&OCFS2_I(t_inode)->ip_lock); i_size_write(t_inode, size); + t_inode->i_blocks = s_inode->i_blocks; di->i_xattr_inline_size = s_di->i_xattr_inline_size; di->i_clusters = s_di->i_clusters; From fcefd25ac89239cb57fa198f125a79ff85468c75 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Mon, 15 Mar 2010 15:39:00 -0700 Subject: [PATCH 066/478] ocfs2: set i_mode on disk during acl operations ocfs2_set_acl() and ocfs2_init_acl() were setting i_mode on the in-memory inode, but never setting it on the disk copy. Thus, acls were some times not getting propagated between nodes. This patch fixes the issue by adding a helper function ocfs2_acl_set_mode() which does this the right way. ocfs2_set_acl() and ocfs2_init_acl() are then updated to call ocfs2_acl_set_mode(). Signed-off-by: Mark Fasheh Signed-off-by: Joel Becker --- fs/ocfs2/acl.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index 0501974bedd..8ccf0f8c9cc 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -30,6 +30,8 @@ #include "alloc.h" #include "dlmglue.h" #include "file.h" +#include "inode.h" +#include "journal.h" #include "ocfs2_fs.h" #include "xattr.h" @@ -165,6 +167,60 @@ static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type) return acl; } +/* + * Helper function to set i_mode in memory and disk. Some call paths + * will not have di_bh or a journal handle to pass, in which case it + * will create it's own. + */ +static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh, + handle_t *handle, umode_t new_mode) +{ + int ret, commit_handle = 0; + struct ocfs2_dinode *di; + + if (di_bh == NULL) { + ret = ocfs2_read_inode_block(inode, &di_bh); + if (ret) { + mlog_errno(ret); + goto out; + } + } else + get_bh(di_bh); + + if (handle == NULL) { + handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), + OCFS2_INODE_UPDATE_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + goto out_brelse; + } + + commit_handle = 1; + } + + di = (struct ocfs2_dinode *)di_bh->b_data; + ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + inode->i_mode = new_mode; + di->i_mode = cpu_to_le16(inode->i_mode); + + ocfs2_journal_dirty(handle, di_bh); + +out_commit: + if (commit_handle) + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); +out_brelse: + brelse(di_bh); +out: + return ret; +} + /* * Set the access or default ACL of an inode. */ @@ -193,9 +249,14 @@ static int ocfs2_set_acl(handle_t *handle, if (ret < 0) return ret; else { - inode->i_mode = mode; if (ret == 0) acl = NULL; + + ret = ocfs2_acl_set_mode(inode, di_bh, + handle, mode); + if (ret) + return ret; + } } break; @@ -283,6 +344,7 @@ int ocfs2_init_acl(handle_t *handle, struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct posix_acl *acl = NULL; int ret = 0; + mode_t mode; if (!S_ISLNK(inode->i_mode)) { if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { @@ -291,12 +353,17 @@ int ocfs2_init_acl(handle_t *handle, if (IS_ERR(acl)) return PTR_ERR(acl); } - if (!acl) - inode->i_mode &= ~current_umask(); + if (!acl) { + mode = inode->i_mode & ~current_umask(); + ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); + if (ret) { + mlog_errno(ret); + goto cleanup; + } + } } if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { struct posix_acl *clone; - mode_t mode; if (S_ISDIR(inode->i_mode)) { ret = ocfs2_set_acl(handle, inode, di_bh, @@ -313,7 +380,7 @@ int ocfs2_init_acl(handle_t *handle, mode = inode->i_mode; ret = posix_acl_create_masq(clone, &mode); if (ret >= 0) { - inode->i_mode = mode; + ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); if (ret > 0) { ret = ocfs2_set_acl(handle, inode, di_bh, ACL_TYPE_ACCESS, From f05dd2f09cac422c423dae8f9b8e2be13df05a8f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 26 Feb 2010 13:32:11 -0800 Subject: [PATCH 067/478] drm/i915: Don't bother with the BKL for GEM ioctls. We probably don't need it for most of the other driver ioctls as well, but we explicitly did locking when doing the GEM pieces. On CPU-bound graphics tasks, the BKL was showing up as 1-2% of CPU time. Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_dma.c | 46 ++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8bfc0bbf13e..a9f8589490c 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1881,29 +1881,29 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, 0), - DRM_IOCTL_DEF(DRM_I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_MADVISE, i915_gem_madvise_ioctl, 0), - DRM_IOCTL_DEF(DRM_I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); From 5d9391628e8eb3b0830697697a95bfd0c3c35b9e Mon Sep 17 00:00:00 2001 From: "Owain G. Ainsworth" Date: Wed, 3 Mar 2010 05:34:29 +0000 Subject: [PATCH 068/478] drm/i915: remove an unnecessary wait_request() The continue just after this call with loop around and wait for the request just added just fine. This leads to slightly more compact code. Signed-Off-by: Owain G. Ainsworth Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fba37e9f775..e52a277814c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2227,11 +2227,6 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) seqno = i915_add_request(dev, NULL, obj->write_domain); if (seqno == 0) return -ENOMEM; - - ret = i915_wait_request(dev, seqno); - if (ret) - return ret; - continue; } } From 4967790112b284f276c5065dc724f7340a2fd7a5 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 2 Mar 2010 11:37:00 +0200 Subject: [PATCH 069/478] drm/i915: Rename FBC_C3_IDLE to FBC_CTL_C3_IDLE to match other registers Signed-off-by: Priit Laes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_reg.h | 2 +- drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3d59862c7cc..1fcc4c9efc0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -366,7 +366,7 @@ #define FBC_CTL_PERIODIC (1<<30) #define FBC_CTL_INTERVAL_SHIFT (16) #define FBC_CTL_UNCOMPRESSIBLE (1<<14) -#define FBC_C3_IDLE (1<<13) +#define FBC_CTL_C3_IDLE (1<<13) #define FBC_CTL_STRIDE_SHIFT (5) #define FBC_CTL_FENCENO (1<<0) #define FBC_COMMAND 0x0320c diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9cd6de5f990..0e2c5dafd9d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1032,7 +1032,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) /* enable it... */ fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; if (IS_I945GM(dev)) - fbc_ctl |= FBC_C3_IDLE; /* 945 needs special SR handling */ + fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; if (obj_priv->tiling_mode != I915_TILING_NONE) From 71cf39b117d5aa817a4693f4478397e6b04bee25 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 8 Mar 2010 23:41:55 -0800 Subject: [PATCH 070/478] drm/i915: Enable VS timer dispatch. This could resolve HW deadlocks where a unit downstream of the VS is waiting for more input, the VS has one vertex queued up but not dispatched because it hopes to get one more vertex for 2x4 dispatch, and software isn't handing more vertices down because it's waiting for rendering to complete. The B-Spec says you should always have this bit set. Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 5 +++++ drivers/gpu/drm/i915/i915_reg.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e52a277814c..134973f7706 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4725,6 +4725,11 @@ i915_gem_init_ringbuffer(struct drm_device *dev) ring->space += ring->Size; } + if (IS_I9XX(dev) && !IS_GEN3(dev)) { + I915_WRITE(MI_MODE, + (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH); + } + return 0; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1fcc4c9efc0..2720bc2cd67 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -298,6 +298,10 @@ #define INSTDONE 0x02090 #define NOPID 0x02094 #define HWSTAM 0x02098 + +#define MI_MODE 0x0209c +# define VS_TIMER_DISPATCH (1 << 6) + #define SCPD0 0x0209c /* 915+ only */ #define IER 0x020a0 #define IIR 0x020a4 From 76e47c30bdc591815eeb5598f1e2a243a30bd585 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 11 Mar 2010 14:01:38 -0800 Subject: [PATCH 071/478] drivers/gpu/drm/i915/intel_bios.c: fix continuation line formats String constants that are continued on subsequent lines with \ will cause spurious whitespace in the resulting output. Signed-off-by: Joe Perches Cc: Dave Airlie Cc: Eric Anholt Cc: Jesse Barnes Signed-off-by: Andrew Morton [anholt: whacked it to wrap to 80 columns instead] Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_bios.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 70c9d4ba704..f9ba452f0cb 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -417,8 +417,9 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) edp = find_section(bdb, BDB_EDP); if (!edp) { if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) { - DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported,\ - assume 18bpp panel color depth.\n"); + DRM_DEBUG_KMS("No eDP BDB found but eDP panel " + "supported, assume 18bpp panel color " + "depth.\n"); dev_priv->edp_bpp = 18; } return; From 59f2d0fc4bdfbbfabfa3715ba17d0609e5964c7e Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Tue, 9 Mar 2010 23:37:07 +0800 Subject: [PATCH 072/478] drm/i915: Fix check with IS_GEN6 IS_GEN6 missed to include SandyBridge mobile chip, which failed in i915_probe_agp() for memory config detection. Fix it with a device info flag. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1b2e95455c0..4b26919abdb 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -139,12 +139,12 @@ const static struct intel_device_info intel_ironlake_m_info = { const static struct intel_device_info intel_sandybridge_d_info = { .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, - .has_hotplug = 1, + .has_hotplug = 1, .is_gen6 = 1, }; const static struct intel_device_info intel_sandybridge_m_info = { .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, .need_gfx_hws = 1, - .has_hotplug = 1, + .has_hotplug = 1, .is_gen6 = 1, }; const static struct pci_device_id pciidlist[] = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 979439cfb82..aba8260fbc5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -205,6 +205,7 @@ struct intel_device_info { u8 is_g4x : 1; u8 is_pineview : 1; u8 is_ironlake : 1; + u8 is_gen6 : 1; u8 has_fbc : 1; u8 has_rc6 : 1; u8 has_pipe_cxsr : 1; @@ -1084,6 +1085,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046) #define IS_IRONLAKE(dev) (INTEL_INFO(dev)->is_ironlake) #define IS_I9XX(dev) (INTEL_INFO(dev)->is_i9xx) +#define IS_GEN6(dev) (INTEL_INFO(dev)->is_gen6) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) #define IS_GEN3(dev) (IS_I915G(dev) || \ @@ -1107,8 +1109,6 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) -#define IS_GEN6(dev) ((dev)->pci_device == 0x0102) - /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. */ From 1f2b10131f83f7caa67bf1273cec126b4283015d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Mar 2010 19:52:55 +0000 Subject: [PATCH 073/478] drm/i915: Avoid NULL deref in get_pages() unwind after error. Fixes: http://bugzilla.kernel.org/show_bug.cgi?id=15527 NULL pointer dereference in i915_gem_object_save_bit_17_swizzle BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] i915_gem_object_save_bit_17_swizzle+0x5b/0xc0 [i915] Call Trace: [] ? i915_gem_object_put_pages+0x125/0x150 [i915] [] ? i915_gem_object_get_pages+0xf1/0x110 [i915] [] ? i915_gem_object_bind_to_gtt+0xb8/0x2a0 [i915] [] ? drm_mm_get_block_generic+0x4d/0x180 [] ? i915_gem_mmap_gtt_ioctl+0x16d/0x240 [i915] [] ? i915_gem_madvise_ioctl+0x86/0x120 [i915] Signed-off-by: Chris Wilson Reported-by: maciej.rutecki@gmail.com Cc: stable@kernel.org Reviewed-by: Eric Anholt Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 134973f7706..933e865a892 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1466,9 +1466,6 @@ i915_gem_object_put_pages(struct drm_gem_object *obj) obj_priv->dirty = 0; for (i = 0; i < page_count; i++) { - if (obj_priv->pages[i] == NULL) - break; - if (obj_priv->dirty) set_page_dirty(obj_priv->pages[i]); @@ -2251,7 +2248,6 @@ i915_gem_object_get_pages(struct drm_gem_object *obj, struct address_space *mapping; struct inode *inode; struct page *page; - int ret; if (obj_priv->pages_refcount++ != 0) return 0; @@ -2274,11 +2270,9 @@ i915_gem_object_get_pages(struct drm_gem_object *obj, mapping_gfp_mask (mapping) | __GFP_COLD | gfpmask); - if (IS_ERR(page)) { - ret = PTR_ERR(page); - i915_gem_object_put_pages(obj); - return ret; - } + if (IS_ERR(page)) + goto err_pages; + obj_priv->pages[i] = page; } @@ -2286,6 +2280,15 @@ i915_gem_object_get_pages(struct drm_gem_object *obj, i915_gem_object_do_bit_17_swizzle(obj); return 0; + +err_pages: + while (i--) + page_cache_release(obj_priv->pages[i]); + + drm_free_large(obj_priv->pages); + obj_priv->pages = NULL; + obj_priv->pages_refcount--; + return PTR_ERR(page); } static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg) From 915a428e43acfd05e4ffeaf40549b0cf163eebe2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 6 Mar 2010 14:05:39 +0300 Subject: [PATCH 074/478] drm/i915: fix small leak on overlay error path We should free "params" before returning. Signed-off-by: Dan Carpenter Reviewed-by: Daniel Vetter Cc: stable@kernel.org (for .33) Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_overlay.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index d355d1d527e..60595fc26fd 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1068,14 +1068,18 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id, DRM_MODE_OBJECT_CRTC); - if (!drmmode_obj) - return -ENOENT; + if (!drmmode_obj) { + ret = -ENOENT; + goto out_free; + } crtc = to_intel_crtc(obj_to_crtc(drmmode_obj)); new_bo = drm_gem_object_lookup(dev, file_priv, put_image_rec->bo_handle); - if (!new_bo) - return -ENOENT; + if (!new_bo) { + ret = -ENOENT; + goto out_free; + } mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->struct_mutex); @@ -1165,6 +1169,7 @@ out_unlock: mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->mode_config.mutex); drm_gem_object_unreference_unlocked(new_bo); +out_free: kfree(params); return ret; From 535297a6ae4c3b7a0562e71fac15c213eeec68e7 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 17 Mar 2010 16:06:11 +0200 Subject: [PATCH 075/478] vhost: fix error handling in vring ioctls Stanse found a locking problem in vhost_set_vring: several returns from VHOST_SET_VRING_KICK, VHOST_SET_VRING_CALL, VHOST_SET_VRING_ERR with the vq->mutex held. Fix these up. Reported-by: Jiri Slaby Acked-by: Laurent Chavey Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 7cd55e07879..7bd7a1e4409 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -476,8 +476,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp) if (r < 0) break; eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); - if (IS_ERR(eventfp)) - return PTR_ERR(eventfp); + if (IS_ERR(eventfp)) { + r = PTR_ERR(eventfp); + break; + } if (eventfp != vq->kick) { pollstop = filep = vq->kick; pollstart = vq->kick = eventfp; @@ -489,8 +491,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp) if (r < 0) break; eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); - if (IS_ERR(eventfp)) - return PTR_ERR(eventfp); + if (IS_ERR(eventfp)) { + r = PTR_ERR(eventfp); + break; + } if (eventfp != vq->call) { filep = vq->call; ctx = vq->call_ctx; @@ -505,8 +509,10 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp) if (r < 0) break; eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); - if (IS_ERR(eventfp)) - return PTR_ERR(eventfp); + if (IS_ERR(eventfp)) { + r = PTR_ERR(eventfp); + break; + } if (eventfp != vq->error) { filep = vq->error; vq->error = eventfp; From 8301b91ba0b2d15c86fdf5357efe7c04eb767a6e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 17 Mar 2010 11:07:55 +0100 Subject: [PATCH 076/478] firewire: ohci: add cycle timer quirk for the TI TSB12LV22 Among the many entries in the TSB12LV22 errata list (TI literature number SLLS312) is the following: PCI Slave reads of the Cycle Timer register may occasionally get an incorrect value. Software may be able to validate value by reading the register multiple times rapidly and evaluating for a reasonable difference. Signed-off-by: Clemens Ladisch (untested) Signed-off-by: Stefan Richter (added #define) --- drivers/firewire/ohci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 75dc6988cff..e33917bf97d 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -231,6 +231,8 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) static char ohci_driver_name[] = KBUILD_MODNAME; +#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 + #define QUIRK_CYCLE_TIMER 1 #define QUIRK_RESET_PACKET 2 #define QUIRK_BE_HEADERS 4 @@ -239,6 +241,8 @@ static char ohci_driver_name[] = KBUILD_MODNAME; static const struct { unsigned short vendor, device, flags; } ohci_quirks[] = { + {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, QUIRK_CYCLE_TIMER | + QUIRK_RESET_PACKET}, {PCI_VENDOR_ID_TI, PCI_ANY_ID, QUIRK_RESET_PACKET}, {PCI_VENDOR_ID_AL, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, {PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, From 9eff26ea48bfbe2885b158742a7512a097ec911b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 18 Mar 2010 16:05:13 +1100 Subject: [PATCH 077/478] powerpc/perf_events: Fix call-graph recording, add perf_arch_fetch_caller_regs This implements a powerpc version of perf_arch_fetch_caller_regs to get correct call-graphs. It's implemented in assembly because that way we can be sure there isn't a stack frame for perf_arch_fetch_caller_regs. If it was in C, gcc might or might not create a stack frame for it, which would affect the number of levels we have to skip. With this, we see results from perf record -e lock:lock_acquire like this: # Samples: 24878 # # Overhead Command Shared Object Symbol # ........ .............. ................. ...... # 14.99% perf [kernel.kallsyms] [k] ._raw_spin_lock | --- ._raw_spin_lock | |--25.00%-- .alloc_fd | (nil) | | | |--50.00%-- .anon_inode_getfd | | .sys_perf_event_open | | syscall_exit | | syscall | | create_counter | | __cmd_record | | run_builtin | | main | | 0xfd2e704 | | 0xfd2e8c0 | | (nil) ... etc. Signed-off-by: Paul Mackerras Acked-by: Benjamin Herrenschmidt Cc: anton@samba.org Cc: linuxppc-dev@ozlabs.org Cc: Peter Zijlstra Cc: Frederic Weisbecker LKML-Reference: <20100318050513.GA6575@drongo> Signed-off-by: Ingo Molnar --- arch/powerpc/include/asm/asm-compat.h | 2 ++ arch/powerpc/kernel/misc.S | 28 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h index c1b475a941e..a9b91ed3d4b 100644 --- a/arch/powerpc/include/asm/asm-compat.h +++ b/arch/powerpc/include/asm/asm-compat.h @@ -28,6 +28,7 @@ #define PPC_LLARX(t, a, b, eh) PPC_LDARX(t, a, b, eh) #define PPC_STLCX stringify_in_c(stdcx.) #define PPC_CNTLZL stringify_in_c(cntlzd) +#define PPC_LR_STKOFF 16 /* Move to CR, single-entry optimized version. Only available * on POWER4 and later. @@ -51,6 +52,7 @@ #define PPC_STLCX stringify_in_c(stwcx.) #define PPC_CNTLZL stringify_in_c(cntlzw) #define PPC_MTOCRF stringify_in_c(mtcrf) +#define PPC_LR_STKOFF 4 #endif diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index 2d29752cbe1..b485a87c94e 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S @@ -127,3 +127,31 @@ _GLOBAL(__setup_cpu_power7) _GLOBAL(__restore_cpu_power7) /* place holder */ blr + +#ifdef CONFIG_EVENT_TRACING +/* + * Get a minimal set of registers for our caller's nth caller. + * r3 = regs pointer, r5 = n. + * + * We only get R1 (stack pointer), NIP (next instruction pointer) + * and LR (link register). These are all we can get in the + * general case without doing complicated stack unwinding, but + * fortunately they are enough to do a stack backtrace, which + * is all we need them for. + */ +_GLOBAL(perf_arch_fetch_caller_regs) + mr r6,r1 + cmpwi r5,0 + mflr r4 + ble 2f + mtctr r5 +1: PPC_LL r6,0(r6) + bdnz 1b + PPC_LL r4,PPC_LR_STKOFF(r6) +2: PPC_LL r7,0(r6) + PPC_LL r7,PPC_LR_STKOFF(r7) + PPC_STL r6,GPR1-STACK_FRAME_OVERHEAD(r3) + PPC_STL r4,_NIP-STACK_FRAME_OVERHEAD(r3) + PPC_STL r7,_LINK-STACK_FRAME_OVERHEAD(r3) + blr +#endif /* CONFIG_EVENT_TRACING */ From da3b062e306452ffb74cf5e9e5128f9f1e0502ab Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Mar 2010 09:39:59 +0100 Subject: [PATCH 078/478] ASoC: SIU driver shall select FW_LOADER The SIU ASoC driver must load firmware to program the DSP, therefore it has to select FW_LOADER in its Kconfig entry. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 106674979b5..f07f6d8b93e 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -32,6 +32,7 @@ config SND_SOC_SH4_SIU select DMA_ENGINE select DMADEVICES select SH_DMAE + select FW_LOADER ## ## Boards From b22b63ebafb97b66d1054e69941ee049d790c6cf Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Thu, 11 Mar 2010 18:43:46 -0800 Subject: [PATCH 079/478] ocfs2: Always try for maximum bits with new local alloc windows What we were doing before was to ask for the current window size as the maximum allocation. This had the effect of limiting the amount of allocation we could get for the local alloc during times when the window size was shrunk due to fragmentation. In some cases, that could actually *increase* fragmentation by artificially limiting the number of bits we can accept. So while we still want to ask for a minimum number of bits equal to window size, there is no reason why we should limit the number of bits the local alloc should accept. Hence always allow the maximum number of local alloc bits. Signed-off-by: Mark Fasheh Signed-off-by: Joel Becker --- fs/ocfs2/localalloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index ca992d91f51..171c691b42a 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -984,8 +984,7 @@ static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb, } retry_enospc: - (*ac)->ac_bits_wanted = osb->local_alloc_bits; - + (*ac)->ac_bits_wanted = osb->local_alloc_default_bits; status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac); if (status == -ENOSPC) { if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_ENOSPC) == @@ -1061,6 +1060,7 @@ retry_enospc: OCFS2_LA_DISABLED) goto bail; + ac->ac_bits_wanted = osb->local_alloc_default_bits; status = ocfs2_claim_clusters(osb, handle, ac, osb->local_alloc_bits, &cluster_off, From 0cff810f54b3b52075c27f7a7021d5b195264b6c Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Thu, 18 Mar 2010 12:25:33 -0700 Subject: [PATCH 080/478] rcu: Fix local_irq_disable() CONFIG_PROVE_RCU=y false positives It is documented that local_irq_disable() also delimits RCU_SCHED read-site critical sections. See the document of synchronize_sched() or Documentation/RCU/whatisRCU.txt. So we have to test irqs_disabled() in rcu_read_lock_sched_held(). Otherwise rcu-lockdep brings incorrect complaint. Signed-off-by: Lai Jiangshan Signed-off-by: Paul E. McKenney Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: eric.dumazet@gmail.com LKML-Reference: <1268940334-10892-1-git-send-email-paulmck@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar --- include/linux/rcupdate.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index e1bdc4bfd27..872a98e13d6 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -149,7 +149,7 @@ static inline int rcu_read_lock_sched_held(void) return 1; if (debug_locks) lockdep_opinion = lock_is_held(&rcu_sched_lock_map); - return lockdep_opinion || preempt_count() != 0; + return lockdep_opinion || preempt_count() != 0 || irqs_disabled(); } #else /* #ifdef CONFIG_PREEMPT */ static inline int rcu_read_lock_sched_held(void) @@ -180,7 +180,7 @@ static inline int rcu_read_lock_bh_held(void) #ifdef CONFIG_PREEMPT static inline int rcu_read_lock_sched_held(void) { - return !rcu_scheduler_active || preempt_count() != 0; + return !rcu_scheduler_active || preempt_count() != 0 || irqs_disabled(); } #else /* #ifdef CONFIG_PREEMPT */ static inline int rcu_read_lock_sched_held(void) From 285aca8e2a7f8af2a18cf89d1dfa95df2f9c9132 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 18 Mar 2010 11:24:06 -0700 Subject: [PATCH 081/478] agp/intel: Respect the GTT size on Sandybridge for scratch page setup. This is similar to 14bc490bbdf1b194ad1f5f3d2a0a27edfdf78986 which respected it for how much of the GTT we would actually use. Now we won't clear beyond allocated memory when filling the GTT with scratch page addresses. Signed-off-by: Eric Anholt --- drivers/char/agp/intel-agp.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index a3e10dc7cc2..f499c5e0ca5 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -175,6 +175,10 @@ extern int agp_memory_reserved; #define SNB_GMCH_GMS_STOLEN_448M (0xe << 3) #define SNB_GMCH_GMS_STOLEN_480M (0xf << 3) #define SNB_GMCH_GMS_STOLEN_512M (0x10 << 3) +#define SNB_GTT_SIZE_0M (0 << 8) +#define SNB_GTT_SIZE_1M (1 << 8) +#define SNB_GTT_SIZE_2M (2 << 8) +#define SNB_GTT_SIZE_MASK (3 << 8) static const struct aper_size_info_fixed intel_i810_sizes[] = { @@ -1438,6 +1442,8 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) { + u16 snb_gmch_ctl; + switch (agp_bridge->dev->device) { case PCI_DEVICE_ID_INTEL_GM45_HB: case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB: @@ -1449,9 +1455,26 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB: case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB: case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB: + *gtt_offset = *gtt_size = MB(2); + break; case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB: case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB: - *gtt_offset = *gtt_size = MB(2); + *gtt_offset = MB(2); + + pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); + switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) { + default: + case SNB_GTT_SIZE_0M: + printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl); + *gtt_size = MB(0); + break; + case SNB_GTT_SIZE_1M: + *gtt_size = MB(1); + break; + case SNB_GTT_SIZE_2M: + *gtt_size = MB(2); + break; + } break; default: *gtt_offset = *gtt_size = KB(512); From 66f6ff09ff67c45919b336395c4d7d0ed3a97edc Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 18 Mar 2010 12:19:37 -0700 Subject: [PATCH 082/478] agp/intel: Don't do the chipset flush on Sandybridge. This CPU should be coherent with graphics in this direction, though flushing graphics caches are still required. Fixes a system reset on module load on Sandybridge with 4G+ memory. Signed-off-by: Eric Anholt --- drivers/char/agp/intel-agp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index f499c5e0ca5..b78d5c381ef 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -97,6 +97,9 @@ EXPORT_SYMBOL(intel_agp_enabled); #define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB) +#define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) + #define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \ @@ -107,8 +110,7 @@ EXPORT_SYMBOL(intel_agp_enabled); agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) + IS_SNB) extern int agp_memory_reserved; @@ -1204,6 +1206,9 @@ static void intel_i9xx_setup_flush(void) if (intel_private.ifp_resource.start) return; + if (IS_SNB) + return; + /* setup a resource for this object */ intel_private.ifp_resource.name = "Intel Flush Page"; intel_private.ifp_resource.flags = IORESOURCE_MEM; From 8956c8bba5b11b3d3aec000e6c6184943011a8d4 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 18 Mar 2010 13:21:14 -0700 Subject: [PATCH 083/478] drm/i915: Set up the documented clock gating on Sandybridge and Ironlake. Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++ drivers/gpu/drm/i915/intel_display.c | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2720bc2cd67..cbbf59f56df 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2176,6 +2176,14 @@ #define DISPLAY_PORT_PLL_BIOS_1 0x46010 #define DISPLAY_PORT_PLL_BIOS_2 0x46014 +#define PCH_DSPCLK_GATE_D 0x42020 +# define DPFDUNIT_CLOCK_GATE_DISABLE (1 << 7) +# define DPARBUNIT_CLOCK_GATE_DISABLE (1 << 5) + +#define PCH_3DCGDIS0 0x46020 +# define MARIUNIT_CLOCK_GATE_DISABLE (1 << 18) +# define SVSMUNIT_CLOCK_GATE_DISABLE (1 << 1) + #define FDI_PLL_FREQ_CTL 0x46030 #define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24) #define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0e2c5dafd9d..58fc7fa0eb1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4717,6 +4717,20 @@ void intel_init_clock_gating(struct drm_device *dev) * specs, but enable as much else as we can. */ if (HAS_PCH_SPLIT(dev)) { + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + if (IS_IRONLAKE(dev)) { + /* Required for FBC */ + dspclk_gate |= DPFDUNIT_CLOCK_GATE_DISABLE; + /* Required for CxSR */ + dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_3DCGDIS0, + MARIUNIT_CLOCK_GATE_DISABLE | + SVSMUNIT_CLOCK_GATE_DISABLE); + } + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); return; } else if (IS_G4X(dev)) { uint32_t dspclk_gate; From fe305198d4bf481d6dd017df35c566c9d477fada Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Mar 2010 09:22:12 +0100 Subject: [PATCH 084/478] drm/intel: fix up set_tiling for untiled->tiled transition Bug introduced in commit 10ae9bd25acf394c8fa2f9d795dfa9cec4d19ed6 Author: Daniel Vetter Date: Mon Feb 1 13:59:17 2010 +0100 drm/i915: blow away userspace mappings before fence change The problem is that when there's no fence reg assigned and the object is mapped at a fenceable offset in the gtt, the userspace mappings won't be torn down. Which happens on untiled->tiled transition quite often on 4th gen and later because there fencing does not have any special alignment constraints (as opposed to 2nd and 3rd gen on which I've tested the original commit). Bugzilla: http://bugs.freedesktop.org/show_bug.cgi?id=26993 Signed-off-by: Daniel Vetter Tested-by: Eric Anholt (fixes OpenArena) Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem_tiling.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index b5c55d88ff7..c01c878e51b 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -325,9 +325,12 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, * need to ensure that any fence register is cleared. */ if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode)) - ret = i915_gem_object_unbind(obj); + ret = i915_gem_object_unbind(obj); + else if (obj_priv->fence_reg != I915_FENCE_REG_NONE) + ret = i915_gem_object_put_fence_reg(obj); else - ret = i915_gem_object_put_fence_reg(obj); + i915_gem_release_mmap(obj); + if (ret != 0) { WARN(ret != -ERESTARTSYS, "failed to reset object for tiling switch"); From 2271048d1b3b0aabf83d25b29c20646dcabedc05 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 18 Mar 2010 17:54:19 -0400 Subject: [PATCH 085/478] ring-buffer: Do 8 byte alignment for 64 bit that can not handle 4 byte align The ring buffer uses 4 byte alignment while recording events into the buffer, even on 64bit machines. This saves space when there are lots of events being recorded at 4 byte boundaries. The ring buffer has a zero copy method to write into the buffer, with the reserving of space and then committing it. This may cause problems when writing an 8 byte word into a 4 byte alignment (not 8). For x86 and PPC this is not an issue, but on some architectures this would cause an out-of-alignment exception. This patch uses CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS to determine if it is OK to use 4 byte alignments on 64 bit machines. If it is not, it forces the ring buffer event header to be 8 bytes and not 4, and will align the length of the data to be 8 byte aligned. This keeps the data payload at 8 byte alignments and will allow these machines to run without issue. The trick to this is that the header can be either 4 bytes or 8 bytes depending on the length of the data payload. The 4 byte header has a length field that supports up to 112 bytes. If the length of the data is more than 112, the length field is set to zero, and the actual length is stored in the next 4 bytes after the header. When CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set, the code forces zero in the 4 byte header forcing the length to be stored in the 4 byte array, even with a small data load. It also forces the length of the data load to be 8 byte aligned. The combination of these two guarantee that the data is always at 8 byte alignment. Tested-by: Frederic Weisbecker (on sparc64) Reported-by: Frederic Weisbecker Acked-by: David S. Miller Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 05a9f83b881..d1187ef20ca 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -207,6 +207,14 @@ EXPORT_SYMBOL_GPL(tracing_is_on); #define RB_MAX_SMALL_DATA (RB_ALIGNMENT * RINGBUF_TYPE_DATA_TYPE_LEN_MAX) #define RB_EVNT_MIN_SIZE 8U /* two 32bit words */ +#if !defined(CONFIG_64BIT) || defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) +# define RB_FORCE_8BYTE_ALIGNMENT 0 +# define RB_ARCH_ALIGNMENT RB_ALIGNMENT +#else +# define RB_FORCE_8BYTE_ALIGNMENT 1 +# define RB_ARCH_ALIGNMENT 8U +#endif + /* define RINGBUF_TYPE_DATA for 'case RINGBUF_TYPE_DATA:' */ #define RINGBUF_TYPE_DATA 0 ... RINGBUF_TYPE_DATA_TYPE_LEN_MAX @@ -1547,7 +1555,7 @@ rb_update_event(struct ring_buffer_event *event, case 0: length -= RB_EVNT_HDR_SIZE; - if (length > RB_MAX_SMALL_DATA) + if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT) event->array[0] = length; else event->type_len = DIV_ROUND_UP(length, RB_ALIGNMENT); @@ -1722,11 +1730,11 @@ static unsigned rb_calculate_event_length(unsigned length) if (!length) length = 1; - if (length > RB_MAX_SMALL_DATA) + if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT) length += sizeof(event.array[0]); length += RB_EVNT_HDR_SIZE; - length = ALIGN(length, RB_ALIGNMENT); + length = ALIGN(length, RB_ARCH_ALIGNMENT); return length; } From b634f87522dff87712df8bda2a6c9061954d552a Mon Sep 17 00:00:00 2001 From: Alexandra Kossovsky Date: Thu, 18 Mar 2010 20:29:24 -0700 Subject: [PATCH 086/478] tcp: Fix OOB POLLIN avoidance. From: Alexandra.Kossovsky@oktetlabs.ru Fixes kernel bugzilla #15541 Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 5901010fad5..ae16f809e71 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -429,7 +429,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) if (tp->urg_seq == tp->copied_seq && !sock_flag(sk, SOCK_URGINLINE) && tp->urg_data) - target--; + target++; /* Potential race condition. If read of tp below will * escape above sk->sk_state, we can be illegally awaken From 658cc524305c9759019c4430ded231f631472482 Mon Sep 17 00:00:00 2001 From: Abraham Arce Date: Tue, 16 Mar 2010 12:24:54 +0000 Subject: [PATCH 087/478] KS8851: Avoid NULL pointer in set rx mode Kernel NULL pointer dereference when setting mode for IFF_MULTICAST. Tested on SDP OMAP4430 board. ks8851 spi1.0: message enable is 0 ks8851 spi1.0: revision 0, MAC f2:f4:2f:56:37:de, IRQ 194 Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = c0004000 [00000000] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP last sysfs file: Modules linked in: CPU: 0 Not tainted (2.6.34-rc1-01039-g38d7ed1-dirty #3) PC is at ks8851_set_rx_mode+0x88/0x124 LR is at bitrev32+0x24/0x2c Backtrace: [] ? (ks8851_set_rx_mode+0x0/0x124) [] (__dev_set_rx_mode+0x0/0x90) [] (dev_mc_add+0x0/0x78) [] (igmp_group_added+0x0/0x64) [] (ip_mc_inc_group+0x0/0x150) [] (ip_mc_up+0x0/0x64) [] (inetdev_event+0x0/0x3d4) [] (notifier_call_chain+0x0/0x78) [] (__raw_notifier_call_chain+0x0/0x24) [] (raw_notifier_call_chain+0x0/0x28) [] (call_netdevice_notifiers+0x0/0x24) [] (__dev_notify_flags+0x0/0x68) [] (dev_change_flags+0x0/0x4c) [] (ip_auto_config+0x0/0xf1c) [] (do_one_initcall+0x0/0x1bc) [] (kernel_init+0x0/0x234) Code: e15130bc e1833012 e14130bc e5943000 (e5934000) ---[ end trace ed0fb00a94142792 ]--- Kernel panic - not syncing: Fatal exception in interrupt Signed-off-by: Abraham Arce Signed-off-by: David S. Miller --- drivers/net/ks8851.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 0573e0bb444..13cc1ca261d 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -976,7 +976,6 @@ static void ks8851_set_rx_mode(struct net_device *dev) crc >>= (32 - 6); /* get top six bits */ rxctrl.mchash[crc >> 4] |= (1 << (crc & 0xf)); - mcptr = mcptr->next; } rxctrl.rxcr1 = RXCR1_RXME | RXCR1_RXPAFMA; From 17da69b8bfbe441a33a873ad5dd7d3d85800bf2b Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Wed, 17 Mar 2010 00:09:29 +0000 Subject: [PATCH 088/478] jme: Fix VLAN memory leak Fix memory leak while receiving 8021q tagged packet which is not registered by user. Signed-off-by: Guo-Fu Tseng Cc: stable@kernel.org Signed-off-by: David S. Miller --- drivers/net/jme.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 0f31497833d..cfc7b9824d6 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -946,6 +946,8 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) jme->jme_vlan_rx(skb, jme->vlgrp, le16_to_cpu(rxdesc->descwb.vlan)); NET_STAT(jme).rx_bytes += 4; + } else { + dev_kfree_skb(skb); } } else { jme->jme_rx(skb); From bf5e5360fd1df1ae429ebbd81838d7d0879797d1 Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Wed, 17 Mar 2010 00:09:30 +0000 Subject: [PATCH 089/478] jme: Protect vlgrp structure by pause RX actions. Temporary stop the RX IRQ, and disable (sync) tasklet or napi. And restore it after finished the vlgrp pointer assignment. Signed-off-by: Guo-Fu Tseng Cc: stable@kernel.org Signed-off-by: David S. Miller --- drivers/net/jme.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/net/jme.c b/drivers/net/jme.c index cfc7b9824d6..c0b59a55538 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -2083,12 +2083,45 @@ jme_tx_timeout(struct net_device *netdev) jme_reset_link(jme); } +static inline void jme_pause_rx(struct jme_adapter *jme) +{ + atomic_dec(&jme->link_changing); + + jme_set_rx_pcc(jme, PCC_OFF); + if (test_bit(JME_FLAG_POLL, &jme->flags)) { + JME_NAPI_DISABLE(jme); + } else { + tasklet_disable(&jme->rxclean_task); + tasklet_disable(&jme->rxempty_task); + } +} + +static inline void jme_resume_rx(struct jme_adapter *jme) +{ + struct dynpcc_info *dpi = &(jme->dpi); + + if (test_bit(JME_FLAG_POLL, &jme->flags)) { + JME_NAPI_ENABLE(jme); + } else { + tasklet_hi_enable(&jme->rxclean_task); + tasklet_hi_enable(&jme->rxempty_task); + } + dpi->cur = PCC_P1; + dpi->attempt = PCC_P1; + dpi->cnt = 0; + jme_set_rx_pcc(jme, PCC_P1); + + atomic_inc(&jme->link_changing); +} + static void jme_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) { struct jme_adapter *jme = netdev_priv(netdev); + jme_pause_rx(jme); jme->vlgrp = grp; + jme_resume_rx(jme); } static void From 54d259d474e1fee6f6bb8f0f1360d85195199ac5 Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Wed, 17 Mar 2010 00:09:31 +0000 Subject: [PATCH 090/478] jme: Advance driver version number Advance driver version number after some bug fix. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller --- drivers/net/jme.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/jme.h b/drivers/net/jme.h index c19db9146a2..07ad3a45718 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -25,7 +25,7 @@ #define __JME_H_INCLUDED__ #define DRV_NAME "jme" -#define DRV_VERSION "1.0.5" +#define DRV_VERSION "1.0.6" #define PFX DRV_NAME ": " #define PCI_DEVICE_ID_JMICRON_JMC250 0x0250 From 0641e4fbf2f824faee00ea74c459a088d94905fd Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 18 Mar 2010 21:16:45 -0700 Subject: [PATCH 091/478] net: Potential null skb->dev dereference When doing "ifenslave -d bond0 eth0", there is chance to get NULL dereference in netif_receive_skb(), because dev->master suddenly becomes NULL after we tested it. We should use ACCESS_ONCE() to avoid this (or rcu_dereference()) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 8 ++++---- net/8021q/vlan_core.c | 4 ++-- net/core/dev.c | 8 +++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c79a88be7c3..fa8b4763799 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2059,12 +2059,12 @@ static inline void skb_bond_set_mac_by_master(struct sk_buff *skb, * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and * ARP on active-backup slaves with arp_validate enabled. */ -static inline int skb_bond_should_drop(struct sk_buff *skb) +static inline int skb_bond_should_drop(struct sk_buff *skb, + struct net_device *master) { - struct net_device *dev = skb->dev; - struct net_device *master = dev->master; - if (master) { + struct net_device *dev = skb->dev; + if (master->priv_flags & IFF_MASTER_ARPMON) dev->last_rx = jiffies; diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index c0316e0ca6e..c584a0af77d 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -11,7 +11,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, if (netpoll_rx(skb)) return NET_RX_DROP; - if (skb_bond_should_drop(skb)) + if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master))) goto drop; skb->skb_iif = skb->dev->ifindex; @@ -83,7 +83,7 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, { struct sk_buff *p; - if (skb_bond_should_drop(skb)) + if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master))) goto drop; skb->skb_iif = skb->dev->ifindex; diff --git a/net/core/dev.c b/net/core/dev.c index bcc490cc945..59d4394d2ce 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2483,6 +2483,7 @@ int netif_receive_skb(struct sk_buff *skb) { struct packet_type *ptype, *pt_prev; struct net_device *orig_dev; + struct net_device *master; struct net_device *null_or_orig; struct net_device *null_or_bond; int ret = NET_RX_DROP; @@ -2503,11 +2504,12 @@ int netif_receive_skb(struct sk_buff *skb) null_or_orig = NULL; orig_dev = skb->dev; - if (orig_dev->master) { - if (skb_bond_should_drop(skb)) + master = ACCESS_ONCE(orig_dev->master); + if (master) { + if (skb_bond_should_drop(skb, master)) null_or_orig = orig_dev; /* deliver only exact match */ else - skb->dev = orig_dev->master; + skb->dev = master; } __get_cpu_var(netdev_rx_stat).total++; From 1097cd17700c4e9903b7bbfcec1432f61784cb53 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Thu, 18 Mar 2010 14:34:52 +0000 Subject: [PATCH 092/478] ixgbe: Fix 82599 multispeed fiber link issues due to Tx laser flapping Fix 82599 link issues during driver load and unload test using multi-speed 10G & 1G fiber modules. When connected back to back sometime 82599 multispeed fiber modules would link at 1G speed instead of 10G highest speed, due to a race condition in autotry process involving Tx laser flapping. Move autotry autoneg-37 tx laser flapping process from multispeed module init setup to driver unload. This will alert the link partner to restart its autotry process when it tries to establish the link with the link partner Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_82599.c | 78 ++++++++++++++++++--------------- drivers/net/ixgbe/ixgbe_main.c | 11 +++++ drivers/net/ixgbe/ixgbe_type.h | 1 + 3 files changed, 54 insertions(+), 36 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 1f30e163bd9..b405a00817c 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -39,6 +39,7 @@ #define IXGBE_82599_MC_TBL_SIZE 128 #define IXGBE_82599_VFT_TBL_SIZE 128 +void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, @@ -68,7 +69,9 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) if (hw->phy.multispeed_fiber) { /* Set up dual speed SFP+ support */ mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber; + mac->ops.flap_tx_laser = &ixgbe_flap_tx_laser_multispeed_fiber; } else { + mac->ops.flap_tx_laser = NULL; if ((mac->ops.get_media_type(hw) == ixgbe_media_type_backplane) && (hw->phy.smart_speed == ixgbe_smart_speed_auto || @@ -412,6 +415,41 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, return status; } +/** + * ixgbe_flap_tx_laser_multispeed_fiber - Flap Tx laser + * @hw: pointer to hardware structure + * + * When the driver changes the link speeds that it can support, + * it sets autotry_restart to true to indicate that we need to + * initiate a new autotry session with the link partner. To do + * so, we set the speed then disable and re-enable the tx laser, to + * alert the link partner that it also needs to restart autotry on its + * end. This is consistent with true clause 37 autoneg, which also + * involves a loss of signal. + **/ +void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) +{ + u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); + + hw_dbg(hw, "ixgbe_flap_tx_laser_multispeed_fiber\n"); + + if (hw->mac.autotry_restart) { + /* Disable tx laser; allow 100us to go dark per spec */ + esdp_reg |= IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + IXGBE_WRITE_FLUSH(hw); + udelay(100); + + /* Enable tx laser; allow 100ms to light up */ + esdp_reg &= ~IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + IXGBE_WRITE_FLUSH(hw); + msleep(100); + + hw->mac.autotry_restart = false; + } +} + /** * ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed * @hw: pointer to hardware structure @@ -439,16 +477,6 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, hw->mac.ops.get_link_capabilities(hw, &phy_link_speed, &negotiation); speed &= phy_link_speed; - /* - * When the driver changes the link speeds that it can support, - * it sets autotry_restart to true to indicate that we need to - * initiate a new autotry session with the link partner. To do - * so, we set the speed then disable and re-enable the tx laser, to - * alert the link partner that it also needs to restart autotry on its - * end. This is consistent with true clause 37 autoneg, which also - * involves a loss of signal. - */ - /* * Try each speed one by one, highest priority first. We do this in * software because 10gb fiber doesn't support speed autonegotiation. @@ -466,6 +494,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, /* Set the module link speed */ esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5); IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + IXGBE_WRITE_FLUSH(hw); /* Allow module to change analog characteristics (1G->10G) */ msleep(40); @@ -478,19 +507,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, return status; /* Flap the tx laser if it has not already been done */ - if (hw->mac.autotry_restart) { - /* Disable tx laser; allow 100us to go dark per spec */ - esdp_reg |= IXGBE_ESDP_SDP3; - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - udelay(100); - - /* Enable tx laser; allow 2ms to light up per spec */ - esdp_reg &= ~IXGBE_ESDP_SDP3; - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - msleep(2); - - hw->mac.autotry_restart = false; - } + hw->mac.ops.flap_tx_laser(hw); /* * Wait for the controller to acquire link. Per IEEE 802.3ap, @@ -525,6 +542,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, esdp_reg &= ~IXGBE_ESDP_SDP5; esdp_reg |= IXGBE_ESDP_SDP5_DIR; IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + IXGBE_WRITE_FLUSH(hw); /* Allow module to change analog characteristics (10G->1G) */ msleep(40); @@ -537,19 +555,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, return status; /* Flap the tx laser if it has not already been done */ - if (hw->mac.autotry_restart) { - /* Disable tx laser; allow 100us to go dark per spec */ - esdp_reg |= IXGBE_ESDP_SDP3; - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - udelay(100); - - /* Enable tx laser; allow 2ms to light up per spec */ - esdp_reg &= ~IXGBE_ESDP_SDP3; - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - msleep(2); - - hw->mac.autotry_restart = false; - } + hw->mac.ops.flap_tx_laser(hw); /* Wait for the link partner to also set speed */ msleep(100); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 684af371462..b858a1a79d0 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5018,6 +5018,7 @@ static void ixgbe_multispeed_fiber_task(struct work_struct *work) autoneg = hw->phy.autoneg_advertised; if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); + hw->mac.autotry_restart = false; if (hw->mac.ops.setup_link) hw->mac.ops.setup_link(hw, autoneg, negotiation, true); adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; @@ -6380,6 +6381,16 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) del_timer_sync(&adapter->sfp_timer); cancel_work_sync(&adapter->watchdog_task); cancel_work_sync(&adapter->sfp_task); + if (adapter->hw.phy.multispeed_fiber) { + struct ixgbe_hw *hw = &adapter->hw; + /* + * Restart clause 37 autoneg, disable and re-enable + * the tx laser, to clear & alert the link partner + * that it needs to restart autotry + */ + hw->mac.autotry_restart = true; + hw->mac.ops.flap_tx_laser(hw); + } cancel_work_sync(&adapter->multispeed_fiber_task); cancel_work_sync(&adapter->sfp_config_module_task); if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 2be90746659..0ed5ab37cc5 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -2397,6 +2397,7 @@ struct ixgbe_mac_operations { s32 (*enable_rx_dma)(struct ixgbe_hw *, u32); /* Link */ + void (*flap_tx_laser)(struct ixgbe_hw *); s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool); s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, From 0ecad5a262923967147e2d1725e277a2a5fbcdd4 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Thu, 18 Mar 2010 15:16:56 +0000 Subject: [PATCH 093/478] ixgbe: Fix 82599 KX4 Wake on LAN issue after an improper system shutdown Advanced Power Management is disabled for 82599 KX4 connections by clearing GRC.APME bit, causing it to not wake the system from an improper system shutdown. By default GRC.APME is enabled and software is not supposed to clear these settings during adapter probe. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index b858a1a79d0..18b5b217f31 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -6246,9 +6246,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, case IXGBE_DEV_ID_82599_KX4: adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX | IXGBE_WUFC_MC | IXGBE_WUFC_BC); - /* Enable ACPI wakeup in GRC */ - IXGBE_WRITE_REG(hw, IXGBE_GRC, - (IXGBE_READ_REG(hw, IXGBE_GRC) & ~IXGBE_GRC_APME)); break; default: adapter->wol = 0; From 11bc3088373e913f165a8652601c6f8b8dc4aea2 Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Thu, 18 Mar 2010 22:18:41 -0700 Subject: [PATCH 094/478] smsc95xx: Fix tx checksum offload for small packets TX checksum offload does not work properly when transmitting UDP packets with 0, 1 or 2 bytes of data. This patch works around the problem by calculating checksums for these packets in the driver. Signed-off-by: Steve Glendinning Signed-off-by: David S. Miller --- drivers/net/usb/smsc95xx.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index d222d7e2527..73f9a31cf94 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1189,9 +1189,21 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, } if (csum) { - u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); - skb_push(skb, 4); - memcpy(skb->data, &csum_preamble, 4); + if (skb->len <= 45) { + /* workaround - hardware tx checksum does not work + * properly with extremely small packets */ + long csstart = skb->csum_start - skb_headroom(skb); + __wsum calc = csum_partial(skb->data + csstart, + skb->len - csstart, 0); + *((__sum16 *)(skb->data + csstart + + skb->csum_offset)) = csum_fold(calc); + + csum = false; + } else { + u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); + skb_push(skb, 4); + memcpy(skb->data, &csum_preamble, 4); + } } skb_push(skb, 4); From 44f497b4e0bba6ce1b73a107cc13636393344252 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 19 Mar 2010 11:10:19 +0200 Subject: [PATCH 095/478] ASoC: tlv320dac33: Fix DSP modes To make DSP_A mode working correctly the data delay should be configured to 0. DSP_B mode thus can not be used with DAC33, so remove it. Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index f9f367d29a9..00d6f36aabc 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1038,11 +1038,7 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_DSP_A: aictrl_a |= DAC33_AFMT_DSP; aictrl_b &= ~DAC33_DATA_DELAY_MASK; - aictrl_b |= DAC33_DATA_DELAY(1); /* 1 bit delay */ - break; - case SND_SOC_DAIFMT_DSP_B: - aictrl_a |= DAC33_AFMT_DSP; - aictrl_b &= ~DAC33_DATA_DELAY_MASK; /* No delay */ + aictrl_b |= DAC33_DATA_DELAY(0); break; case SND_SOC_DAIFMT_RIGHT_J: aictrl_a |= DAC33_AFMT_RIGHT_J; From fdb6b1e195757a66670801702e4b5fcc66ed3d72 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 19 Mar 2010 11:10:20 +0200 Subject: [PATCH 096/478] ASoC: tlv320dac33: Internal clocking changes During validation of the internal clocking setup it has been found that the following settings were not configured in an optimal way: ASRC_CTRL_A: SRCLKDIV was incorrect, instad of divide ratio 3, ratio of 2 has to be used (as the comment stated) DAC_CTRL_A: Fs = Fsref is the desired configuration instead of Fs = Fsref / 1.5 Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 00d6f36aabc..d50f1699ccb 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -778,7 +778,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) if (dac33->fifo_mode) { /* Generic for all FIFO modes */ /* 50-51 : ASRC Control registers */ - dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */ + dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCLKDIV(1)); dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */ /* Write registers 0x34 and 0x35 (MSB, LSB) */ @@ -1062,7 +1062,7 @@ static void dac33_init_chip(struct snd_soc_codec *codec) { /* 44-46: DAC Control Registers */ /* A : DAC sample rate Fsref/1.5 */ - dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(1)); + dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0)); /* B : DAC src=normal, not muted */ dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT | DAC33_DACSRCL_LEFT); From 6937c947d31186750f72c9f8c942bbcc6fe63585 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 18 Mar 2010 12:25:35 +0000 Subject: [PATCH 097/478] ASoC: Bail out of wm_hubs DC servo if calibration fails We're keeping track of the number of times we've iterated but never actually using this to bail out if the chip looks stuck. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm_hubs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 0ad9f5d536c..486bdd21a98 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -74,7 +74,7 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec) msleep(1); reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_0); dev_dbg(codec->dev, "DC servo: %x\n", reg); - } while (reg & WM8993_DCS_DATAPATH_BUSY); + } while (reg & WM8993_DCS_DATAPATH_BUSY && count < 400); if (reg & WM8993_DCS_DATAPATH_BUSY) dev_err(codec->dev, "Timed out waiting for DC Servo\n"); From 8727b909bb2348d29e62c599cd7a5d610da3760f Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sun, 28 Feb 2010 10:42:38 +0800 Subject: [PATCH 098/478] ASoC: pxa-pcm-lib: initialize DMA channel to -1 This fixes a warning ("pxa_free_dma: trying to free channel 0 which is already freed") when a device was opened but the hw_params() call failed. Signed-off-by: Daniel Mack Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/arm/pxa2xx-pcm-lib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c index 743ac6a2906..fd51fa8b06a 100644 --- a/sound/arm/pxa2xx-pcm-lib.c +++ b/sound/arm/pxa2xx-pcm-lib.c @@ -205,6 +205,7 @@ int __pxa2xx_pcm_open(struct snd_pcm_substream *substream) if (!rtd->dma_desc_array) goto err1; + rtd->dma_ch = -1; runtime->private_data = rtd; return 0; From d812e575822a2b7ab1a7cadae2571505ec6ec2bd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 19 Mar 2010 13:55:17 -0400 Subject: [PATCH 099/478] NFS: Prevent another deadlock in nfs_release_page() We should not attempt to free the page if __GFP_FS is not set. Otherwise we can deadlock as per http://bugzilla.kernel.org/show_bug.cgi?id=15578 Signed-off-by: Trond Myklebust Cc: stable@kernel.org --- fs/nfs/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index ae8d02294e4..ae0d9273653 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -491,7 +491,8 @@ static int nfs_release_page(struct page *page, gfp_t gfp) { dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); - if (gfp & __GFP_WAIT) + /* Only do I/O if gfp is a superset of GFP_KERNEL */ + if ((gfp & GFP_KERNEL) == GFP_KERNEL) nfs_wb_page(page->mapping->host, page); /* If PagePrivate() is set, then the page is not freeable */ if (PagePrivate(page)) From 25daeb550b69e89aff59bc6a84218a12b5203531 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 9 Mar 2010 22:26:40 -0500 Subject: [PATCH 100/478] PCI: fix return value from pcix_get_max_mmrbc() For the PCI_X_STATUS register, pcix_get_max_mmrbc() is returning an incorrect value, which is based on: (stat & PCI_X_STATUS_MAX_READ) >> 12 Valid return values are 512, 1024, 2048, 4096, which correspond to a 'stat' (masked and right shifted by 21) of 0, 1, 2, 3, respectively. A right shift by 11 would generate the correct return value when 'stat' (masked and right shifted by 21) has a value of 1 or 2. But for a value of 0 or 3 it's not possible to generate the correct return value by only right shifting. Fix is based on pcix_get_mmrbc()'s similar dealings with the PCI_X_CMD register. Cc: stable@kernel.org Signed-off-by: Dean Nelson Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cb1dd5f4988..ed9eb68fd94 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2587,7 +2587,7 @@ int pcix_get_max_mmrbc(struct pci_dev *dev) if (err) return -EINVAL; - return (stat & PCI_X_STATUS_MAX_READ) >> 12; + return 512 << ((stat & PCI_X_STATUS_MAX_READ) >> 21); } EXPORT_SYMBOL(pcix_get_max_mmrbc); From ded1d8f29b4d315a2093cafc3ee17ac870a87972 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 11 Mar 2010 14:08:33 -0800 Subject: [PATCH 101/478] PCI: kill off pci_register_set_vga_state() symbol export. When pci_register_set_vga_state() was made __init, the EXPORT_SYMBOL() was retained, which now leaves us with a section mismatch. Signed-off-by: Paul Mundt Cc: Mike Travis Signed-off-by: Andrew Morton Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index ed9eb68fd94..9af986085d0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3023,7 +3023,6 @@ EXPORT_SYMBOL(pcim_pin_device); EXPORT_SYMBOL(pci_disable_device); EXPORT_SYMBOL(pci_find_capability); EXPORT_SYMBOL(pci_bus_find_capability); -EXPORT_SYMBOL(pci_register_set_vga_state); EXPORT_SYMBOL(pci_release_regions); EXPORT_SYMBOL(pci_request_regions); EXPORT_SYMBOL(pci_request_regions_exclusive); From bdc2bda7c4dd253026cc1fce45fc939304749029 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 9 Mar 2010 22:26:48 -0500 Subject: [PATCH 102/478] PCI: fix access of PCI_X_CMD by pcix get and set mmrbc functions An e1000 driver on a system with a PCI-X bus was always being returned a value of 135 from both pcix_get_mmrbc() and pcix_set_mmrbc(). This value reflects an error return of PCIBIOS_BAD_REGISTER_NUMBER from pci_bus_read_config_dword(,, cap + PCI_X_CMD,). This is because for a dword, the following portion of the PCI_OP_READ() macro: if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; expands to: if (pos & 3) return PCIBIOS_BAD_REGISTER_NUMBER; And is always true for 'cap + PCI_X_CMD', which is 0xe4 + 2 = 0xe6. ('cap' is the result of calling pci_find_capability(, PCI_CAP_ID_PCIX).) The same problem exists for pci_bus_write_config_dword(,, cap + PCI_X_CMD,). In both cases, instead of calling _dword(), _word() should be called. Cc: stable@kernel.org Signed-off-by: Dean Nelson Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 9af986085d0..5c80b59c593 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2601,13 +2601,13 @@ EXPORT_SYMBOL(pcix_get_max_mmrbc); int pcix_get_mmrbc(struct pci_dev *dev) { int ret, cap; - u32 cmd; + u16 cmd; cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (!cap) return -EINVAL; - ret = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd); + ret = pci_read_config_word(dev, cap + PCI_X_CMD, &cmd); if (!ret) ret = 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2); @@ -2627,7 +2627,8 @@ EXPORT_SYMBOL(pcix_get_mmrbc); int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) { int cap, err = -EINVAL; - u32 stat, cmd, v, o; + u32 stat, v, o; + u16 cmd; if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc)) goto out; @@ -2645,7 +2646,7 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) if (v > (stat & PCI_X_STATUS_MAX_READ) >> 21) return -E2BIG; - err = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd); + err = pci_read_config_word(dev, cap + PCI_X_CMD, &cmd); if (err) goto out; @@ -2657,7 +2658,7 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) cmd &= ~PCI_X_CMD_MAX_READ; cmd |= v << 2; - err = pci_write_config_dword(dev, cap + PCI_X_CMD, cmd); + err = pci_write_config_word(dev, cap + PCI_X_CMD, cmd); } out: return err; From 7c9e2b1c4784c6e574f69dbd904b2822f2e04d6e Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 9 Mar 2010 22:26:55 -0500 Subject: [PATCH 103/478] PCI: cleanup error return for pcix get and set mmrbc functions pcix_get_mmrbc() returns the maximum memory read byte count (mmrbc), if successful, or an appropriate error value, if not. Distinguishing errors from correct values and understanding the meaning of an error can be somewhat confusing in that: correct values: 512, 1024, 2048, 4096 errors: -EINVAL -22 PCIBIOS_FUNC_NOT_SUPPORTED 0x81 PCIBIOS_BAD_VENDOR_ID 0x83 PCIBIOS_DEVICE_NOT_FOUND 0x86 PCIBIOS_BAD_REGISTER_NUMBER 0x87 PCIBIOS_SET_FAILED 0x88 PCIBIOS_BUFFER_TOO_SMALL 0x89 The PCIBIOS_ errors are returned from the PCI functions generated by the PCI_OP_READ() and PCI_OP_WRITE() macros. In a similar manner, pcix_set_mmrbc() also returns the PCIBIOS_ error values returned from pci_read_config_[word|dword]() and pci_write_config_word(). Following pcix_get_max_mmrbc()'s example, the following patch simply returns -EINVAL for all PCIBIOS_ errors encountered by pcix_get_mmrbc(), and -EINVAL or -EIO for those encountered by pcix_set_mmrbc(). This simplification was chosen in light of the fact that none of the current callers of these functions are interested in the specific type of error encountered. In the future, should this change, one could simply create a function that maps each PCIBIOS_ error to a corresponding unique errno value, which could be called by pcix_get_max_mmrbc(), pcix_get_mmrbc(), and pcix_set_mmrbc(). Additionally, this patch eliminates some unnecessary variables. Cc: stable@kernel.org Signed-off-by: Dean Nelson Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5c80b59c593..1531f3a4987 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2576,15 +2576,14 @@ EXPORT_SYMBOL_GPL(pci_reset_function); */ int pcix_get_max_mmrbc(struct pci_dev *dev) { - int err, cap; + int cap; u32 stat; cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (!cap) return -EINVAL; - err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat); - if (err) + if (pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat)) return -EINVAL; return 512 << ((stat & PCI_X_STATUS_MAX_READ) >> 21); @@ -2600,18 +2599,17 @@ EXPORT_SYMBOL(pcix_get_max_mmrbc); */ int pcix_get_mmrbc(struct pci_dev *dev) { - int ret, cap; + int cap; u16 cmd; cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (!cap) return -EINVAL; - ret = pci_read_config_word(dev, cap + PCI_X_CMD, &cmd); - if (!ret) - ret = 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2); + if (pci_read_config_word(dev, cap + PCI_X_CMD, &cmd)) + return -EINVAL; - return ret; + return 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2); } EXPORT_SYMBOL(pcix_get_mmrbc); @@ -2626,29 +2624,27 @@ EXPORT_SYMBOL(pcix_get_mmrbc); */ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) { - int cap, err = -EINVAL; + int cap; u32 stat, v, o; u16 cmd; if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc)) - goto out; + return -EINVAL; v = ffs(mmrbc) - 10; cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (!cap) - goto out; + return -EINVAL; - err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat); - if (err) - goto out; + if (pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat)) + return -EINVAL; if (v > (stat & PCI_X_STATUS_MAX_READ) >> 21) return -E2BIG; - err = pci_read_config_word(dev, cap + PCI_X_CMD, &cmd); - if (err) - goto out; + if (pci_read_config_word(dev, cap + PCI_X_CMD, &cmd)) + return -EINVAL; o = (cmd & PCI_X_CMD_MAX_READ) >> 2; if (o != v) { @@ -2658,10 +2654,10 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) cmd &= ~PCI_X_CMD_MAX_READ; cmd |= v << 2; - err = pci_write_config_word(dev, cap + PCI_X_CMD, cmd); + if (pci_write_config_word(dev, cap + PCI_X_CMD, cmd)) + return -EIO; } -out: - return err; + return 0; } EXPORT_SYMBOL(pcix_set_mmrbc); From 035a02c1e1de31888e8b6adac0ff667971ac04db Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 19 Mar 2010 12:09:22 +0100 Subject: [PATCH 104/478] x86, amd: Restrict usage of c1e_idle() Currently c1e_idle returns true for all CPUs greater than or equal to family 0xf model 0x40. This covers too many CPUs. Meanwhile a respective erratum for the underlying problem was filed (#400). This patch adds the logic to check whether erratum #400 applies to a given CPU. Especially for CPUs where SMI/HW triggered C1e is not supported, c1e_idle() doesn't need to be used. We can check this by looking at the respective OSVW bit for erratum #400. Cc: # .32.x .33.x Signed-off-by: Andreas Herrmann LKML-Reference: <20100319110922.GA19614@alberich.amd.com> Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/msr-index.h | 2 ++ arch/x86/kernel/process.c | 32 ++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 1cd58cdbc03..4604e6a54d3 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -105,6 +105,8 @@ #define MSR_AMD64_PATCH_LEVEL 0x0000008b #define MSR_AMD64_NB_CFG 0xc001001f #define MSR_AMD64_PATCH_LOADER 0xc0010020 +#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 +#define MSR_AMD64_OSVW_STATUS 0xc0010141 #define MSR_AMD64_IBSFETCHCTL 0xc0011030 #define MSR_AMD64_IBSFETCHLINAD 0xc0011031 #define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index ad9540676fc..28ad9f4d8b9 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -526,21 +526,37 @@ static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c) } /* - * Check for AMD CPUs, which have potentially C1E support + * Check for AMD CPUs, where APIC timer interrupt does not wake up CPU from C1e. + * For more information see + * - Erratum #400 for NPT family 0xf and family 0x10 CPUs + * - Erratum #365 for family 0x11 (not affected because C1e not in use) */ static int __cpuinit check_c1e_idle(const struct cpuinfo_x86 *c) { + u64 val; if (c->x86_vendor != X86_VENDOR_AMD) - return 0; - - if (c->x86 < 0x0F) - return 0; + goto no_c1e_idle; /* Family 0x0f models < rev F do not have C1E */ - if (c->x86 == 0x0f && c->x86_model < 0x40) - return 0; + if (c->x86 == 0x0F && c->x86_model >= 0x40) + return 1; - return 1; + if (c->x86 == 0x10) { + /* + * check OSVW bit for CPUs that are not affected + * by erratum #400 + */ + rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, val); + if (val >= 2) { + rdmsrl(MSR_AMD64_OSVW_STATUS, val); + if (!(val & BIT(1))) + goto no_c1e_idle; + } + return 1; + } + +no_c1e_idle: + return 0; } static cpumask_var_t c1e_mask; From dfe4d3d6a6f707fff1dbfd4b8fce65e64a91b809 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Fri, 19 Mar 2010 15:04:23 +0800 Subject: [PATCH 105/478] ocfs2: Fix the update of name_offset when removing xattrs When replacing a xattr's value, in some case we wipe its name/value first and then re-add it. The wipe is done by ocfs2_xa_block_wipe_namevalue() when the xattr is in the inode or block. We currently adjust name_offset for all the entries which have (offset < name_offset). This does not adjust the entrie we're replacing. Since we are replacing the entry, we don't adjust the total entry count. When we calculate a new namevalue location, we trust the entries now-wrong offset in ocfs2_xa_get_free_start(). The solution is to also adjust the name_offset for the replaced entry, allowing ocfs2_xa_get_free_start() to calculate the new namevalue location correctly. The following script can trigger a kernel panic easily. echo 'y'|mkfs.ocfs2 --fs-features=local,xattr -b 4K $DEVICE mount -t ocfs2 $DEVICE $MNT_DIR FILE=$MNT_DIR/$RANDOM for((i=0;i<76;i++)) do string_76="a$string_76" done string_78="aa$string_76" string_82="aaaa$string_78" touch $FILE setfattr -n 'user.test1234567890' -v $string_76 $FILE setfattr -n 'user.test1234567890' -v $string_78 $FILE setfattr -n 'user.test1234567890' -v $string_82 $FILE Signed-off-by: Tao Ma Signed-off-by: Joel Becker --- fs/ocfs2/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index d1b0d386f6d..82c2a0b53eb 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -1622,7 +1622,7 @@ static void ocfs2_xa_block_wipe_namevalue(struct ocfs2_xa_loc *loc) /* Now tell xh->xh_entries about it */ for (i = 0; i < count; i++) { offset = le16_to_cpu(xh->xh_entries[i].xe_name_offset); - if (offset < namevalue_offset) + if (offset <= namevalue_offset) le16_add_cpu(&xh->xh_entries[i].xe_name_offset, namevalue_size); } From b23179681c90a55e2a2083e1dde9f727ecffb2b7 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Fri, 19 Mar 2010 15:04:24 +0800 Subject: [PATCH 106/478] ocfs2: Init meta_ac properly in ocfs2_create_empty_xattr_block. You can't store a pointer that you haven't filled in yet and expect it to work. Signed-off-by: Tao Ma Signed-off-by: Joel Becker --- fs/ocfs2/xattr.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 82c2a0b53eb..3e7773089b9 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -6528,13 +6528,11 @@ static int ocfs2_create_empty_xattr_block(struct inode *inode, int indexed) { int ret; - struct ocfs2_alloc_context *meta_ac; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct ocfs2_xattr_set_ctxt ctxt = { - .meta_ac = meta_ac, - }; + struct ocfs2_xattr_set_ctxt ctxt; - ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac); + memset(&ctxt, 0, sizeof(ctxt)); + ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &ctxt.meta_ac); if (ret < 0) { mlog_errno(ret); return ret; @@ -6556,7 +6554,7 @@ static int ocfs2_create_empty_xattr_block(struct inode *inode, ocfs2_commit_trans(osb, ctxt.handle); out: - ocfs2_free_alloc_context(meta_ac); + ocfs2_free_alloc_context(ctxt.meta_ac); return ret; } From d11a4dc18bf41719c9f0d7ed494d295dd2973b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 18 Mar 2010 23:20:20 +0000 Subject: [PATCH 107/478] ipv4: check rt_genid in dst_check Xfrm_dst keeps a reference to ipv4 rtable entries on each cached bundle. The only way to renew xfrm_dst when the underlying route has changed, is to implement dst_check for this. This is what ipv6 side does too. The problems started after 87c1e12b5eeb7b30b4b41291bef8e0b41fc3dde9 ("ipsec: Fix bogus bundle flowi") which fixed a bug causing xfrm_dst to not get reused, until that all lookups always generated new xfrm_dst with new route reference and path mtu worked. But after the fix, the old routes started to get reused even after they were expired causing pmtu to break (well it would occationally work if the rtable gc had run recently and marked the route obsolete causing dst_check to get called). Signed-off-by: Timo Teras Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/route.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a770df2493d..32d396196df 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1441,7 +1441,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, dev_hold(rt->u.dst.dev); if (rt->idev) in_dev_hold(rt->idev); - rt->u.dst.obsolete = 0; + rt->u.dst.obsolete = -1; rt->u.dst.lastuse = jiffies; rt->u.dst.path = &rt->u.dst; rt->u.dst.neighbour = NULL; @@ -1506,7 +1506,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) struct dst_entry *ret = dst; if (rt) { - if (dst->obsolete) { + if (dst->obsolete > 0) { ip_rt_put(rt); ret = NULL; } else if ((rt->rt_flags & RTCF_REDIRECTED) || @@ -1726,7 +1726,9 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) { - return NULL; + if (rt_is_expired((struct rtable *)dst)) + return NULL; + return dst; } static void ipv4_dst_destroy(struct dst_entry *dst) @@ -1888,7 +1890,8 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (!rth) goto e_nobufs; - rth->u.dst.output= ip_rt_bug; + rth->u.dst.output = ip_rt_bug; + rth->u.dst.obsolete = -1; atomic_set(&rth->u.dst.__refcnt, 1); rth->u.dst.flags= DST_HOST; @@ -2054,6 +2057,7 @@ static int __mkroute_input(struct sk_buff *skb, rth->fl.oif = 0; rth->rt_spec_dst= spec_dst; + rth->u.dst.obsolete = -1; rth->u.dst.input = ip_forward; rth->u.dst.output = ip_output; rth->rt_genid = rt_genid(dev_net(rth->u.dst.dev)); @@ -2218,6 +2222,7 @@ local_input: goto e_nobufs; rth->u.dst.output= ip_rt_bug; + rth->u.dst.obsolete = -1; rth->rt_genid = rt_genid(net); atomic_set(&rth->u.dst.__refcnt, 1); @@ -2444,6 +2449,7 @@ static int __mkroute_output(struct rtable **result, rth->rt_spec_dst= fl->fl4_src; rth->u.dst.output=ip_output; + rth->u.dst.obsolete = -1; rth->rt_genid = rt_genid(dev_net(dev_out)); RT_CACHE_STAT_INC(out_slow_tot); From 10414444cb8a8ee8893e00390b7cf40502e28352 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 18 Mar 2010 23:00:22 +0000 Subject: [PATCH 108/478] ipv6: Remove redundant dst NULL check in ip6_dst_check As the only path leading to ip6_dst_check makes an indirect call through dst->ops, dst cannot be NULL in ip6_dst_check. This patch removes this check in case it misleads people who come across this code. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv6/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 52cd3eff31d..7fcb0e5d121 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -879,7 +879,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) rt = (struct rt6_info *) dst; - if (rt && rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) + if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) return dst; return NULL; From 97e3ecd112ba45eb217cddab59f48659bc15d9d0 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 18 Mar 2010 11:27:32 +0000 Subject: [PATCH 109/478] TCP: check min TTL on received ICMP packets This adds RFC5082 checks for TTL on received ICMP packets. It adds some security against spoofed ICMP packets disrupting GTSM protected sessions. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 70df40980a8..f4df5f931f3 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -370,6 +370,11 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) if (sk->sk_state == TCP_CLOSE) goto out; + if (unlikely(iph->ttl < inet_sk(sk)->min_ttl)) { + NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP); + goto out; + } + icsk = inet_csk(sk); tp = tcp_sk(sk); seq = ntohl(th->seq); From 936332b8e00103fc20eb7e915c9a3bcb2835a11a Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 19 Mar 2010 04:33:10 +0000 Subject: [PATCH 110/478] ixgbe: fix for real_num_tx_queues update issue Currently netdev_features_change is called before fcoe tx queues setup is done, so this patch moves calling of netdev_features_change after tx queues setup is done in ixgbe_init_interrupt_scheme, so that real_num_tx_queues is updated correctly on each fcoe enable or disable. This allows additional fcoe queues updated correctly in vlan driver for their correct queue selection. Signed-off-by: Vasu Dev Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_fcoe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 4123dec0dfb..700cfc0aa1b 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -614,9 +614,9 @@ int ixgbe_fcoe_enable(struct net_device *netdev) netdev->vlan_features |= NETIF_F_FSO; netdev->vlan_features |= NETIF_F_FCOE_MTU; netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; - netdev_features_change(netdev); ixgbe_init_interrupt_scheme(adapter); + netdev_features_change(netdev); if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); @@ -660,11 +660,11 @@ int ixgbe_fcoe_disable(struct net_device *netdev) netdev->vlan_features &= ~NETIF_F_FSO; netdev->vlan_features &= ~NETIF_F_FCOE_MTU; netdev->fcoe_ddp_xid = 0; - netdev_features_change(netdev); ixgbe_cleanup_fcoe(adapter); - ixgbe_init_interrupt_scheme(adapter); + netdev_features_change(netdev); + if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); rc = 0; From fd3686a842717b890fbe3024b83a616c54d5dba0 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Fri, 19 Mar 2010 04:41:33 +0000 Subject: [PATCH 111/478] ixgbe: Set IXGBE_RSC_CB(skb)->DMA field to zero after unmapping the address As per Simon Horman's feedback set IXGBE_RSC_CB(skb)->dma to zero after unmapping HWRSC DMA address to avoid double freeing. Signed-off-by: Mallikarjuna R Chilakala Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 18b5b217f31..d75c46ff31f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -935,10 +935,12 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, if (skb->prev) skb = ixgbe_transform_rsc_queue(skb, &(rx_ring->rsc_count)); if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) { - if (IXGBE_RSC_CB(skb)->dma) + if (IXGBE_RSC_CB(skb)->dma) { pci_unmap_single(pdev, IXGBE_RSC_CB(skb)->dma, rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); + IXGBE_RSC_CB(skb)->dma = 0; + } if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) rx_ring->rsc_count += skb_shinfo(skb)->nr_frags; else @@ -3126,10 +3128,12 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, rx_buffer_info->skb = NULL; do { struct sk_buff *this = skb; - if (IXGBE_RSC_CB(this)->dma) + if (IXGBE_RSC_CB(this)->dma) { pci_unmap_single(pdev, IXGBE_RSC_CB(this)->dma, rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); + IXGBE_RSC_CB(this)->dma = 0; + } skb = skb->prev; dev_kfree_skb(this); } while (skb); From 33bd9f601ea21c4389870e425ae4eaf210d49b95 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 19 Mar 2010 02:59:52 +0000 Subject: [PATCH 112/478] ixgbevf: Fix VF Stats accounting after reset The counters in the 82599 Virtual Function are not clear on read. They accumulate to the maximum value and then roll over. They are also not cleared when the VF executes a soft reset, so it is possible they are non-zero when the driver loads and starts. This has all been accounted for in the code that keeps the stats up to date but there is one case that is not. When the PF driver is reset the counters in the VF are all reset to zero. This adds an additional accounting overhead into the VF driver when the PF is reset under its feet. This patch adds additional counters that are used by the VF driver to accumulate and save stats after a PF reset has been detected. Prior to this patch displaying the stats in the VF after the PF has reset would show bogus data. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/ethtool.c | 42 ++++++++++++------ drivers/net/ixgbevf/ixgbevf_main.c | 68 +++++++++++++++++++----------- drivers/net/ixgbevf/vf.h | 6 +++ 3 files changed, 78 insertions(+), 38 deletions(-) diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c index 399be0c34c3..6fdd651abcd 100644 --- a/drivers/net/ixgbevf/ethtool.c +++ b/drivers/net/ixgbevf/ethtool.c @@ -46,22 +46,32 @@ struct ixgbe_stats { int sizeof_stat; int stat_offset; int base_stat_offset; + int saved_reset_offset; }; -#define IXGBEVF_STAT(m, b) sizeof(((struct ixgbevf_adapter *)0)->m), \ - offsetof(struct ixgbevf_adapter, m), \ - offsetof(struct ixgbevf_adapter, b) +#define IXGBEVF_STAT(m, b, r) sizeof(((struct ixgbevf_adapter *)0)->m), \ + offsetof(struct ixgbevf_adapter, m), \ + offsetof(struct ixgbevf_adapter, b), \ + offsetof(struct ixgbevf_adapter, r) static struct ixgbe_stats ixgbe_gstrings_stats[] = { - {"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc)}, - {"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc)}, - {"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc)}, - {"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc)}, - {"tx_busy", IXGBEVF_STAT(tx_busy, zero_base)}, - {"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc)}, - {"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base)}, - {"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base)}, - {"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base)}, - {"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base)}, + {"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc, + stats.saved_reset_vfgprc)}, + {"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc, + stats.saved_reset_vfgptc)}, + {"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc, + stats.saved_reset_vfgorc)}, + {"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc, + stats.saved_reset_vfgotc)}, + {"tx_busy", IXGBEVF_STAT(tx_busy, zero_base, zero_base)}, + {"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc, + stats.saved_reset_vfmprc)}, + {"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base, + zero_base)}, + {"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base, + zero_base)}, + {"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base, + zero_base)}, + {"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base, zero_base)}, }; #define IXGBE_QUEUE_STATS_LEN 0 @@ -455,10 +465,14 @@ static void ixgbevf_get_ethtool_stats(struct net_device *netdev, ixgbe_gstrings_stats[i].stat_offset; char *b = (char *)adapter + ixgbe_gstrings_stats[i].base_stat_offset; + char *r = (char *)adapter + + ixgbe_gstrings_stats[i].saved_reset_offset; data[i] = ((ixgbe_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p) - ((ixgbe_gstrings_stats[i].sizeof_stat == - sizeof(u64)) ? *(u64 *)b : *(u32 *)b); + sizeof(u64)) ? *(u64 *)b : *(u32 *)b) + + ((ixgbe_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)r : *(u32 *)r); } } diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index ca653c49b76..43927e1b343 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -1610,6 +1610,44 @@ static inline void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter, (adapter->rx_ring[rxr].count - 1)); } +static void ixgbevf_save_reset_stats(struct ixgbevf_adapter *adapter) +{ + /* Only save pre-reset stats if there are some */ + if (adapter->stats.vfgprc || adapter->stats.vfgptc) { + adapter->stats.saved_reset_vfgprc += adapter->stats.vfgprc - + adapter->stats.base_vfgprc; + adapter->stats.saved_reset_vfgptc += adapter->stats.vfgptc - + adapter->stats.base_vfgptc; + adapter->stats.saved_reset_vfgorc += adapter->stats.vfgorc - + adapter->stats.base_vfgorc; + adapter->stats.saved_reset_vfgotc += adapter->stats.vfgotc - + adapter->stats.base_vfgotc; + adapter->stats.saved_reset_vfmprc += adapter->stats.vfmprc - + adapter->stats.base_vfmprc; + } +} + +static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + + adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC); + adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB); + adapter->stats.last_vfgorc |= + (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32); + adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC); + adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB); + adapter->stats.last_vfgotc |= + (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32); + adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC); + + adapter->stats.base_vfgprc = adapter->stats.last_vfgprc; + adapter->stats.base_vfgorc = adapter->stats.last_vfgorc; + adapter->stats.base_vfgptc = adapter->stats.last_vfgptc; + adapter->stats.base_vfgotc = adapter->stats.last_vfgotc; + adapter->stats.base_vfmprc = adapter->stats.last_vfmprc; +} + static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -1656,6 +1694,9 @@ static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter) /* enable transmits */ netif_tx_start_all_queues(netdev); + ixgbevf_save_reset_stats(adapter); + ixgbevf_init_last_counter_stats(adapter); + /* bring the link up in the watchdog, this could race with our first * link up interrupt but shouldn't be a problem */ adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; @@ -2228,27 +2269,6 @@ out: return err; } -static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - - adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC); - adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB); - adapter->stats.last_vfgorc |= - (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32); - adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC); - adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB); - adapter->stats.last_vfgotc |= - (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32); - adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC); - - adapter->stats.base_vfgprc = adapter->stats.last_vfgprc; - adapter->stats.base_vfgorc = adapter->stats.last_vfgorc; - adapter->stats.base_vfgptc = adapter->stats.last_vfgptc; - adapter->stats.base_vfgotc = adapter->stats.last_vfgotc; - adapter->stats.base_vfmprc = adapter->stats.last_vfmprc; -} - #define UPDATE_VF_COUNTER_32bit(reg, last_counter, counter) \ { \ u32 current_counter = IXGBE_READ_REG(hw, reg); \ @@ -2416,9 +2436,9 @@ static void ixgbevf_watchdog_task(struct work_struct *work) } } -pf_has_reset: ixgbevf_update_stats(adapter); +pf_has_reset: /* Force detection of hung controller every watchdog period */ adapter->detect_tx_hung = true; @@ -3390,8 +3410,6 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, /* setup the private structure */ err = ixgbevf_sw_init(adapter); - ixgbevf_init_last_counter_stats(adapter); - #ifdef MAX_SKB_FRAGS netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | @@ -3449,6 +3467,8 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, adapter->netdev_registered = true; + ixgbevf_init_last_counter_stats(adapter); + /* print the MAC address */ hw_dbg(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", netdev->dev_addr[0], diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h index 799600e9270..1f31b052d4b 100644 --- a/drivers/net/ixgbevf/vf.h +++ b/drivers/net/ixgbevf/vf.h @@ -157,6 +157,12 @@ struct ixgbevf_hw_stats { u64 vfgorc; u64 vfgotc; u64 vfmprc; + + u64 saved_reset_vfgprc; + u64 saved_reset_vfgptc; + u64 saved_reset_vfgorc; + u64 saved_reset_vfgotc; + u64 saved_reset_vfmprc; }; struct ixgbevf_info { From 4c3a822395c01d50ca2ba3aa4529e19d237a2f8c Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 19 Mar 2010 03:00:12 +0000 Subject: [PATCH 113/478] ixgbevf: Shorten up delay timer for watchdog task The recovery from PF reset works better when you shorten up the delay until the watchdog task executes. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/ixgbevf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index 43927e1b343..3de93ae70e5 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -965,7 +965,7 @@ static irqreturn_t ixgbevf_msix_mbx(int irq, void *data) if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG) mod_timer(&adapter->watchdog_timer, - round_jiffies(jiffies + 10)); + round_jiffies(jiffies + 1)); return IRQ_HANDLED; } From 29b8dd024bd48c3d1d1e5140f5bbb683786f998e Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 19 Mar 2010 03:00:31 +0000 Subject: [PATCH 114/478] ixgbevf: Message formatting cleanups Clean up some text output formatting. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/ixgbevf_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index 3de93ae70e5..d6cbd943a6f 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -2419,7 +2419,7 @@ static void ixgbevf_watchdog_task(struct work_struct *work) if (!netif_carrier_ok(netdev)) { hw_dbg(&adapter->hw, "NIC Link is Up %s, ", ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? - "10 Gbps" : "1 Gbps")); + "10 Gbps\n" : "1 Gbps\n")); netif_carrier_on(netdev); netif_tx_wake_all_queues(netdev); } else { @@ -2695,7 +2695,7 @@ static int ixgbevf_open(struct net_device *netdev) if (hw->adapter_stopped) { err = IXGBE_ERR_MBX; printk(KERN_ERR "Unable to start - perhaps the PF" - "Driver isn't up yet\n"); + " Driver isn't up yet\n"); goto err_setup_reset; } } From b894fa2627e28c078740dc7041cd08c7e2c353ab Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Fri, 19 Mar 2010 06:07:48 +0000 Subject: [PATCH 115/478] igb: Add support for 82576 ET2 Quad Port Server Adapter Signed-off-by: Carolyn Wyborny Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.c | 1 + drivers/net/igb/e1000_hw.h | 1 + drivers/net/igb/igb_main.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 9d7fa2fb85e..0bc990ec4a8 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -94,6 +94,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) case E1000_DEV_ID_82576_FIBER: case E1000_DEV_ID_82576_SERDES: case E1000_DEV_ID_82576_QUAD_COPPER: + case E1000_DEV_ID_82576_QUAD_COPPER_ET2: case E1000_DEV_ID_82576_SERDES_QUAD: mac->type = e1000_82576; break; diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 448005276b2..82a533f5192 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -41,6 +41,7 @@ struct e1000_hw; #define E1000_DEV_ID_82576_FIBER 0x10E6 #define E1000_DEV_ID_82576_SERDES 0x10E7 #define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 +#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526 #define E1000_DEV_ID_82576_NS 0x150A #define E1000_DEV_ID_82576_NS_SERDES 0x1518 #define E1000_DEV_ID_82576_SERDES_QUAD 0x150D diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 0ed25f059a0..45a0e4fd587 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -72,6 +72,7 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER_ET2), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 }, From ea93fd9456ad32cd85b2d7914b58c6313cc40c9e Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Fri, 19 Mar 2010 22:43:29 -0700 Subject: [PATCH 116/478] KS8695: update ksp->next_rx_desc_read at the end of rx loop There is no need to adjust the next rx descriptor after each packet, so do it only once at the end of the routine. Signed-off-by: Eric Dumazet Signed-off-by: Yegor Yefremov --- drivers/net/arm/ks8695net.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index a1d4188c430..e7810b74f39 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -449,11 +449,10 @@ ks8695_rx_irq(int irq, void *dev_id) } /** - * ks8695_rx - Receive packets called by NAPI poll method + * ks8695_rx - Receive packets called by NAPI poll method * @ksp: Private data for the KS8695 Ethernet - * @budget: The max packets would be receive + * @budget: Number of packets allowed to process */ - static int ks8695_rx(struct ks8695_priv *ksp, int budget) { struct net_device *ndev = ksp->ndev; @@ -461,7 +460,6 @@ static int ks8695_rx(struct ks8695_priv *ksp, int budget) int buff_n; u32 flags; int pktlen; - int last_rx_processed = -1; int received = 0; buff_n = ksp->next_rx_desc_read; @@ -471,6 +469,7 @@ static int ks8695_rx(struct ks8695_priv *ksp, int budget) cpu_to_le32(RDES_OWN)))) { rmb(); flags = le32_to_cpu(ksp->rx_ring[buff_n].status); + /* Found an SKB which we own, this means we * received a packet */ @@ -533,23 +532,18 @@ rx_failure: ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN); rx_finished: received++; - /* And note this as processed so we can start - * from here next time - */ - last_rx_processed = buff_n; buff_n = (buff_n + 1) & MAX_RX_DESC_MASK; - /*And note which RX descriptor we last did */ - if (likely(last_rx_processed != -1)) - ksp->next_rx_desc_read = - (last_rx_processed + 1) & - MAX_RX_DESC_MASK; } + + /* And note which RX descriptor we last did */ + ksp->next_rx_desc_read = buff_n; + /* And refill the buffers */ ks8695_refill_rxbuffers(ksp); - /* Kick the RX DMA engine, in case it became - * suspended */ + /* Kick the RX DMA engine, in case it became suspended */ ks8695_writereg(ksp, KS8695_DRSC, 0); + return received; } From a50436f2cd6e85794f7e1aad795ca8302177b896 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 17 Mar 2010 06:04:14 +0000 Subject: [PATCH 117/478] net: ipmr/ip6mr: fix potential out-of-bounds vif_table access mfc_parent of cache entries is used to index into the vif_table and is initialised from mfcctl->mfcc_parent. This can take values of to 2^16-1, while the vif_table has only MAXVIFS (32) entries. The same problem affects ip6mr. Refuse invalid values to fix a potential out-of-bounds access. Unlike the other validity checks, this is checked in ipmr_mfc_add() instead of the setsockopt handler since its unused in the delete path and might be uninitialized. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/ipmr.c | 3 +++ net/ipv6/ip6mr.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 8582e12e4a6..0b9d03c54dc 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -802,6 +802,9 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock) int line; struct mfc_cache *uc, *c, **cp; + if (mfc->mfcc_parent >= MAXVIFS) + return -ENFILE; + line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr); for (cp = &net->ipv4.mfc_cache_array[line]; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 52e0f74fdfe..23e4ac0cc30 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1113,6 +1113,9 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) unsigned char ttls[MAXMIFS]; int i; + if (mfc->mf6cc_parent >= MAXMIFS) + return -ENFILE; + memset(ttls, 255, MAXMIFS); for (i = 0; i < MAXMIFS; i++) { if (IF_ISSET(i, &mfc->mf6cc_ifset)) From 6830c25b7d08fbbd922959425193791bc42079f2 Mon Sep 17 00:00:00 2001 From: Lennart Schulte Date: Wed, 17 Mar 2010 02:16:29 +0000 Subject: [PATCH 118/478] tcp: Fix tcp_mark_head_lost() with packets == 0 A packet is marked as lost in case packets == 0, although nothing should be done. This results in a too early retransmitted packet during recovery in some cases. This small patch fixes this issue by returning immediately. Signed-off-by: Lennart Schulte Signed-off-by: Arnd Hannemann Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 788851ca8c5..c096a4218b8 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2511,6 +2511,9 @@ static void tcp_mark_head_lost(struct sock *sk, int packets) int err; unsigned int mss; + if (packets == 0) + return; + WARN_ON(packets > tp->packets_out); if (tp->lost_skb_hint) { skb = tp->lost_skb_hint; From f5d410f2ea7ba340f11815a56e05b9fa9421c421 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 16 Mar 2010 13:30:44 +0000 Subject: [PATCH 119/478] netlink: fix unaligned access in nla_get_be64() This patch fixes a unaligned access in nla_get_be64() that was introduced by myself in a17c859849402315613a0015ac8fbf101acf0cc1. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- include/net/netlink.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index f82e463c875..4fc05b58503 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -945,7 +945,11 @@ static inline u64 nla_get_u64(const struct nlattr *nla) */ static inline __be64 nla_get_be64(const struct nlattr *nla) { - return *(__be64 *) nla_data(nla); + __be64 tmp; + + nla_memcpy(&tmp, nla, sizeof(tmp)); + + return tmp; } /** From 0372c38047394e23278fe6dbc0827db12ce60bd3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 20 Mar 2010 15:33:09 +0000 Subject: [PATCH 120/478] ARM: Fix IXP23xx build error in mach/memory.h One to many close parens. In file included from arch/arm/include/asm/page.h:202, from include/linux/mm_types.h:15, from include/linux/sched.h:63, from arch/arm/kernel/asm-offsets.c:13: arch/arm/include/asm/memory.h: In function 'virt_to_bus': arch/arm/include/asm/memory.h:214: error: expected ';' before ')' token arch/arm/include/asm/memory.h:214: error: expected statement before ')' token arch/arm/include/asm/memory.h: In function 'bus_to_virt': arch/arm/include/asm/memory.h:219: error: expected ';' before ')' token arch/arm/include/asm/memory.h:219: error: expected statement before ')' token Signed-off-by: Russell King --- arch/arm/mach-ixp23xx/include/mach/memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-ixp23xx/include/mach/memory.h b/arch/arm/mach-ixp23xx/include/mach/memory.h index 94a3a86cfeb..6ef65d813f1 100644 --- a/arch/arm/mach-ixp23xx/include/mach/memory.h +++ b/arch/arm/mach-ixp23xx/include/mach/memory.h @@ -19,7 +19,7 @@ */ #define PHYS_OFFSET (0x00000000) -#define IXP23XX_PCI_SDRAM_OFFSET (*((volatile int *)IXP23XX_PCI_SDRAM_BAR) & 0xfffffff0)) +#define IXP23XX_PCI_SDRAM_OFFSET (*((volatile int *)IXP23XX_PCI_SDRAM_BAR) & 0xfffffff0) #define __phys_to_bus(x) ((x) + (IXP23XX_PCI_SDRAM_OFFSET - PHYS_OFFSET)) #define __bus_to_phys(x) ((x) - (IXP23XX_PCI_SDRAM_OFFSET - PHYS_OFFSET)) From 48edcfcfbfcb3ffa76539f237b5527b62d72133a Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 20 Mar 2010 15:37:39 +0000 Subject: [PATCH 121/478] ARM: Update mach-types Signed-off-by: Russell King --- arch/arm/tools/mach-types | 75 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 31c2f4c30a9..1536f1784ca 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -12,7 +12,7 @@ # # http://www.arm.linux.org.uk/developer/machines/?action=new # -# Last update: Sat Feb 20 14:16:15 2010 +# Last update: Sat Mar 20 15:35:41 2010 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -2663,7 +2663,7 @@ reb01 MACH_REB01 REB01 2675 aquila MACH_AQUILA AQUILA 2676 spark_sls_hw2 MACH_SPARK_SLS_HW2 SPARK_SLS_HW2 2677 sheeva_esata MACH_ESATA_SHEEVAPLUG ESATA_SHEEVAPLUG 2678 -surf7x30 MACH_SURF7X30 SURF7X30 2679 +msm7x30_surf MACH_MSM7X30_SURF MSM7X30_SURF 2679 micro2440 MACH_MICRO2440 MICRO2440 2680 am2440 MACH_AM2440 AM2440 2681 tq2440 MACH_TQ2440 TQ2440 2682 @@ -2678,3 +2678,74 @@ vc088x MACH_VC088X VC088X 2690 mioa702 MACH_MIOA702 MIOA702 2691 hpmin MACH_HPMIN HPMIN 2692 ak880xak MACH_AK880XAK AK880XAK 2693 +arm926tomap850 MACH_ARM926TOMAP850 ARM926TOMAP850 2694 +lkevm MACH_LKEVM LKEVM 2695 +mw6410 MACH_MW6410 MW6410 2696 +terastation_wxl MACH_TERASTATION_WXL TERASTATION_WXL 2697 +cpu8000e MACH_CPU8000E CPU8000E 2698 +catania MACH_CATANIA CATANIA 2699 +tokyo MACH_TOKYO TOKYO 2700 +msm7201a_surf MACH_MSM7201A_SURF MSM7201A_SURF 2701 +msm7201a_ffa MACH_MSM7201A_FFA MSM7201A_FFA 2702 +msm7x25_surf MACH_MSM7X25_SURF MSM7X25_SURF 2703 +msm7x25_ffa MACH_MSM7X25_FFA MSM7X25_FFA 2704 +msm7x27_surf MACH_MSM7X27_SURF MSM7X27_SURF 2705 +msm7x27_ffa MACH_MSM7X27_FFA MSM7X27_FFA 2706 +msm7x30_ffa MACH_MSM7X30_FFA MSM7X30_FFA 2707 +qsd8x50_surf MACH_QSD8X50_SURF QSD8X50_SURF 2708 +qsd8x50_comet MACH_QSD8X50_COMET QSD8X50_COMET 2709 +qsd8x50_ffa MACH_QSD8X50_FFA QSD8X50_FFA 2710 +qsd8x50a_surf MACH_QSD8X50A_SURF QSD8X50A_SURF 2711 +qsd8x50a_ffa MACH_QSD8X50A_FFA QSD8X50A_FFA 2712 +adx_xgcp10 MACH_ADX_XGCP10 ADX_XGCP10 2713 +mcgwumts2a MACH_MCGWUMTS2A MCGWUMTS2A 2714 +mobikt MACH_MOBIKT MOBIKT 2715 +mx53_evk MACH_MX53_EVK MX53_EVK 2716 +igep0030 MACH_IGEP0030 IGEP0030 2717 +axell_h40_h50_ctrl MACH_AXELL_H40_H50_CTRL AXELL_H40_H50_CTRL 2718 +dtcommod MACH_DTCOMMOD DTCOMMOD 2719 +gould MACH_GOULD GOULD 2720 +siberia MACH_SIBERIA SIBERIA 2721 +sbc3530 MACH_SBC3530 SBC3530 2722 +qarm MACH_QARM QARM 2723 +mips MACH_MIPS MIPS 2724 +mx27grb MACH_MX27GRB MX27GRB 2725 +sbc8100 MACH_SBC8100 SBC8100 2726 +saarb MACH_SAARB SAARB 2727 +omap3mini MACH_OMAP3MINI OMAP3MINI 2728 +cnmbook7se MACH_CNMBOOK7SE CNMBOOK7SE 2729 +catan MACH_CATAN CATAN 2730 +harmony MACH_HARMONY HARMONY 2731 +tonga MACH_TONGA TONGA 2732 +cybook_orizon MACH_CYBOOK_ORIZON CYBOOK_ORIZON 2733 +htcrhodiumcdma MACH_HTCRHODIUMCDMA HTCRHODIUMCDMA 2734 +epc_g45 MACH_EPC_G45 EPC_G45 2735 +epc_lpc3250 MACH_EPC_LPC3250 EPC_LPC3250 2736 +mxc91341evb MACH_MXC91341EVB MXC91341EVB 2737 +rtw1000 MACH_RTW1000 RTW1000 2738 +bobcat MACH_BOBCAT BOBCAT 2739 +trizeps6 MACH_TRIZEPS6 TRIZEPS6 2740 +msm7x30_fluid MACH_MSM7X30_FLUID MSM7X30_FLUID 2741 +nedap9263 MACH_NEDAP9263 NEDAP9263 2742 +netgear_ms2110 MACH_NETGEAR_MS2110 NETGEAR_MS2110 2743 +bmx MACH_BMX BMX 2744 +netstream MACH_NETSTREAM NETSTREAM 2745 +vpnext_rcu MACH_VPNEXT_RCU VPNEXT_RCU 2746 +vpnext_mpu MACH_VPNEXT_MPU VPNEXT_MPU 2747 +bcmring_tablet_v1 MACH_BCMRING_TABLET_V1 BCMRING_TABLET_V1 2748 +sgarm10 MACH_SGARM10 SGARM10 2749 +cm_t3517 MACH_CM_T3517 CM_T3517 2750 +omap3_cps MACH_OMAP3_CPS OMAP3_CPS 2751 +axar1500_receiver MACH_AXAR1500_RECEIVER AXAR1500_RECEIVER 2752 +wbd222 MACH_WBD222 WBD222 2753 +mt65xx MACH_MT65XX MT65XX 2754 +msm8x60_surf MACH_MSM8X60_SURF MSM8X60_SURF 2755 +msm8x60_sim MACH_MSM8X60_SIM MSM8X60_SIM 2756 +vmc300 MACH_VMC300 VMC300 2757 +tcc8000_sdk MACH_TCC8000_SDK TCC8000_SDK 2758 +nanos MACH_NANOS NANOS 2759 +stamp9g10 MACH_STAMP9G10 STAMP9G10 2760 +stamp9g45 MACH_STAMP9G45 STAMP9G45 2761 +h6053 MACH_H6053 H6053 2762 +smint01 MACH_SMINT01 SMINT01 2763 +prtlvt2 MACH_PRTLVT2 PRTLVT2 2764 From 73852e8151b7d7a529fbe019ab6d2d0c02d8f3f2 Mon Sep 17 00:00:00 2001 From: "Steven J. Magnani" Date: Tue, 16 Mar 2010 05:22:44 +0000 Subject: [PATCH 122/478] NET_DMA: free skbs periodically Under NET_DMA, data transfer can grind to a halt when userland issues a large read on a socket with a high RCVLOWAT (i.e., 512 KB for both). This appears to be because the NET_DMA design queues up lots of memcpy operations, but doesn't issue or wait for them (and thus free the associated skbs) until it is time for tcp_recvmesg() to return. The socket hangs when its TCP window goes to zero before enough data is available to satisfy the read. Periodically issue asynchronous memcpy operations, and free skbs for ones that have completed, to prevent sockets from going into zero-window mode. Signed-off-by: Steven J. Magnani Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 63 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index ae16f809e71..6afb6d8662b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1254,6 +1254,39 @@ static void tcp_prequeue_process(struct sock *sk) tp->ucopy.memory = 0; } +#ifdef CONFIG_NET_DMA +static void tcp_service_net_dma(struct sock *sk, bool wait) +{ + dma_cookie_t done, used; + dma_cookie_t last_issued; + struct tcp_sock *tp = tcp_sk(sk); + + if (!tp->ucopy.dma_chan) + return; + + last_issued = tp->ucopy.dma_cookie; + dma_async_memcpy_issue_pending(tp->ucopy.dma_chan); + + do { + if (dma_async_memcpy_complete(tp->ucopy.dma_chan, + last_issued, &done, + &used) == DMA_SUCCESS) { + /* Safe to free early-copied skbs now */ + __skb_queue_purge(&sk->sk_async_wait_queue); + break; + } else { + struct sk_buff *skb; + while ((skb = skb_peek(&sk->sk_async_wait_queue)) && + (dma_async_is_complete(skb->dma_cookie, done, + used) == DMA_SUCCESS)) { + __skb_dequeue(&sk->sk_async_wait_queue); + kfree_skb(skb); + } + } + } while (wait); +} +#endif + static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) { struct sk_buff *skb; @@ -1546,6 +1579,10 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* __ Set realtime policy in scheduler __ */ } +#ifdef CONFIG_NET_DMA + if (tp->ucopy.dma_chan) + dma_async_memcpy_issue_pending(tp->ucopy.dma_chan); +#endif if (copied >= target) { /* Do not sleep, just process backlog. */ release_sock(sk); @@ -1554,6 +1591,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, sk_wait_data(sk, &timeo); #ifdef CONFIG_NET_DMA + tcp_service_net_dma(sk, false); /* Don't block */ tp->ucopy.wakeup = 0; #endif @@ -1633,6 +1671,9 @@ do_prequeue: copied = -EFAULT; break; } + + dma_async_memcpy_issue_pending(tp->ucopy.dma_chan); + if ((offset + used) == skb->len) copied_early = 1; @@ -1702,27 +1743,9 @@ skip_copy: } #ifdef CONFIG_NET_DMA - if (tp->ucopy.dma_chan) { - dma_cookie_t done, used; + tcp_service_net_dma(sk, true); /* Wait for queue to drain */ + tp->ucopy.dma_chan = NULL; - dma_async_memcpy_issue_pending(tp->ucopy.dma_chan); - - while (dma_async_memcpy_complete(tp->ucopy.dma_chan, - tp->ucopy.dma_cookie, &done, - &used) == DMA_IN_PROGRESS) { - /* do partial cleanup of sk_async_wait_queue */ - while ((skb = skb_peek(&sk->sk_async_wait_queue)) && - (dma_async_is_complete(skb->dma_cookie, done, - used) == DMA_SUCCESS)) { - __skb_dequeue(&sk->sk_async_wait_queue); - kfree_skb(skb); - } - } - - /* Safe to free early-copied skbs now */ - __skb_queue_purge(&sk->sk_async_wait_queue); - tp->ucopy.dma_chan = NULL; - } if (tp->ucopy.pinned_list) { dma_unpin_iovec_pages(tp->ucopy.pinned_list); tp->ucopy.pinned_list = NULL; From 1a50307ba1826e4da0024e64b245ce4eadf7688a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 18 Mar 2010 14:24:42 +0000 Subject: [PATCH 123/478] netlink: fix NETLINK_RECV_NO_ENOBUFS in netlink_set_err() Currently, ENOBUFS errors are reported to the socket via netlink_set_err() even if NETLINK_RECV_NO_ENOBUFS is set. However, that should not happen. This fixes this problem and it changes the prototype of netlink_set_err() to return the number of sockets that have set the NETLINK_RECV_NO_ENOBUFS socket option. This return value is used in the next patch in these bugfix series. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- include/linux/netlink.h | 2 +- net/netlink/af_netlink.c | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index fde27c01732..6eaca5e1e8c 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -188,7 +188,7 @@ extern int netlink_has_listeners(struct sock *sk, unsigned int group); extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, __u32 group, gfp_t allocation); -extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code); +extern int netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code); extern int netlink_register_notifier(struct notifier_block *nb); extern int netlink_unregister_notifier(struct notifier_block *nb); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 320d0423a24..acbbae1e89b 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1093,6 +1093,7 @@ static inline int do_one_set_err(struct sock *sk, struct netlink_set_err_data *p) { struct netlink_sock *nlk = nlk_sk(sk); + int ret = 0; if (sk == p->exclude_sk) goto out; @@ -1104,10 +1105,15 @@ static inline int do_one_set_err(struct sock *sk, !test_bit(p->group - 1, nlk->groups)) goto out; + if (p->code == ENOBUFS && nlk->flags & NETLINK_RECV_NO_ENOBUFS) { + ret = 1; + goto out; + } + sk->sk_err = p->code; sk->sk_error_report(sk); out: - return 0; + return ret; } /** @@ -1116,12 +1122,16 @@ out: * @pid: the PID of a process that we want to skip (if any) * @groups: the broadcast group that will notice the error * @code: error code, must be negative (as usual in kernelspace) + * + * This function returns the number of broadcast listeners that have set the + * NETLINK_RECV_NO_ENOBUFS socket option. */ -void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) +int netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) { struct netlink_set_err_data info; struct hlist_node *node; struct sock *sk; + int ret = 0; info.exclude_sk = ssk; info.pid = pid; @@ -1132,9 +1142,10 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) read_lock(&nl_table_lock); sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) - do_one_set_err(sk, &info); + ret += do_one_set_err(sk, &info); read_unlock(&nl_table_lock); + return ret; } EXPORT_SYMBOL(netlink_set_err); From 37b7ef7203240b3aba577bb1ff6765fe15225976 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 16 Mar 2010 13:30:21 +0000 Subject: [PATCH 124/478] netfilter: ctnetlink: fix reliable event delivery if message building fails This patch fixes a bug that allows to lose events when reliable event delivery mode is used, ie. if NETLINK_BROADCAST_SEND_ERROR and NETLINK_RECV_NO_ENOBUFS socket options are set. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- include/linux/netfilter/nfnetlink.h | 2 +- net/netfilter/nf_conntrack_netlink.c | 4 +++- net/netfilter/nfnetlink.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 53923868c9b..361d6b5630e 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -76,7 +76,7 @@ extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); extern int nfnetlink_has_listeners(struct net *net, unsigned int group); extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo, gfp_t flags); -extern void nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error); +extern int nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error); extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags); extern void nfnl_lock(void); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 2b2af631d2b..569410a8595 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -582,7 +582,9 @@ nla_put_failure: nlmsg_failure: kfree_skb(skb); errout: - nfnetlink_set_err(net, 0, group, -ENOBUFS); + if (nfnetlink_set_err(net, 0, group, -ENOBUFS) > 0) + return -ENOBUFS; + return 0; } #endif /* CONFIG_NF_CONNTRACK_EVENTS */ diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 8eb0cc23ada..6afa3d52ea5 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -113,9 +113,9 @@ int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, } EXPORT_SYMBOL_GPL(nfnetlink_send); -void nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error) +int nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error) { - netlink_set_err(net->nfnl, pid, group, error); + return netlink_set_err(net->nfnl, pid, group, error); } EXPORT_SYMBOL_GPL(nfnetlink_set_err); From 978097c907b58a2d085bbf7632bee1a5a7e6f6ba Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 8 Mar 2010 15:27:53 -0800 Subject: [PATCH 125/478] ceph: implemented caps should always be superset of issued caps Added assertion, and cleared one case where the implemented caps were not following the issued caps. Signed-off-by: Yehuda Sadeh Signed-off-by: Sage Weil --- fs/ceph/caps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index db122bb357b..57d9b44a882 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2334,6 +2334,7 @@ static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, revoked_rdcache) reply = 2; /* send revoke ack in check_caps */ cap->issued = newcaps; + cap->implemented |= newcaps; } else if (cap->issued == newcaps) { dout("caps unchanged: %s -> %s\n", ceph_cap_string(cap->issued), ceph_cap_string(newcaps)); @@ -2346,6 +2347,7 @@ static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, * pending revocation */ wake = 1; } + BUG_ON(cap->issued & ~cap->implemented); spin_unlock(&inode->i_lock); if (writeback) From 052bb34af3bf8ae2001b9f03d884ba0def3e427c Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 9 Mar 2010 12:52:26 -0800 Subject: [PATCH 126/478] ceph: add missing locking to protect i_snap_realm_item during split All ci->i_snap_realm_item/realm->inodes_with_caps manipulation should be protected by realm->inodes_with_caps_lock. This bug would have only bit us in a rare race with a realm split (during some snap creations). Signed-off-by: Sage Weil --- fs/ceph/snap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index bf2a5f3846a..8a43bc8675e 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -818,7 +818,9 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc, * queued (again) by ceph_update_snap_trace() * below. Queue it _now_, under the old context. */ + spin_lock(&realm->inodes_with_caps_lock); list_del_init(&ci->i_snap_realm_item); + spin_unlock(&realm->inodes_with_caps_lock); spin_unlock(&inode->i_lock); ceph_queue_cap_snap(ci, From 8b218b8a4a65bf4e304ae8690cadb9100ef029c0 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 9 Mar 2010 12:59:08 -0800 Subject: [PATCH 127/478] ceph: fix inode removal from snap realm when racing with migration When an inode was dropped while being migrated between two MDSs, i_cap_exporting_issued was non-zero such that issue caps were non-zero and __ceph_is_any_caps(ci) was true. This prevented the inode from being removed from the snap realm, even as it was dropped from the cache. Fix this by dropping any residual i_snap_realm ref in destroy_inode. Signed-off-by: Sage Weil --- fs/ceph/inode.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 7abe1aed819..aca82d55cc5 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -378,6 +378,22 @@ void ceph_destroy_inode(struct inode *inode) ceph_queue_caps_release(inode); + /* + * we may still have a snap_realm reference if there are stray + * caps in i_cap_exporting_issued or i_snap_caps. + */ + if (ci->i_snap_realm) { + struct ceph_mds_client *mdsc = + &ceph_client(ci->vfs_inode.i_sb)->mdsc; + struct ceph_snap_realm *realm = ci->i_snap_realm; + + dout(" dropping residual ref to snap realm %p\n", realm); + spin_lock(&realm->inodes_with_caps_lock); + list_del_init(&ci->i_snap_realm_item); + spin_unlock(&realm->inodes_with_caps_lock); + ceph_put_snap_realm(mdsc, realm); + } + kfree(ci->i_symlink); while ((n = rb_first(&ci->i_fragtree)) != NULL) { frag = rb_entry(n, struct ceph_inode_frag, node); From 63733a0fc55cca74b1911769633dc5dfd1a45907 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 15 Mar 2010 15:47:22 -0700 Subject: [PATCH 128/478] ceph: fix authenticator timeout We were failing to reconnect to services due to an old authenticator, even though we had the new ticket, because we weren't properly retrying the connect handshake, because we were calling an old/incorrect helper that left in_base_pos incorrect. The result was a failure to reconnect to the OSD or MDS (with an authentication error) if the MDS restarted after the service had been up a few hours (long enough for the original authenticator to be invalid). This was only a problem if the AUTH_X authentication was enabled. Now that the 'negotiate' and 'connect' stages are fully separated, we should use the prepare_read_connect() helper instead, and remove the obsolete one. Signed-off-by: Sage Weil --- fs/ceph/messenger.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/fs/ceph/messenger.c b/fs/ceph/messenger.c index 781656a49bf..203c4359b54 100644 --- a/fs/ceph/messenger.c +++ b/fs/ceph/messenger.c @@ -830,13 +830,6 @@ static void prepare_read_connect(struct ceph_connection *con) con->in_base_pos = 0; } -static void prepare_read_connect_retry(struct ceph_connection *con) -{ - dout("prepare_read_connect_retry %p\n", con); - con->in_base_pos = strlen(CEPH_BANNER) + sizeof(con->actual_peer_addr) - + sizeof(con->peer_addr_for_me); -} - static void prepare_read_ack(struct ceph_connection *con) { dout("prepare_read_ack %p\n", con); @@ -1146,7 +1139,7 @@ static int process_connect(struct ceph_connection *con) } con->auth_retry = 1; prepare_write_connect(con->msgr, con, 0); - prepare_read_connect_retry(con); + prepare_read_connect(con); break; case CEPH_MSGR_TAG_RESETSESSION: From 807c86e2ceba8febe79b289d50cd0d5e0b0af917 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 15 Mar 2010 15:52:17 -0700 Subject: [PATCH 129/478] ceph: fix authenticator buffer size calculation The buffer size was incorrectly calculated for the ceph_x_encrypt() encapsulated ticket blob. Use a helper (with correct arithmetic) and BUG out if we were wrong. Signed-off-by: Sage Weil --- fs/ceph/auth_x.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/fs/ceph/auth_x.c b/fs/ceph/auth_x.c index f0318427b6d..96e7aaa7767 100644 --- a/fs/ceph/auth_x.c +++ b/fs/ceph/auth_x.c @@ -28,6 +28,12 @@ static int ceph_x_is_authenticated(struct ceph_auth_client *ac) return (ac->want_keys & xi->have_keys) == ac->want_keys; } +static int ceph_x_encrypt_buflen(int ilen) +{ + return sizeof(struct ceph_x_encrypt_header) + ilen + 16 + + sizeof(u32); +} + static int ceph_x_encrypt(struct ceph_crypto_key *secret, void *ibuf, int ilen, void *obuf, size_t olen) { @@ -242,7 +248,7 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac, struct ceph_x_ticket_handler *th, struct ceph_x_authorizer *au) { - int len; + int maxlen; struct ceph_x_authorize_a *msg_a; struct ceph_x_authorize_b msg_b; void *p, *end; @@ -253,15 +259,15 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac, dout("build_authorizer for %s %p\n", ceph_entity_type_name(th->service), au); - len = sizeof(*msg_a) + sizeof(msg_b) + sizeof(u32) + - ticket_blob_len + 16; - dout(" need len %d\n", len); - if (au->buf && au->buf->alloc_len < len) { + maxlen = sizeof(*msg_a) + sizeof(msg_b) + + ceph_x_encrypt_buflen(ticket_blob_len); + dout(" need len %d\n", maxlen); + if (au->buf && au->buf->alloc_len < maxlen) { ceph_buffer_put(au->buf); au->buf = NULL; } if (!au->buf) { - au->buf = ceph_buffer_new(len, GFP_NOFS); + au->buf = ceph_buffer_new(maxlen, GFP_NOFS); if (!au->buf) return -ENOMEM; } @@ -296,6 +302,7 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac, au->buf->vec.iov_len = p - au->buf->vec.iov_base; dout(" built authorizer nonce %llx len %d\n", au->nonce, (int)au->buf->vec.iov_len); + BUG_ON(au->buf->vec.iov_len > maxlen); return 0; out_buf: From 5b3dbb44ab40660a080d03585bd35f45b2890c49 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 15 Mar 2010 15:57:04 -0700 Subject: [PATCH 130/478] ceph: release old ticket_blob buffer Release the old ticket_blob buffer when we get an updated service ticket from the monitor. Previously these were getting leaked. Signed-off-by: Sage Weil --- fs/ceph/auth_x.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/ceph/auth_x.c b/fs/ceph/auth_x.c index 96e7aaa7767..33d3ad4dc45 100644 --- a/fs/ceph/auth_x.c +++ b/fs/ceph/auth_x.c @@ -156,6 +156,7 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, struct timespec validity; struct ceph_crypto_key old_key; void *tp, *tpend; + struct ceph_buffer *new_ticket_blob; ceph_decode_need(&p, end, sizeof(u32) + 1, bad); @@ -223,9 +224,12 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad); struct_v = ceph_decode_8(&tp); th->secret_id = ceph_decode_64(&tp); - ret = ceph_decode_buffer(&th->ticket_blob, &tp, tpend); + ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend); if (ret) goto out; + if (th->ticket_blob) + ceph_buffer_put(th->ticket_blob); + th->ticket_blob = new_ticket_blob; dout(" got ticket service %d (%s) secret_id %lld len %d\n", type, ceph_entity_type_name(type), th->secret_id, (int)th->ticket_blob->vec.iov_len); From 101545f6fef4a0a3ea8daf0b5b880df2c6a92a69 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 15 Mar 2010 14:12:58 -0700 Subject: [PATCH 131/478] Bluetooth: Fix potential bad memory access with sysfs files When creating a high number of Bluetooth sockets (L2CAP, SCO and RFCOMM) it is possible to scribble repeatedly on arbitrary pages of memory. Ensure that the content of these sysfs files is always less than one page. Even if this means truncating. The files in question are scheduled to be moved over to debugfs in the future anyway. Based on initial patches from Neil Brown and Linus Torvalds Reported-by: Neil Brown Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 10 +++++++++- net/bluetooth/rfcomm/core.c | 13 ++++++++++++- net/bluetooth/rfcomm/sock.c | 11 ++++++++++- net/bluetooth/sco.c | 11 ++++++++++- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 4db7ae2fe07..27551820741 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3944,16 +3944,24 @@ static ssize_t l2cap_sysfs_show(struct class *dev, struct sock *sk; struct hlist_node *node; char *str = buf; + int size = PAGE_SIZE; read_lock_bh(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { struct l2cap_pinfo *pi = l2cap_pi(sk); + int len; - str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n", + len = snprintf(str, size, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state, __le16_to_cpu(pi->psm), pi->scid, pi->dcid, pi->imtu, pi->omtu, pi->sec_level); + + size -= len; + if (size <= 0) + break; + + str += len; } read_unlock_bh(&l2cap_sk_list.lock); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index db8a68e1a5b..cf164073269 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -2105,6 +2105,7 @@ static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, struct rfcomm_session *s; struct list_head *pp, *p; char *str = buf; + int size = PAGE_SIZE; rfcomm_lock(); @@ -2113,11 +2114,21 @@ static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, list_for_each(pp, &s->dlcs) { struct sock *sk = s->sock->sk; struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list); + int len; - str += sprintf(str, "%s %s %ld %d %d %d %d\n", + len = snprintf(str, size, "%s %s %ld %d %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits); + + size -= len; + if (size <= 0) + break; + + str += len; } + + if (size <= 0) + break; } rfcomm_unlock(); diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index ca87d6ac6a2..8d0ee0b8a6b 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -1068,13 +1068,22 @@ static ssize_t rfcomm_sock_sysfs_show(struct class *dev, struct sock *sk; struct hlist_node *node; char *str = buf; + int size = PAGE_SIZE; read_lock_bh(&rfcomm_sk_list.lock); sk_for_each(sk, node, &rfcomm_sk_list.head) { - str += sprintf(str, "%s %s %d %d\n", + int len; + + len = snprintf(str, size, "%s %s %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state, rfcomm_pi(sk)->channel); + + size -= len; + if (size <= 0) + break; + + str += len; } read_unlock_bh(&rfcomm_sk_list.lock); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index f93b939539b..967a75175c6 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -960,13 +960,22 @@ static ssize_t sco_sysfs_show(struct class *dev, struct sock *sk; struct hlist_node *node; char *str = buf; + int size = PAGE_SIZE; read_lock_bh(&sco_sk_list.lock); sk_for_each(sk, node, &sco_sk_list.head) { - str += sprintf(str, "%s %s %d\n", + int len; + + len = snprintf(str, size, "%s %s %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state); + + size -= len; + if (size <= 0) + break; + + str += len; } read_unlock_bh(&sco_sk_list.lock); From aef7d97cc604309b66f6f45cce02cd734934cd4e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 21 Mar 2010 05:27:45 +0100 Subject: [PATCH 132/478] Bluetooth: Convert debug files to actually use debugfs instead of sysfs Some of the debug files ended up wrongly in sysfs, because at that point of time, debugfs didn't exist. Convert these files to use debugfs and also seq_file. This patch converts all of these files at once and then removes the exported symbol for the Bluetooth sysfs class. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/bluetooth.h | 2 +- net/bluetooth/hci_sysfs.c | 3 +- net/bluetooth/l2cap.c | 51 +++++++++++++++++------------- net/bluetooth/rfcomm/core.c | 52 +++++++++++++++++-------------- net/bluetooth/rfcomm/sock.c | 47 ++++++++++++++++------------ net/bluetooth/sco.c | 47 +++++++++++++++------------- 6 files changed, 114 insertions(+), 88 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 04a6908e38d..ff77e8f882f 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -176,6 +176,6 @@ extern void hci_sock_cleanup(void); extern int bt_sysfs_init(void); extern void bt_sysfs_cleanup(void); -extern struct class *bt_class; +extern struct dentry *bt_debugfs; #endif /* __BLUETOOTH_H */ diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index cafb55b0cea..05fd125f74f 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -8,8 +8,7 @@ #include #include -struct class *bt_class = NULL; -EXPORT_SYMBOL_GPL(bt_class); +static struct class *bt_class; struct dentry *bt_debugfs = NULL; EXPORT_SYMBOL_GPL(bt_debugfs); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 27551820741..43e17f7d7ec 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include #include @@ -3937,39 +3939,42 @@ drop: return 0; } -static ssize_t l2cap_sysfs_show(struct class *dev, - struct class_attribute *attr, - char *buf) +static int l2cap_debugfs_show(struct seq_file *f, void *p) { struct sock *sk; struct hlist_node *node; - char *str = buf; - int size = PAGE_SIZE; read_lock_bh(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { struct l2cap_pinfo *pi = l2cap_pi(sk); - int len; - len = snprintf(str, size, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, __le16_to_cpu(pi->psm), pi->scid, - pi->dcid, pi->imtu, pi->omtu, pi->sec_level); - - size -= len; - if (size <= 0) - break; - - str += len; + seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n", + batostr(&bt_sk(sk)->src), + batostr(&bt_sk(sk)->dst), + sk->sk_state, __le16_to_cpu(pi->psm), + pi->scid, pi->dcid, + pi->imtu, pi->omtu, pi->sec_level); } read_unlock_bh(&l2cap_sk_list.lock); - return str - buf; + return 0; } -static CLASS_ATTR(l2cap, S_IRUGO, l2cap_sysfs_show, NULL); +static int l2cap_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, l2cap_debugfs_show, inode->i_private); +} + +static const struct file_operations l2cap_debugfs_fops = { + .open = l2cap_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct dentry *l2cap_debugfs; static const struct proto_ops l2cap_sock_ops = { .family = PF_BLUETOOTH, @@ -4029,8 +4034,12 @@ static int __init l2cap_init(void) goto error; } - if (class_create_file(bt_class, &class_attr_l2cap) < 0) - BT_ERR("Failed to create L2CAP info file"); + if (bt_debugfs) { + l2cap_debugfs = debugfs_create_file("l2cap", 0444, + bt_debugfs, NULL, &l2cap_debugfs_fops); + if (!l2cap_debugfs) + BT_ERR("Failed to create L2CAP debug file"); + } BT_INFO("L2CAP ver %s", VERSION); BT_INFO("L2CAP socket layer initialized"); @@ -4044,7 +4053,7 @@ error: static void __exit l2cap_exit(void) { - class_remove_file(bt_class, &class_attr_l2cap); + debugfs_remove(l2cap_debugfs); if (bt_sock_unregister(BTPROTO_L2CAP) < 0) BT_ERR("L2CAP socket unregistration failed"); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index cf164073269..13f114e8b0f 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -2098,14 +2100,10 @@ static struct hci_cb rfcomm_cb = { .security_cfm = rfcomm_security_cfm }; -static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, - struct class_attribute *attr, - char *buf) +static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x) { struct rfcomm_session *s; struct list_head *pp, *p; - char *str = buf; - int size = PAGE_SIZE; rfcomm_lock(); @@ -2114,29 +2112,33 @@ static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, list_for_each(pp, &s->dlcs) { struct sock *sk = s->sock->sk; struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list); - int len; - len = snprintf(str, size, "%s %s %ld %d %d %d %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits); - - size -= len; - if (size <= 0) - break; - - str += len; + seq_printf(f, "%s %s %ld %d %d %d %d\n", + batostr(&bt_sk(sk)->src), + batostr(&bt_sk(sk)->dst), + d->state, d->dlci, d->mtu, + d->rx_credits, d->tx_credits); } - - if (size <= 0) - break; } rfcomm_unlock(); - return (str - buf); + return 0; } -static CLASS_ATTR(rfcomm_dlc, S_IRUGO, rfcomm_dlc_sysfs_show, NULL); +static int rfcomm_dlc_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, rfcomm_dlc_debugfs_show, inode->i_private); +} + +static const struct file_operations rfcomm_dlc_debugfs_fops = { + .open = rfcomm_dlc_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct dentry *rfcomm_dlc_debugfs; /* ---- Initialization ---- */ static int __init rfcomm_init(void) @@ -2153,8 +2155,12 @@ static int __init rfcomm_init(void) goto unregister; } - if (class_create_file(bt_class, &class_attr_rfcomm_dlc) < 0) - BT_ERR("Failed to create RFCOMM info file"); + if (bt_debugfs) { + rfcomm_dlc_debugfs = debugfs_create_file("rfcomm_dlc", 0444, + bt_debugfs, NULL, &rfcomm_dlc_debugfs_fops); + if (!rfcomm_dlc_debugfs) + BT_ERR("Failed to create RFCOMM debug file"); + } err = rfcomm_init_ttys(); if (err < 0) @@ -2182,7 +2188,7 @@ unregister: static void __exit rfcomm_exit(void) { - class_remove_file(bt_class, &class_attr_rfcomm_dlc); + debugfs_remove(rfcomm_dlc_debugfs); hci_unregister_cb(&rfcomm_cb); diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 8d0ee0b8a6b..7f439765403 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include @@ -1061,37 +1063,38 @@ done: return result; } -static ssize_t rfcomm_sock_sysfs_show(struct class *dev, - struct class_attribute *attr, - char *buf) +static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p) { struct sock *sk; struct hlist_node *node; - char *str = buf; - int size = PAGE_SIZE; read_lock_bh(&rfcomm_sk_list.lock); sk_for_each(sk, node, &rfcomm_sk_list.head) { - int len; - - len = snprintf(str, size, "%s %s %d %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), + seq_printf(f, "%s %s %d %d\n", + batostr(&bt_sk(sk)->src), + batostr(&bt_sk(sk)->dst), sk->sk_state, rfcomm_pi(sk)->channel); - - size -= len; - if (size <= 0) - break; - - str += len; } read_unlock_bh(&rfcomm_sk_list.lock); - return (str - buf); + return 0; } -static CLASS_ATTR(rfcomm, S_IRUGO, rfcomm_sock_sysfs_show, NULL); +static int rfcomm_sock_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, rfcomm_sock_debugfs_show, inode->i_private); +} + +static const struct file_operations rfcomm_sock_debugfs_fops = { + .open = rfcomm_sock_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct dentry *rfcomm_sock_debugfs; static const struct proto_ops rfcomm_sock_ops = { .family = PF_BLUETOOTH, @@ -1131,8 +1134,12 @@ int __init rfcomm_init_sockets(void) if (err < 0) goto error; - if (class_create_file(bt_class, &class_attr_rfcomm) < 0) - BT_ERR("Failed to create RFCOMM info file"); + if (bt_debugfs) { + rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444, + bt_debugfs, NULL, &rfcomm_sock_debugfs_fops); + if (!rfcomm_sock_debugfs) + BT_ERR("Failed to create RFCOMM debug file"); + } BT_INFO("RFCOMM socket layer initialized"); @@ -1146,7 +1153,7 @@ error: void rfcomm_cleanup_sockets(void) { - class_remove_file(bt_class, &class_attr_rfcomm); + debugfs_remove(rfcomm_sock_debugfs); if (bt_sock_unregister(BTPROTO_RFCOMM) < 0) BT_ERR("RFCOMM socket layer unregistration failed"); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 967a75175c6..e5b16b76b22 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include @@ -953,37 +955,36 @@ drop: return 0; } -static ssize_t sco_sysfs_show(struct class *dev, - struct class_attribute *attr, - char *buf) +static int sco_debugfs_show(struct seq_file *f, void *p) { struct sock *sk; struct hlist_node *node; - char *str = buf; - int size = PAGE_SIZE; read_lock_bh(&sco_sk_list.lock); sk_for_each(sk, node, &sco_sk_list.head) { - int len; - - len = snprintf(str, size, "%s %s %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state); - - size -= len; - if (size <= 0) - break; - - str += len; + seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src), + batostr(&bt_sk(sk)->dst), sk->sk_state); } read_unlock_bh(&sco_sk_list.lock); - return (str - buf); + return 0; } -static CLASS_ATTR(sco, S_IRUGO, sco_sysfs_show, NULL); +static int sco_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, sco_debugfs_show, inode->i_private); +} + +static const struct file_operations sco_debugfs_fops = { + .open = sco_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct dentry *sco_debugfs; static const struct proto_ops sco_sock_ops = { .family = PF_BLUETOOTH, @@ -1041,8 +1042,12 @@ static int __init sco_init(void) goto error; } - if (class_create_file(bt_class, &class_attr_sco) < 0) - BT_ERR("Failed to create SCO info file"); + if (bt_debugfs) { + sco_debugfs = debugfs_create_file("sco", 0444, + bt_debugfs, NULL, &sco_debugfs_fops); + if (!sco_debugfs) + BT_ERR("Failed to create SCO debug file"); + } BT_INFO("SCO (Voice Link) ver %s", VERSION); BT_INFO("SCO socket layer initialized"); @@ -1056,7 +1061,7 @@ error: static void __exit sco_exit(void) { - class_remove_file(bt_class, &class_attr_sco); + debugfs_remove(sco_debugfs); if (bt_sock_unregister(BTPROTO_SCO) < 0) BT_ERR("SCO socket unregistration failed"); From c2c77ec83bdad17fb688557b5b3fdc36661dd1c6 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 19 Mar 2010 10:26:28 +0200 Subject: [PATCH 133/478] Bluetooth: Fix kernel crash on L2CAP stress tests Added very simple check that req buffer has enough space to fit configuration parameters. Shall be enough to reject packets with configuration size more than req buffer. Crash trace below [ 6069.659393] Unable to handle kernel paging request at virtual address 02000205 [ 6069.673034] Internal error: Oops: 805 [#1] PREEMPT ... [ 6069.727172] PC is at l2cap_add_conf_opt+0x70/0xf0 [l2cap] [ 6069.732604] LR is at l2cap_recv_frame+0x1350/0x2e78 [l2cap] ... [ 6070.030303] Backtrace: [ 6070.032806] [] (l2cap_add_conf_opt+0x0/0xf0 [l2cap]) from [] (l2cap_recv_frame+0x1350/0x2e78 [l2cap]) [ 6070.043823] r8:dc5d3100 r7:df2a91d6 r6:00000001 r5:df2a8000 r4:00000200 [ 6070.050659] [] (l2cap_recv_frame+0x0/0x2e78 [l2cap]) from [] (l2cap_recv_acldata+0x2bc/0x350 [l2cap]) [ 6070.061798] [] (l2cap_recv_acldata+0x0/0x350 [l2cap]) from [] (hci_rx_task+0x244/0x478 [bluetooth]) [ 6070.072631] r6:dc647700 r5:00000001 r4:df2ab740 [ 6070.077362] [] (hci_rx_task+0x0/0x478 [bluetooth]) from [] (tasklet_action+0x78/0xd8) [ 6070.087005] [] (tasklet_action+0x0/0xd8) from [] Signed-off-by: Andrei Emeltchenko Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 43e17f7d7ec..7794a2e2adc 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2832,6 +2832,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr int len = cmd->len - sizeof(*rsp); char req[64]; + if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { + l2cap_send_disconn_req(conn, sk); + goto done; + } + /* throw out any old stored conf requests */ result = L2CAP_CONF_SUCCESS; len = l2cap_parse_conf_rsp(sk, rsp->data, From fc8aa7b16a5fcfe9c6d0be9bb587f1fcedd9145f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 18 Mar 2010 07:53:11 +0100 Subject: [PATCH 134/478] sound/oss/vidc.c: change the field used with DMA_ACTIVE The constant DMA_ACTIVE is defined with the dma_buffparams structure rather than with the audio_operations structure. Takashi Iwai suggested that the dmap_out field of the audio_operations structure should be used instead. This is not tested. Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/oss/vidc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c index 725fef0f59a..a4127bab923 100644 --- a/sound/oss/vidc.c +++ b/sound/oss/vidc.c @@ -363,13 +363,13 @@ static void vidc_audio_trigger(int dev, int enable_bits) struct audio_operations *adev = audio_devs[dev]; if (enable_bits & PCM_ENABLE_OUTPUT) { - if (!(adev->flags & DMA_ACTIVE)) { + if (!(adev->dmap_out->flags & DMA_ACTIVE)) { unsigned long flags; local_irq_save(flags); /* prevent recusion */ - adev->flags |= DMA_ACTIVE; + adev->dmap_out->flags |= DMA_ACTIVE; dma_interrupt = vidc_audio_dma_interrupt; vidc_sound_dma_irq(0, NULL); From e3d2530a6cea80987f77b75d8784a00f3aaf22ff Mon Sep 17 00:00:00 2001 From: Kunal Gangakhedkar Date: Sat, 20 Mar 2010 23:08:01 +0530 Subject: [PATCH 135/478] ALSA: hda - Add PCI quirk for HP dv6-1110ax. Adding this PCI quirk fixes the board config detection. This also fixes jack sensing by using "hp_detect=1" via properly detected board config. Signed-off-by: Kunal Gangakhedkar Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8c416bb18a5..c4be3fab94e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1730,6 +1730,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "HP HDX", STAC_HP_HDX), /* HDX16 */ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3620, "HP dv6", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3061, + "HP dv6", STAC_HP_DV5), /* HP dv6-1110ax */ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010, "HP", STAC_HP_DV5), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, From cdead7cf12896c0e50a8be2e52de52c364603095 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 19 Mar 2010 15:36:22 -0400 Subject: [PATCH 136/478] SUNRPC: Fix a potential memory leak in auth_gss The function alloc_enc_pages() currently fails to release the pointer rqstp->rq_enc_pages in the error path. Signed-off-by: Trond Myklebust Acked-by: J. Bruce Fields Cc: stable@kernel.org --- net/sunrpc/auth_gss/auth_gss.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 0cfccc2a029..c389ccf6437 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -1280,9 +1280,8 @@ alloc_enc_pages(struct rpc_rqst *rqstp) rqstp->rq_release_snd_buf = priv_release_snd_buf; return 0; out_free: - for (i--; i >= 0; i--) { - __free_page(rqstp->rq_enc_pages[i]); - } + rqstp->rq_enc_pages_num = i; + priv_release_snd_buf(rqstp); out: return -EAGAIN; } From 8c2eb4805d422bdbf60ba00ff233c794d23c3c00 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 19 Mar 2010 10:28:02 +0000 Subject: [PATCH 137/478] softlockup: Stop spurious softlockup messages due to overflow Ensure additions on touch_ts do not overflow. This can occur when the top 32 bits of the TSC reach 0xffffffff causing additions to touch_ts to overflow and this in turn generates spurious softlockup warnings. Signed-off-by: Colin Ian King Cc: Peter Zijlstra Cc: Eric Dumazet Cc: LKML-Reference: <1268994482.1798.6.camel@lenovo> Signed-off-by: Ingo Molnar --- kernel/softlockup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/softlockup.c b/kernel/softlockup.c index 0d4c7898ab8..4b493f67dcb 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c @@ -155,11 +155,11 @@ void softlockup_tick(void) * Wake up the high-prio watchdog task twice per * threshold timespan. */ - if (now > touch_ts + softlockup_thresh/2) + if (time_after(now - softlockup_thresh/2, touch_ts)) wake_up_process(per_cpu(softlockup_watchdog, this_cpu)); /* Warn about unreasonable delays: */ - if (now <= (touch_ts + softlockup_thresh)) + if (time_before_eq(now - softlockup_thresh, touch_ts)) return; per_cpu(softlockup_print_ts, this_cpu) = touch_ts; From 634a4b2038a6eba4c211fb906fa2f6ec9a4bbfc7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 21 Mar 2010 18:01:05 -0700 Subject: [PATCH 138/478] net: suppress lockdep-RCU false positive in FIB trie. Allow fib_find_node() to be called either under rcu_read_lock() protection or with RTNL held. Signed-off-by: Paul E. McKenney Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/fib_trie.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index af5d8979286..01ef8ba9025 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -961,7 +961,9 @@ fib_find_node(struct trie *t, u32 key) struct node *n; pos = 0; - n = rcu_dereference(t->trie); + n = rcu_dereference_check(t->trie, + rcu_read_lock_held() || + lockdep_rtnl_is_held()); while (n != NULL && NODE_TYPE(n) == T_TNODE) { tn = (struct tnode *) n; From 5e016cbf6cffd4a53b7922e0c91b775399d7fe47 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 21 Mar 2010 20:55:13 -0700 Subject: [PATCH 139/478] ipv4: Don't drop redirected route cache entry unless PTMU actually expired TCP sessions over IPv4 can get stuck if routers between endpoints do not fragment packets but implement PMTU instead, and we are using those routers because of an ICMP redirect. Setup is as follows MTU1 MTU2 MTU1 A--------B------C------D with MTU1 > MTU2. A and D are endpoints, B and C are routers. B and C implement PMTU and drop packets larger than MTU2 (for example because DF is set on all packets). TCP sessions are initiated between A and D. There is packet loss between A and D, causing frequent TCP retransmits. After the number of retransmits on a TCP session reaches tcp_retries1, tcp calls dst_negative_advice() prior to each retransmit. This results in route cache entries for the peer to be deleted in ipv4_negative_advice() if the Path MTU is set. If the outstanding data on an affected TCP session is larger than MTU2, packets sent from the endpoints will be dropped by B or C, and ICMP NEEDFRAG will be returned. A and D receive NEEDFRAG messages and update PMTU. Before the next retransmit, tcp will again call dst_negative_advice(), causing the route cache entry (with correct PMTU) to be deleted. The retransmitted packet will be larger than MTU2, causing it to be dropped again. This sequence repeats until the TCP session aborts or is terminated. Problem is fixed by removing redirected route cache entries in ipv4_negative_advice() only if the PMTU is expired. Signed-off-by: Guenter Roeck Signed-off-by: David S. Miller --- net/ipv4/route.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 32d396196df..54fd68c14c8 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1510,7 +1510,8 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) ip_rt_put(rt); ret = NULL; } else if ((rt->rt_flags & RTCF_REDIRECTED) || - rt->u.dst.expires) { + (rt->u.dst.expires && + time_after_eq(jiffies, rt->u.dst.expires))) { unsigned hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src, rt->fl.oif, rt_genid(dev_net(dst->dev))); From 2a8ac187e03027a958b289dd8701ca9c013ab096 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 8 Mar 2010 17:44:19 +0000 Subject: [PATCH 140/478] [ARM] pxa: fix for variables in uncompress.h being discarded Due to commit: 5de813b ARM: Eliminate decompressor -Dstatic= PIC hack The data section will be discarded for the decompressor, thus move the static variables into BSS section by initializing them at run time. Signed-off-by: Jonathan Cameron Signed-off-by: Eric Miao --- arch/arm/mach-pxa/include/mach/uncompress.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-pxa/include/mach/uncompress.h b/arch/arm/mach-pxa/include/mach/uncompress.h index 5ef91d9d17e..759b851ec98 100644 --- a/arch/arm/mach-pxa/include/mach/uncompress.h +++ b/arch/arm/mach-pxa/include/mach/uncompress.h @@ -16,9 +16,9 @@ #define BTUART_BASE (0x40200000) #define STUART_BASE (0x40700000) -static unsigned long uart_base = FFUART_BASE; -static unsigned int uart_shift = 2; -static unsigned int uart_is_pxa = 1; +static unsigned long uart_base; +static unsigned int uart_shift; +static unsigned int uart_is_pxa; static inline unsigned char uart_read(int offset) { @@ -56,6 +56,11 @@ static inline void flush(void) static inline void arch_decomp_setup(void) { + /* initialize to default */ + uart_base = FFUART_BASE; + uart_shift = 2; + uart_is_pxa = 1; + if (machine_is_littleton() || machine_is_intelmote2() || machine_is_csb726() || machine_is_stargate2() || machine_is_cm_x300() || machine_is_balloon3()) From 7471f46d74e0e2a668f4bc085ef486b1079b3466 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Mon, 22 Mar 2010 09:39:58 +0800 Subject: [PATCH 141/478] [ARM] mmp: fix for variables in uncompress.h being discarded Due to commit: 5de813b ARM: Eliminate decompressor -Dstatic= PIC hack The data section will be discarded for the decompressor, thus move the static variables into BSS section by initializing them at run time. Reported-by: Jonathan Cameron Signed-off-by: Eric Miao --- arch/arm/mach-mmp/include/mach/uncompress.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-mmp/include/mach/uncompress.h b/arch/arm/mach-mmp/include/mach/uncompress.h index a7dcc530721..85bd8a2d84b 100644 --- a/arch/arm/mach-mmp/include/mach/uncompress.h +++ b/arch/arm/mach-mmp/include/mach/uncompress.h @@ -14,7 +14,7 @@ #define UART2_BASE (APB_PHYS_BASE + 0x17000) #define UART3_BASE (APB_PHYS_BASE + 0x18000) -static volatile unsigned long *UART = (unsigned long *)UART2_BASE; +static volatile unsigned long *UART; static inline void putc(char c) { @@ -37,6 +37,9 @@ static inline void flush(void) static inline void arch_decomp_setup(void) { + /* default to UART2 */ + UART = (unsigned long *)UART2_BASE; + if (machine_is_avengers_lite()) UART = (unsigned long *)UART3_BASE; } From ef80936f99ce558a470c5379040abd0ece52c2ff Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 7 Mar 2010 21:59:16 +0000 Subject: [PATCH 142/478] [ARM] pxa: remove spi cs gpio direction to avoid clash with driver Signed-off-by: Jonathan Cameron Signed-off-by: Eric Miao --- arch/arm/mach-pxa/imote2.c | 4 ---- arch/arm/mach-pxa/stargate2.c | 5 ----- 2 files changed, 9 deletions(-) diff --git a/arch/arm/mach-pxa/imote2.c b/arch/arm/mach-pxa/imote2.c index b2f878bd460..5161dca8ccc 100644 --- a/arch/arm/mach-pxa/imote2.c +++ b/arch/arm/mach-pxa/imote2.c @@ -559,10 +559,6 @@ static void __init imote2_init(void) pxa_set_btuart_info(NULL); pxa_set_stuart_info(NULL); - /* SPI chip select directions - all other directions should - * be handled by drivers.*/ - gpio_direction_output(37, 0); - platform_add_devices(imote2_devices, ARRAY_SIZE(imote2_devices)); pxa2xx_set_spi_info(1, &pxa_ssp_master_0_info); diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c index a98a434f011..2041eb1d90b 100644 --- a/arch/arm/mach-pxa/stargate2.c +++ b/arch/arm/mach-pxa/stargate2.c @@ -764,11 +764,6 @@ static void __init stargate2_init(void) pxa_set_btuart_info(NULL); pxa_set_stuart_info(NULL); - /* spi chip selects */ - gpio_direction_output(37, 0); - gpio_direction_output(24, 0); - gpio_direction_output(39, 0); - platform_add_devices(ARRAY_AND_SIZE(stargate2_devices)); pxa2xx_set_spi_info(1, &pxa_ssp_master_0_info); From 1fe2b6b527779ca966bc285dc27f84835bc1591a Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Tue, 9 Mar 2010 11:04:44 +0800 Subject: [PATCH 143/478] [ARM] pxa: remove unnecessary 'select FB_W100' from some platforms Reported-by: Jonathan Cameron Signed-off-by: Eric Miao --- arch/arm/mach-pxa/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 38fbd0a0e40..c5b2f0abf45 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -272,7 +272,6 @@ config MACH_H5000 config MACH_HIMALAYA bool "HTC Himalaya Support" select CPU_PXA26x - select FB_W100 config MACH_MAGICIAN bool "Enable HTC Magician Support" @@ -547,7 +546,6 @@ config MACH_E740 bool "Toshiba e740" default y depends on ARCH_PXA_ESERIES - select FB_W100 help Say Y here if you intend to run this kernel on a Toshiba e740 family PDA. @@ -556,7 +554,6 @@ config MACH_E750 bool "Toshiba e750" default y depends on ARCH_PXA_ESERIES - select FB_W100 help Say Y here if you intend to run this kernel on a Toshiba e750 family PDA. @@ -573,7 +570,6 @@ config MACH_E800 bool "Toshiba e800" default y depends on ARCH_PXA_ESERIES - select FB_W100 help Say Y here if you intend to run this kernel on a Toshiba e800 family PDA. From 6533be390b1210285854fb2fc7ea80c0ada60b13 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Tue, 9 Mar 2010 10:34:27 +0800 Subject: [PATCH 144/478] [ARM] pxa/sharpsl: add dependency of max1111 driver to sharpsl_pm sharpsl_pm.c actually depends on max1111 driver being built-in when not using legacy ssp code. Reported-by: Jonathan Cameron Signed-off-by: Eric Miao --- arch/arm/mach-pxa/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index c5b2f0abf45..5b6ee46fa7f 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -453,6 +453,13 @@ config PXA_SHARPSL config SHARPSL_PM bool select APM_EMULATION + select SHARPSL_PM_MAX1111 + +config SHARPSL_PM_MAX1111 + bool + depends on !CORGI_SSP_DEPRECATED + select HWMON + select SENSORS_MAX1111 config CORGI_SSP_DEPRECATED bool From 1b0d76cb9d5a65567230097a2512046f09f30523 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 22 Mar 2010 10:33:58 +0800 Subject: [PATCH 145/478] [ARM] locomo: fix SPI register offset The locomo spi registers are all defined in locomo.h as offsets from the first spi register LOCOMO_SPI (0x60), which is itself an offset from the locomo base address. To correctly access these registers LOCOMO_SPI must always be included in the address calculation. There are two places in locomo.c where this is not done. The first one, in locomo_suspend, actually results in a write to LOCOMO_ST instead of LOCOMO_SPICT. The second is in __locomo_probe and results in a write to LOCOMO_MCSX2 instead of LOCOMO_SPIIE. Fix these by including LOCOMO_SPI in the calculation. Signed-off-by: H Hartley Sweeten Signed-off-by: Eric Miao --- arch/arm/common/locomo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 90ae00b631c..4f9ccf60aac 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -290,7 +290,7 @@ static int locomo_suspend(struct platform_device *dev, pm_message_t state) save->LCM_GPO = locomo_readl(lchip->base + LOCOMO_GPO); /* GPIO */ locomo_writel(0x00, lchip->base + LOCOMO_GPO); save->LCM_SPICT = locomo_readl(lchip->base + LOCOMO_SPI + LOCOMO_SPICT); /* SPI */ - locomo_writel(0x40, lchip->base + LOCOMO_SPICT); + locomo_writel(0x40, lchip->base + LOCOMO_SPI + LOCOMO_SPICT); save->LCM_GPE = locomo_readl(lchip->base + LOCOMO_GPE); /* GPIO */ locomo_writel(0x00, lchip->base + LOCOMO_GPE); save->LCM_ASD = locomo_readl(lchip->base + LOCOMO_ASD); /* ADSTART */ @@ -418,7 +418,7 @@ __locomo_probe(struct device *me, struct resource *mem, int irq) /* Longtime timer */ locomo_writel(0, lchip->base + LOCOMO_LTINT); /* SPI */ - locomo_writel(0, lchip->base + LOCOMO_SPIIE); + locomo_writel(0, lchip->base + LOCOMO_SPI + LOCOMO_SPIIE); locomo_writel(6 + 8 + 320 + 30 - 10, lchip->base + LOCOMO_ASD); r = locomo_readl(lchip->base + LOCOMO_ASD); From c8c3dcb9df8025ed48f8b14bf4b8a77801d88758 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 22 Mar 2010 11:09:20 +0800 Subject: [PATCH 146/478] [ARM] locomo: fix unpaired spin_lock_irqsave The function locomo_m62332_senddata sends a three byte i2c message to a M62332 DAC. This entire function is guarded with a spin_lock_irqsave at the start of the function and a spin_unlock_irqrestore at the end. As each byte is transferred, the i2c ACK from the DAC is checked. Currently, if the ACK is missing the function simply returns without the unlock. It also leaves the i2c bus in an invalid state since the last byte transferred did not have a "stop" condition and leave the bus idle. Fix this by adding an exit path using goto. Signed-off-by: H Hartley Sweeten Signed-off-by: Eric Miao --- arch/arm/common/locomo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 4f9ccf60aac..9dff07c80dd 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -707,7 +707,7 @@ void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ printk(KERN_WARNING "locomo: m62332_senddata Error 1\n"); - return; + goto out; } /* Send Sub address (LSB is channel select) */ @@ -735,7 +735,7 @@ void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ printk(KERN_WARNING "locomo: m62332_senddata Error 2\n"); - return; + goto out; } /* Send DAC data */ @@ -760,9 +760,9 @@ void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ printk(KERN_WARNING "locomo: m62332_senddata Error 3\n"); - return; } +out: /* stop */ r = locomo_readl(mapbase + LOCOMO_DAC); r &= ~(LOCOMO_DAC_SCLOEB); From af089f517a1fea0af2053f105c9360df614be07c Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Mon, 22 Mar 2010 11:51:05 +0800 Subject: [PATCH 147/478] [ARM] pxa/raumfeld: remove duplicated #include Remove duplicated #include('s) in arch/arm/mach-pxa/raumfeld.c Signed-off-by: Huang Weiyi Signed-off-by: Eric Miao --- arch/arm/mach-pxa/raumfeld.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 3184bdc1452..9d23f690444 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -37,8 +37,6 @@ #include #include #include -#include -#include #include #include #include From fe3ebaad3229c5e842e8b24cf2a24d7049a6481c Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 18 Mar 2010 19:37:29 +0100 Subject: [PATCH 148/478] [ARM] pxa/raumfeld: fix button name This fixes a warning when booting 2.6.34-rc2: [ 26.619814] ------------[ cut here ]------------ [ 26.624604] WARNING: at fs/proc/generic.c:316 __xlate_proc_name+0xac/0xc0() [ 26.631555] name 'on/off button' [ 26.634753] Modules linked in: Signed-off-by: Daniel Mack Cc: Sven Neumann Signed-off-by: Eric Miao --- arch/arm/mach-pxa/raumfeld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 9d23f690444..44bb675e47f 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -442,7 +442,7 @@ static struct gpio_keys_button gpio_keys_button[] = { .active_low = 0, .wakeup = 0, .debounce_interval = 5, /* ms */ - .desc = "on/off button", + .desc = "on_off button", }, }; From 9bf35c8dddd56f7f247a27346f74f5adc18071f4 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Sun, 21 Mar 2010 21:19:02 -0700 Subject: [PATCH 149/478] if_tunnel.h: add missing ams/byteorder.h include When compiling userspace application which includes if_tunnel.h and uses GRE_* defines you will get undefined reference to __cpu_to_be16. Fix this by adding missing #include Cc: stable@kernel.org Signed-off-by: Paulius Zaleckas Signed-off-by: David S. Miller --- include/linux/if_tunnel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 1822d635be6..16b92d008be 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -2,6 +2,7 @@ #define _IF_TUNNEL_H_ #include +#include #ifdef __KERNEL__ #include From 243aad830e8a4cdda261626fbaeddde16b08d04a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Sat, 20 Mar 2010 02:27:58 +0000 Subject: [PATCH 150/478] ip_gre: include route header_len in max_headroom calculation Taking route's header_len into account, and updating gre device needed_headroom will give better hints on upper bound of required headroom. This is useful if the gre traffic is xfrm'ed. Signed-off-by: Timo Teras Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index f47c9f76754..f78402d097b 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -810,11 +810,13 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev tunnel->err_count = 0; } - max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen; + max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->u.dst.header_len; if (skb_headroom(skb) < max_headroom || skb_shared(skb)|| (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); + if (max_headroom > dev->needed_headroom) + dev->needed_headroom = max_headroom; if (!new_skb) { ip_rt_put(rt); txq->tx_dropped++; From 2d8428acaee5468d194d8a84de22a0797791cb33 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 22 Mar 2010 14:01:24 +0900 Subject: [PATCH 151/478] nilfs2: fix duplicate call to nilfs_segctor_cancel_freev Andreas Beckmann gave me a report that nilfs logged the following warnings when it got a disk full: nilfs_sufile_do_cancel_free: segment 0 must be clean nilfs_sufile_do_cancel_free: segment 1 must be clean These arise from a duplicate call to nilfs_segctor_cancel_freev in an error path of log writer. This will fix the issue. Reported-by: Andreas Beckmann Signed-off-by: Ryusuke Konishi --- fs/nilfs2/segment.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 69576a95e13..b6221230f84 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -1510,6 +1510,12 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci, if (mode != SC_LSEG_SR || sci->sc_stage.scnt < NILFS_ST_CPFILE) break; + nilfs_clear_logs(&sci->sc_segbufs); + + err = nilfs_segctor_extend_segments(sci, nilfs, nadd); + if (unlikely(err)) + return err; + if (sci->sc_stage.flags & NILFS_CF_SUFREED) { err = nilfs_sufile_cancel_freev(nilfs->ns_sufile, sci->sc_freesegs, @@ -1517,12 +1523,6 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci, NULL); WARN_ON(err); /* do not happen */ } - nilfs_clear_logs(&sci->sc_segbufs); - - err = nilfs_segctor_extend_segments(sci, nilfs, nadd); - if (unlikely(err)) - return err; - nadd = min_t(int, nadd << 1, SC_MAX_SEGDELTA); sci->sc_stage = prev_stage; } From 025f206c9e0f96cc41567b01c07fb852d8900da1 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Sun, 21 Mar 2010 18:34:43 -0400 Subject: [PATCH 152/478] ALSA: hda: Fix 0 dB offset for HP laptops using CX20551 (Waikiki) BugLink: https://launchpad.net/bugs/420578 The OR has verified that his hardware distorts because of the 0 dB offset not corresponding to the highest PCM level. Fix this by capping said PCM level to 0 dB similarly to what we do for CX20549 (Venice). Reported-by: Mike Pontillo Tested-by: Mike Pontillo Cc: Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 194a28c5499..61682e1d09d 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1591,6 +1591,21 @@ static int patch_cxt5047(struct hda_codec *codec) #endif } spec->vmaster_nid = 0x13; + + switch (codec->subsystem_id >> 16) { + case 0x103c: + /* HP laptops have really bad sound over 0 dB on NID 0x10. + * Fix max PCM level to 0 dB (originally it has 0x1e steps + * with 0 dB offset 0x17) + */ + snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); + break; + } + return 0; } From e933e9e5238b79870b04718024416a6dcf602a27 Mon Sep 17 00:00:00 2001 From: Derek Kelly Date: Mon, 22 Mar 2010 08:04:19 +0100 Subject: [PATCH 153/478] ALSA: hda - Add support of Nvidia GT220 HDMI This patch adds the device id for Nvidia GT220 cards to the nvhdmi driver. I have tested it and confirmed it to be working. Original patch download link: https://gist.github.com/324070/ Signed-off-by: Derek Kelly Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 70669a24690..9e47717c8e2 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -554,6 +554,8 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de000b, .name = "GT21x HDMI", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de000a, .name = "GT220 HDMI", + .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de000d, .name = "GT240 HDMI", .patch = patch_nvhdmi_8ch_89 }, {} /* terminator */ @@ -568,6 +570,7 @@ MODULE_ALIAS("snd-hda-codec-id:10de0067"); MODULE_ALIAS("snd-hda-codec-id:10de8001"); MODULE_ALIAS("snd-hda-codec-id:10de000c"); MODULE_ALIAS("snd-hda-codec-id:10de000b"); +MODULE_ALIAS("snd-hda-codec-id:10de000a"); MODULE_ALIAS("snd-hda-codec-id:10de000d"); MODULE_LICENSE("GPL"); From ea823c08912cfb6d4af2fa8b6dd5d8deb2fb486a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 22 Mar 2010 08:07:55 +0100 Subject: [PATCH 154/478] ALSA: hda - Sort codec entry list of Nvidia HDMI Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 9e47717c8e2..3c10c0b149f 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -538,8 +538,6 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { - { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, - { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0003, .name = "MCP77/78 HDMI", @@ -550,14 +548,16 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de000c, .name = "MCP89 HDMI", + { .id = 0x10de000a, .name = "GT220 HDMI", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de000b, .name = "GT21x HDMI", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de000a, .name = "GT220 HDMI", + { .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de000d, .name = "GT240 HDMI", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, + { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, {} /* terminator */ }; @@ -566,12 +566,12 @@ MODULE_ALIAS("snd-hda-codec-id:10de0003"); MODULE_ALIAS("snd-hda-codec-id:10de0005"); MODULE_ALIAS("snd-hda-codec-id:10de0006"); MODULE_ALIAS("snd-hda-codec-id:10de0007"); +MODULE_ALIAS("snd-hda-codec-id:10de000a"); +MODULE_ALIAS("snd-hda-codec-id:10de000b"); +MODULE_ALIAS("snd-hda-codec-id:10de000c"); +MODULE_ALIAS("snd-hda-codec-id:10de000d"); MODULE_ALIAS("snd-hda-codec-id:10de0067"); MODULE_ALIAS("snd-hda-codec-id:10de8001"); -MODULE_ALIAS("snd-hda-codec-id:10de000c"); -MODULE_ALIAS("snd-hda-codec-id:10de000b"); -MODULE_ALIAS("snd-hda-codec-id:10de000a"); -MODULE_ALIAS("snd-hda-codec-id:10de000d"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec"); From bae84e70d66fe46c12231082cf1c4848ea22f3ef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 22 Mar 2010 08:30:20 +0100 Subject: [PATCH 155/478] ALSA: hda - Fix access-after-free in patch_realtek.c alc_free_kctls() has to be called after all jobs done in alc_build_controls(). Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4ec57633af8..053d53d8c8b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2532,8 +2532,6 @@ static int alc_build_controls(struct hda_codec *codec) return err; } - alc_free_kctls(codec); /* no longer needed */ - /* assign Capture Source enums to NID */ kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); if (!kctl) @@ -2602,6 +2600,9 @@ static int alc_build_controls(struct hda_codec *codec) } } } + + alc_free_kctls(codec); /* no longer needed */ + return 0; } From c9acb42ef1904d15d0fb315061cefbe638f67f3a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 19 Mar 2010 15:36:22 -0400 Subject: [PATCH 156/478] SUNRPC: Fix a use after free bug with the NFSv4.1 backchannel The ->release_request() callback was designed to allow the transport layer to do housekeeping after the RPC call is done. It cannot be used to free the request itself, and doing so leads to a use-after-free bug in xprt_release(). Signed-off-by: Trond Myklebust --- include/linux/sunrpc/bc_xprt.h | 5 ++++- net/sunrpc/bc_svc.c | 15 --------------- net/sunrpc/xprt.c | 22 +++++++++------------- net/sunrpc/xprtsock.c | 3 --- 4 files changed, 13 insertions(+), 32 deletions(-) diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h index d7152b451e2..7c91260c44a 100644 --- a/include/linux/sunrpc/bc_xprt.h +++ b/include/linux/sunrpc/bc_xprt.h @@ -36,7 +36,6 @@ struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt); void xprt_free_bc_request(struct rpc_rqst *req); int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); void xprt_destroy_backchannel(struct rpc_xprt *, int max_reqs); -void bc_release_request(struct rpc_task *); int bc_send(struct rpc_rqst *req); /* @@ -59,6 +58,10 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp) { return 0; } + +static inline void xprt_free_bc_request(struct rpc_rqst *req) +{ +} #endif /* CONFIG_NFS_V4_1 */ #endif /* _LINUX_SUNRPC_BC_XPRT_H */ diff --git a/net/sunrpc/bc_svc.c b/net/sunrpc/bc_svc.c index 13f214f5312..f0c05d3311c 100644 --- a/net/sunrpc/bc_svc.c +++ b/net/sunrpc/bc_svc.c @@ -37,21 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define RPCDBG_FACILITY RPCDBG_SVCDSP -void bc_release_request(struct rpc_task *task) -{ - struct rpc_rqst *req = task->tk_rqstp; - - dprintk("RPC: bc_release_request: task= %p\n", task); - - /* - * Release this request only if it's a backchannel - * preallocated request - */ - if (!bc_prealloc(req)) - return; - xprt_free_bc_request(req); -} - /* Empty callback ops */ static const struct rpc_call_ops nfs41_callback_ops = { }; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 469de292c23..42f09ade004 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -46,6 +46,7 @@ #include #include +#include #include "sunrpc.h" @@ -1032,21 +1033,16 @@ void xprt_release(struct rpc_task *task) if (req->rq_release_snd_buf) req->rq_release_snd_buf(req); - /* - * Early exit if this is a backchannel preallocated request. - * There is no need to have it added to the RPC slot list. - */ - if (is_bc_request) - return; - - memset(req, 0, sizeof(*req)); /* mark unused */ - dprintk("RPC: %5u release request %p\n", task->tk_pid, req); + if (likely(!is_bc_request)) { + memset(req, 0, sizeof(*req)); /* mark unused */ - spin_lock(&xprt->reserve_lock); - list_add(&req->rq_list, &xprt->free); - rpc_wake_up_next(&xprt->backlog); - spin_unlock(&xprt->reserve_lock); + spin_lock(&xprt->reserve_lock); + list_add(&req->rq_list, &xprt->free); + rpc_wake_up_next(&xprt->backlog); + spin_unlock(&xprt->reserve_lock); + } else + xprt_free_bc_request(req); } /** diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index e4839c07c91..9847c30b500 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2251,9 +2251,6 @@ static struct rpc_xprt_ops xs_tcp_ops = { .buf_free = rpc_free, .send_request = xs_tcp_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_def, -#if defined(CONFIG_NFS_V4_1) - .release_request = bc_release_request, -#endif /* CONFIG_NFS_V4_1 */ .close = xs_tcp_close, .destroy = xs_destroy, .print_stats = xs_tcp_print_stats, From ff0901f8036a1586037c30a365c9666e946af0f1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 19 Mar 2010 16:17:45 -0400 Subject: [PATCH 157/478] SUNRPC: Fix the return value of rpc_run_bc_task() Currently rpc_run_bc_task() will return NULL if the task allocation failed. However the only caller is bc_send, which assumes that the return value will be an ERR_PTR. Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 154034b675b..19c9983d536 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -659,6 +659,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, task = rpc_new_task(&task_setup_data); if (!task) { xprt_free_bc_request(req); + task = ERR_PTR(-ENOMEM); goto out; } task->tk_rqstp = req; From f1f0abe192a72e75d7c59972e30784d043fd8d73 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 21 Mar 2010 12:10:34 -0400 Subject: [PATCH 158/478] sunrpc: handle allocation errors from __rpc_lookup_create() __rpc_lookup_create() can return ERR_PTR(-ENOMEM). Signed-off-by: Dan Carpenter Signed-off-by: Trond Myklebust Cc: stable@kernel.org --- net/sunrpc/rpc_pipe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 8d63f8fd29b..20e30c6f835 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -587,6 +587,8 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, struct dentry *dentry; dentry = __rpc_lookup_create(parent, name); + if (IS_ERR(dentry)) + return dentry; if (dentry->d_inode == NULL) return dentry; dput(dentry); From 556ae3bb32cabe483375b857dda1322384c57b65 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Sun, 21 Mar 2010 12:10:36 -0400 Subject: [PATCH 159/478] NFS: don't try to decode GETATTR if DELEGRETURN returned error The reply parsing code attempts to decode the GETATTR response even if the DELEGRETURN portion of the compound returned an error. The GETATTR response won't actually exist if that's the case and we're asking the parser to read past the end of the response. This bug is fairly benign. The parser catches this without reading past the end of the response and decode_getfattr returns -EIO. Earlier kernels however had decode_op_hdr using the READ_BUF macro, and this bug would make this printk pop any time the client got an error from a delegreturn: kernel: decode_op_hdr: reply buffer overflowed in line XXXX More recent kernels seem to have replaced this printk with a dprintk. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 4d338be492c..dd17713413a 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -5552,6 +5552,8 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf if (status != 0) goto out; status = decode_delegreturn(&xdr); + if (status != 0) + goto out; decode_getfattr(&xdr, res->fattr, res->server, !RPC_IS_ASYNC(rqstp->rq_task)); out: From 3cc4e53f86dab635166929bfa47cc68d59b28c26 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 12 Feb 2010 14:39:36 +0000 Subject: [PATCH 160/478] ASoC: Remove BROKEN from i.MX audio after dependencies merged Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/imx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index c7d0fd9b7de..7174b4c710d 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -1,6 +1,6 @@ config SND_IMX_SOC tristate "SoC Audio for Freescale i.MX CPUs" - depends on ARCH_MXC && BROKEN + depends on ARCH_MXC select SND_PCM select FIQ select SND_SOC_AC97_BUS From ec64213c4d482ee4d15b34511441eaecdd002adf Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Fri, 19 Mar 2010 17:36:43 +0530 Subject: [PATCH 161/478] virtio: console: Generate a kobject CHANGE event on adding 'name' attribute When the host lets us know what 'name' a port is assigned, we create the sysfs 'name' attribute. Generate a 'change' event after this so that udev wakes up and acts on the rules for virtio-ports (currently there's only one rule that creates a symlink from the 'name' to the actual char device). Signed-off-by: Amit Shah Signed-off-by: Michael S. Tsirkin --- drivers/char/virtio_console.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index f404ccfc9c2..67b474b4167 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -947,11 +947,18 @@ static void handle_control_message(struct ports_device *portdev, */ err = sysfs_create_group(&port->dev->kobj, &port_attribute_group); - if (err) + if (err) { dev_err(port->dev, "Error %d creating sysfs device attributes\n", err); - + } else { + /* + * Generate a udev event so that appropriate + * symlinks can be created based on udev + * rules. + */ + kobject_uevent(&port->dev->kobj, KOBJ_CHANGE); + } break; case VIRTIO_CONSOLE_PORT_REMOVE: /* From 2de16a493cc6153f7fa0b9da12a3862d063e3425 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Fri, 19 Mar 2010 17:36:44 +0530 Subject: [PATCH 162/478] virtio: console: Check if port is valid in resize_console The console port could have been hot-unplugged. Check if it is valid before working on it. Signed-off-by: Amit Shah Signed-off-by: Michael S. Tsirkin --- drivers/char/virtio_console.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 67b474b4167..44288ce0cb4 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -681,6 +681,10 @@ static void resize_console(struct port *port) struct virtio_device *vdev; struct winsize ws; + /* The port could have been hot-unplugged */ + if (!port) + return; + vdev = port->portdev->vdev; if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) { vdev->config->get(vdev, From e3396b263c6a8f086a99f1d524272ff409d66de0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Mar 2010 15:10:35 +0300 Subject: [PATCH 163/478] pxa168fb: fix incorrect resource calculation The size calculation is not correct. It should be end - start + 1. Use resource_size() to caculate it. Signed-off-by: Dan Carpenter Signed-off-by: Eric Miao --- drivers/video/pxa168fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c index 75285d3f393..c91a7f70f7b 100644 --- a/drivers/video/pxa168fb.c +++ b/drivers/video/pxa168fb.c @@ -668,7 +668,7 @@ static int __init pxa168fb_probe(struct platform_device *pdev) /* * Map LCD controller registers. */ - fbi->reg_base = ioremap_nocache(res->start, res->end - res->start); + fbi->reg_base = ioremap_nocache(res->start, resource_size(res)); if (fbi->reg_base == NULL) { ret = -ENOMEM; goto failed; From 5b89d2f9ace1970324facc68ca9b8fae19ce8096 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 9 Mar 2010 20:38:48 +0100 Subject: [PATCH 164/478] edac, mce: Filter out invalid values Print the CPU associated with the error only when the field is valid. Cc: # .32.x .33.x Signed-off-by: Borislav Petkov --- drivers/edac/edac_mce_amd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index 8fc91a01962..f5b6d9fe4de 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -316,7 +316,12 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) if (regs->nbsh & K8_NBSH_ERR_CPU_VAL) pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf)); } else { - pr_cont(", core: %d\n", fls((regs->nbsh & 0xf) - 1)); + u8 assoc_cpus = regs->nbsh & 0xf; + + if (assoc_cpus > 0) + pr_cont(", core: %d", fls(assoc_cpus) - 1); + + pr_cont("\n"); } pr_emerg("%s.\n", EXT_ERR_MSG(xec)); From a90110c61073eab95d1986322693c2b9a8a6a5f6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 21 Mar 2010 21:51:51 +0100 Subject: [PATCH 165/478] x86 / perf: Fix suspend to RAM on HP nx6325 Commit 3f6da3905398826d85731247e7fbcf53400c18bd (perf: Rework and fix the arch CPU-hotplug hooks) broke suspend to RAM on my HP nx6325 (and most likely on other AMD-based boxes too) by allowing amd_pmu_cpu_offline() to be executed for CPUs that are going offline as part of the suspend process. The problem is that cpuhw->amd_nb may be NULL already, so the function should make sure it's not NULL before accessing the object pointed to by it. Signed-off-by: Rafael J. Wysocki Signed-off-by: Linus Torvalds --- arch/x86/kernel/cpu/perf_event_amd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index 573458f1caf..b87e0b6970c 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c @@ -348,10 +348,12 @@ static void amd_pmu_cpu_offline(int cpu) raw_spin_lock(&amd_nb_lock); - if (--cpuhw->amd_nb->refcnt == 0) - kfree(cpuhw->amd_nb); + if (cpuhw->amd_nb) { + if (--cpuhw->amd_nb->refcnt == 0) + kfree(cpuhw->amd_nb); - cpuhw->amd_nb = NULL; + cpuhw->amd_nb = NULL; + } raw_spin_unlock(&amd_nb_lock); } From 45575f5a426c01ec68cd33d998267ba2f6278fac Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 22 Mar 2010 17:47:59 +1100 Subject: [PATCH 166/478] ppc64 sys_ipc breakage in 2.6.34-rc2 I chased down a fail on ppc64 on 2.6.34-rc2 where an application that uses shared memory was getting a SEGV. Commit baed7fc9b580bd3fb8252ff1d9b36eaf1f86b670 ("Add generic sys_ipc wrapper") changed the second argument from an unsigned long to an int. When we call shmget the system call wrappers for sys_ipc will sign extend second (ie the size) which truncates it. It took a while to track down because the call succeeds and strace shows the untruncated size :) The patch below changes second from an int to an unsigned long which fixes shmget on ppc64 (and I assume s390, sparc64 and mips64). Signed-off-by: Anton Blanchard -- I assume the function prototypes for the other IPC methods would cause us to sign or zero extend second where appropriate (avoiding any security issues). Come to think of it, the syscall wrappers for each method should do that for us as well. Signed-off-by: Linus Torvalds --- ipc/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipc/syscall.c b/ipc/syscall.c index 355a3da9ec7..1d6f53f6b56 100644 --- a/ipc/syscall.c +++ b/ipc/syscall.c @@ -13,7 +13,7 @@ #include #include -SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, int, second, +SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second, unsigned long, third, void __user *, ptr, long, fifth) { int version, ret; From 99b437a9257cb6b267bf32adfb7675948dc6d485 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Mar 2010 13:07:14 +0000 Subject: [PATCH 167/478] AFS: Potential null dereference It seems clear from the surrounding code that xpermits is allowed to be NULL here. Signed-off-by: Dan Carpenter Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- fs/afs/security.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/afs/security.c b/fs/afs/security.c index 3ef50437003..bb4ed144d0e 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c @@ -189,8 +189,9 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, long acl_order) if (!permits) goto out_unlock; - memcpy(permits->permits, xpermits->permits, - count * sizeof(struct afs_permit)); + if (xpermits) + memcpy(permits->permits, xpermits->permits, + count * sizeof(struct afs_permit)); _debug("key %x access %x", key_serial(key), vnode->status.caller_access); From c3824d21eb653fe7017476724257ccaa8bf3d9e1 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 22 Mar 2010 13:50:19 +0000 Subject: [PATCH 168/478] rxrpc: Check allocation failure. alloc_skb() can return NULL. Signed-off-by: Tetsuo Handa Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- net/rxrpc/ar-accept.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/rxrpc/ar-accept.c b/net/rxrpc/ar-accept.c index 77228f28fa3..2d744f22a9a 100644 --- a/net/rxrpc/ar-accept.c +++ b/net/rxrpc/ar-accept.c @@ -88,6 +88,11 @@ static int rxrpc_accept_incoming_call(struct rxrpc_local *local, /* get a notification message to send to the server app */ notification = alloc_skb(0, GFP_NOFS); + if (!notification) { + _debug("no memory"); + ret = -ENOMEM; + goto error_nofree; + } rxrpc_new_skb(notification); notification->mark = RXRPC_SKB_MARK_NEW_CALL; @@ -189,6 +194,7 @@ invalid_service: ret = -ECONNREFUSED; error: rxrpc_free_skb(notification); +error_nofree: _leave(" = %d", ret); return ret; } From 7c3456fdb503071787f7f972de1069b9cacd16f0 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 22 Mar 2010 10:22:55 -0700 Subject: [PATCH 169/478] rxrpc: Check allocation failure. alloc_skb() can return NULL. Signed-off-by: Tetsuo Handa Signed-off-by: David Howells Signed-off-by: David S. Miller --- net/rxrpc/ar-accept.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/rxrpc/ar-accept.c b/net/rxrpc/ar-accept.c index 77228f28fa3..2d744f22a9a 100644 --- a/net/rxrpc/ar-accept.c +++ b/net/rxrpc/ar-accept.c @@ -88,6 +88,11 @@ static int rxrpc_accept_incoming_call(struct rxrpc_local *local, /* get a notification message to send to the server app */ notification = alloc_skb(0, GFP_NOFS); + if (!notification) { + _debug("no memory"); + ret = -ENOMEM; + goto error_nofree; + } rxrpc_new_skb(notification); notification->mark = RXRPC_SKB_MARK_NEW_CALL; @@ -189,6 +194,7 @@ invalid_service: ret = -ECONNREFUSED; error: rxrpc_free_skb(notification); +error_nofree: _leave(" = %d", ret); return ret; } From ef1691504c83ba3eb636c0cfd3ed33f7a6d0b4ee Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 22 Mar 2010 18:25:20 +0100 Subject: [PATCH 170/478] netfilter: xt_recent: fix regression in rules using a zero hit_count Commit 8ccb92ad (netfilter: xt_recent: fix false match) fixed supposedly false matches in rules using a zero hit_count. As it turns out there is nothing false about these matches and people are actually using entries with a hit_count of zero to make rules dependant on addresses inserted manually through /proc. Since this slipped past the eyes of three reviewers, instead of reverting the commit in question, this patch explicitly checks for a hit_count of zero to make the intentions more clear. Reported-by: Thomas Jarosch Tested-by: Thomas Jarosch Cc: stable@kernel.org Signed-off-by: Patrick McHardy --- net/netfilter/xt_recent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 7073dbb8100..971d172afec 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -267,7 +267,7 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) for (i = 0; i < e->nstamps; i++) { if (info->seconds && time_after(time, e->stamps[i])) continue; - if (info->hit_count && ++hits >= info->hit_count) { + if (!info->hit_count || ++hits >= info->hit_count) { ret = !ret; break; } From 3fff6c04d81a2852821135736fad2d8386464753 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 23 Feb 2010 23:38:55 -0800 Subject: [PATCH 171/478] Regulators: max8925-regulator - clean up driver data after removal It is a good tone to reset driver data after unbinding the device. Also change find_regulator_info() fro inline to __devinit - let compiler figure out if it wants it to be inlined or not. Signed-off-by: Dmitry Torokhov Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/max8925-regulator.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 67873f08ed4..b6218f11c95 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -230,7 +230,7 @@ static struct max8925_regulator_info max8925_regulator_info[] = { MAX8925_LDO(20, 750, 3900, 50), }; -static inline struct max8925_regulator_info *find_regulator_info(int id) +static struct max8925_regulator_info * __devinit find_regulator_info(int id) { struct max8925_regulator_info *ri; int i; @@ -247,7 +247,7 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); struct max8925_platform_data *pdata = chip->dev->platform_data; - struct max8925_regulator_info *ri = NULL; + struct max8925_regulator_info *ri; struct regulator_dev *rdev; ri = find_regulator_info(pdev->id); @@ -274,7 +274,9 @@ static int __devexit max8925_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); regulator_unregister(rdev); + return 0; } From 67e46f347eb25222e2b415540b6ba3fd2574afe2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 7 Mar 2010 15:36:45 +0300 Subject: [PATCH 172/478] regulator: handle kcalloc() failure Return -ENOMEM if kcalloc() fails Signed-off-by: Dan Carpenter Acked-by: Mark Brown Acked-by: Wolfram Sang Signed-off-by: Liam Girdwood --- drivers/regulator/lp3971.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index f5532ed7927..55fab4a3064 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -439,6 +439,10 @@ static int __devinit setup_regulators(struct lp3971 *lp3971, lp3971->num_regulators = pdata->num_regulators; lp3971->rdev = kcalloc(pdata->num_regulators, sizeof(struct regulator_dev *), GFP_KERNEL); + if (!lp3971->rdev) { + err = -ENOMEM; + goto err_nomem; + } /* Instantiate the regulators */ for (i = 0; i < pdata->num_regulators; i++) { @@ -461,6 +465,7 @@ error: regulator_unregister(lp3971->rdev[i]); kfree(lp3971->rdev); lp3971->rdev = NULL; +err_nomem: return err; } From 4f26a2abe1eed18dc6adddf2d0ae5553e51578c2 Mon Sep 17 00:00:00 2001 From: Ameya Palande Date: Fri, 12 Mar 2010 20:09:01 +0200 Subject: [PATCH 173/478] regulator: Get rid of lockdep warning WARNING: at kernel/lockdep.c:2706 sysfs_add_file_mode+0x4c/0xa8() Difference between v1 and v2: Moved sysfs_attr_init() call as first one to access the structure. Signed-off-by: Ameya Palande CC: Liam Girdwood CC: Mark Brown CC: David Brownell Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c7bbe30010f..5af16c2bb54 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1038,6 +1038,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, goto overflow_err; regulator->dev = dev; + sysfs_attr_init(®ulator->dev_attr.attr); regulator->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL); if (regulator->dev_attr.attr.name == NULL) goto attr_name_err; From cdb868f58103825856e27aa4e1f26943fc119e41 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 9 Mar 2010 16:53:59 +0800 Subject: [PATCH 174/478] lp3971: Fix setting val for LDO2 and LDO4 In lp3971_ldo_set_voltage function, it requires val to left shift 4 bits for LDO2 and LDO4. This patch fix this issue. Signed-off-by: Axel Lin Acked-by: Marek Szyprowski Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/lp3971.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 55fab4a3064..8bdcf41ab68 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -187,7 +187,8 @@ static int lp3971_ldo_set_voltage(struct regulator_dev *dev, return -EINVAL; return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo), - LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo), val); + LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo), + val << LDO_VOL_CONTR_SHIFT(ldo)); } static struct regulator_ops lp3971_ldo_ops = { From 451a73cd46573444f68f412c87439c0a291718ec Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 11 Mar 2010 09:50:07 +0800 Subject: [PATCH 175/478] lp3971: Fix BUCK_VOL_CHANGE_SHIFT logic Given x=0,1,2, current implementation of BUCK_VOL_CHANGE_SHIFT(x) returns 0,4,8. The correct return value should be 0,4,6. This patch fix the logic. Signed-off-by: Axel Lin Acked-by: Marek Szyprowski Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/lp3971.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 8bdcf41ab68..b20b3e1d821 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -45,7 +45,7 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val); LP3971_BUCK2 -> 4 LP3971_BUCK3 -> 6 */ -#define BUCK_VOL_CHANGE_SHIFT(x) (((1 << x) & ~0x01) << 1) +#define BUCK_VOL_CHANGE_SHIFT(x) (((!!x) << 2) | (x & ~0x01)) #define BUCK_VOL_CHANGE_FLAG_GO 0x01 #define BUCK_VOL_CHANGE_FLAG_TARGET 0x02 #define BUCK_VOL_CHANGE_FLAG_MASK 0x03 From 8b4709ecea4aab1957ae7b726d6824485404a3a5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 20 Mar 2010 15:12:58 +0100 Subject: [PATCH 176/478] regulator: fix dangling pointers Fix I2C-drivers which missed setting clientdata to NULL before freeing the structure it points to. Also fix drivers which do this _after_ the structure was freed already. Signed-off-by: Wolfram Sang Cc: Liam Girdwood Cc: Mark Brown Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/max1586.c | 2 +- drivers/regulator/max8649.c | 3 ++- drivers/regulator/max8660.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index a49fc952c9a..c0b09e15edb 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -243,8 +243,8 @@ static int __devexit max1586_pmic_remove(struct i2c_client *client) for (i = 0; i <= MAX1586_V6; i++) if (rdev[i]) regulator_unregister(rdev[i]); - kfree(rdev); i2c_set_clientdata(client, NULL); + kfree(rdev); return 0; } diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 3ebdf698c64..833aaedc7e6 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -356,6 +356,7 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, dev_info(info->dev, "Max8649 regulator device is detected.\n"); return 0; out: + i2c_set_clientdata(client, NULL); kfree(info); return ret; } @@ -367,9 +368,9 @@ static int __devexit max8649_regulator_remove(struct i2c_client *client) if (info) { if (info->regulator) regulator_unregister(info->regulator); + i2c_set_clientdata(client, NULL); kfree(info); } - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index f12f1bb6213..47f90b2fc29 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -470,8 +470,8 @@ static int __devexit max8660_remove(struct i2c_client *client) for (i = 0; i < MAX8660_V_END; i++) if (rdev[i]) regulator_unregister(rdev[i]); - kfree(rdev); i2c_set_clientdata(client, NULL); + kfree(rdev); return 0; } From ae6be51ed01d6c4aaf249a207b4434bc7785853b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 22 Mar 2010 13:12:33 -0700 Subject: [PATCH 177/478] Fix up prototype for sys_ipc breakage Commit 45575f5a426c ("ppc64 sys_ipc breakage in 2.6.34-rc2") fixed the definition of the sys_ipc() helper, but didn't fix the prototype in Reported-and-tested-by: Andreas Schwab Signed-off-by: Linus Torvalds --- include/linux/syscalls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index f994ae58a00..057929b0a65 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -688,7 +688,7 @@ asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg); asmlinkage long sys_shmget(key_t key, size_t size, int flag); asmlinkage long sys_shmdt(char __user *shmaddr); asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); -asmlinkage long sys_ipc(unsigned int call, int first, int second, +asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second, unsigned long third, void __user *ptr, long fifth); asmlinkage long sys_mq_open(const char __user *name, int oflag, mode_t mode, struct mq_attr __user *attr); From 4f1deba435ef75380c1d06fda860c7a15ea16fdf Mon Sep 17 00:00:00 2001 From: "JosephChan@via.com.tw" Date: Fri, 19 Mar 2010 14:08:11 +0800 Subject: [PATCH 178/478] pata_via: Add VIA VX900 support Signed-off-by: Joseph Chan Signed-off-by: Jeff Garzik --- drivers/ata/pata_via.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 3059ec017de..95d39c36ace 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -677,6 +677,7 @@ static const struct pci_device_id via[] = { { PCI_VDEVICE(VIA, 0x3164), }, { PCI_VDEVICE(VIA, 0x5324), }, { PCI_VDEVICE(VIA, 0xC409), VIA_IDFLAG_SINGLE }, + { PCI_VDEVICE(VIA, 0x9001), VIA_IDFLAG_SINGLE }, { }, }; From 21afc27c9f9ae1f6370c47b323be7f3b75106569 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 21 Mar 2010 21:06:01 +0000 Subject: [PATCH 179/478] can: bfin_can: switch to common Blackfin can header The MMR bits are being moved to this header, so include it. Signed-off-by: Mike Frysinger Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/bfin_can.c | 97 +++----------------------------------- 1 file changed, 7 insertions(+), 90 deletions(-) diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index 866905fa411..03489864376 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -22,96 +22,13 @@ #include #include +#include #include #define DRV_NAME "bfin_can" #define BFIN_CAN_TIMEOUT 100 #define TX_ECHO_SKB_MAX 1 -/* - * transmit and receive channels - */ -#define TRANSMIT_CHL 24 -#define RECEIVE_STD_CHL 0 -#define RECEIVE_EXT_CHL 4 -#define RECEIVE_RTR_CHL 8 -#define RECEIVE_EXT_RTR_CHL 12 -#define MAX_CHL_NUMBER 32 - -/* - * bfin can registers layout - */ -struct bfin_can_mask_regs { - u16 aml; - u16 dummy1; - u16 amh; - u16 dummy2; -}; - -struct bfin_can_channel_regs { - u16 data[8]; - u16 dlc; - u16 dummy1; - u16 tsv; - u16 dummy2; - u16 id0; - u16 dummy3; - u16 id1; - u16 dummy4; -}; - -struct bfin_can_regs { - /* - * global control and status registers - */ - u16 mc1; /* offset 0 */ - u16 dummy1; - u16 md1; /* offset 4 */ - u16 rsv1[13]; - u16 mbtif1; /* offset 0x20 */ - u16 dummy2; - u16 mbrif1; /* offset 0x24 */ - u16 dummy3; - u16 mbim1; /* offset 0x28 */ - u16 rsv2[11]; - u16 mc2; /* offset 0x40 */ - u16 dummy4; - u16 md2; /* offset 0x44 */ - u16 dummy5; - u16 trs2; /* offset 0x48 */ - u16 rsv3[11]; - u16 mbtif2; /* offset 0x60 */ - u16 dummy6; - u16 mbrif2; /* offset 0x64 */ - u16 dummy7; - u16 mbim2; /* offset 0x68 */ - u16 rsv4[11]; - u16 clk; /* offset 0x80 */ - u16 dummy8; - u16 timing; /* offset 0x84 */ - u16 rsv5[3]; - u16 status; /* offset 0x8c */ - u16 dummy9; - u16 cec; /* offset 0x90 */ - u16 dummy10; - u16 gis; /* offset 0x94 */ - u16 dummy11; - u16 gim; /* offset 0x98 */ - u16 rsv6[3]; - u16 ctrl; /* offset 0xa0 */ - u16 dummy12; - u16 intr; /* offset 0xa4 */ - u16 rsv7[7]; - u16 esr; /* offset 0xb4 */ - u16 rsv8[37]; - - /* - * channel(mailbox) mask and message registers - */ - struct bfin_can_mask_regs msk[MAX_CHL_NUMBER]; /* offset 0x100 */ - struct bfin_can_channel_regs chl[MAX_CHL_NUMBER]; /* offset 0x200 */ -}; - /* * bfin can private data */ @@ -163,7 +80,7 @@ static int bfin_can_set_bittiming(struct net_device *dev) if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) timing |= SAM; - bfin_write16(®->clk, clk); + bfin_write16(®->clock, clk); bfin_write16(®->timing, timing); dev_info(dev->dev.parent, "setting CLOCK=0x%04x TIMING=0x%04x\n", @@ -185,11 +102,11 @@ static void bfin_can_set_reset_mode(struct net_device *dev) bfin_write16(®->gim, 0); /* reset can and enter configuration mode */ - bfin_write16(®->ctrl, SRS | CCR); + bfin_write16(®->control, SRS | CCR); SSYNC(); - bfin_write16(®->ctrl, CCR); + bfin_write16(®->control, CCR); SSYNC(); - while (!(bfin_read16(®->ctrl) & CCA)) { + while (!(bfin_read16(®->control) & CCA)) { udelay(10); if (--timeout == 0) { dev_err(dev->dev.parent, @@ -244,7 +161,7 @@ static void bfin_can_set_normal_mode(struct net_device *dev) /* * leave configuration mode */ - bfin_write16(®->ctrl, bfin_read16(®->ctrl) & ~CCR); + bfin_write16(®->control, bfin_read16(®->control) & ~CCR); while (bfin_read16(®->status) & CCA) { udelay(10); @@ -726,7 +643,7 @@ static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg) if (netif_running(dev)) { /* enter sleep mode */ - bfin_write16(®->ctrl, bfin_read16(®->ctrl) | SMR); + bfin_write16(®->control, bfin_read16(®->control) | SMR); SSYNC(); while (!(bfin_read16(®->intr) & SMACK)) { udelay(10); From 5fc05f8764f301138003ff562a31ad3721f1675f Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Sun, 21 Mar 2010 22:59:58 +0000 Subject: [PATCH 180/478] netpoll: warn when there are spaces in parameters v2: update according to Frans' comments. Currently, if we leave spaces before dst port, netconsole will silently accept it as 0. Warn about this. Also, when spaces appear in other places, make them visible in error messages. Signed-off-by: WANG Cong Cc: David Miller Acked-by: Neil Horman Signed-off-by: David S. Miller --- net/core/netpoll.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index d4ec38fa64e..6f9206b36dc 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -614,7 +614,7 @@ void netpoll_print_options(struct netpoll *np) np->name, np->local_port); printk(KERN_INFO "%s: local IP %pI4\n", np->name, &np->local_ip); - printk(KERN_INFO "%s: interface %s\n", + printk(KERN_INFO "%s: interface '%s'\n", np->name, np->dev_name); printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port); @@ -661,6 +661,9 @@ int netpoll_parse_options(struct netpoll *np, char *opt) if ((delim = strchr(cur, '@')) == NULL) goto parse_failed; *delim = 0; + if (*cur == ' ' || *cur == '\t') + printk(KERN_INFO "%s: warning: whitespace" + "is not allowed\n", np->name); np->remote_port = simple_strtol(cur, NULL, 10); cur = delim; } @@ -708,7 +711,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt) return 0; parse_failed: - printk(KERN_INFO "%s: couldn't parse config at %s!\n", + printk(KERN_INFO "%s: couldn't parse config at '%s'!\n", np->name, cur); return -1; } From 688328c7ec3cd0dc3b16342aeb045d28012cc955 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 17 Mar 2010 22:24:39 +0000 Subject: [PATCH 181/478] netxen: The driver doesn't work on NX_P3_B1 so cause probe to fail. I haven't been able to get link up on a NX_P3_B1 since 2.6.31. The driver complains about a firmware hang instead. When I asked I was told rev 0x41 was a preproduction rev. So disable support in the driver so no one is surprised the code doesn't work. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 08780ef1c1f..9a7a0f3c36c 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1246,8 +1246,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int pci_func_id = PCI_FUNC(pdev->devfn); uint8_t revision_id; - if (pdev->revision >= NX_P3_A0 && pdev->revision < NX_P3_B1) { - pr_warning("%s: chip revisions between 0x%x-0x%x" + if (pdev->revision >= NX_P3_A0 && pdev->revision <= NX_P3_B1) { + pr_warning("%s: chip revisions between 0x%x-0x%x " "will not be enabled.\n", module_name(THIS_MODULE), NX_P3_A0, NX_P3_B1); return -ENODEV; From b230eb32c8d568284c1f33f5d06005eb97d4f897 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Mar 2010 02:01:33 +0000 Subject: [PATCH 182/478] sh: mach-ecovec24: Add i2c_put_adapter on sh_eth_init i2c_put_adapter is needed after i2c_get_adapter Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/sh/boards/mach-ecovec24/setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 39ed8722d11..6c13b92742e 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -836,6 +836,8 @@ static void __init sh_eth_init(struct sh_eth_plat_data *pd) pd->mac_addr[i] = mac_read(a, 0x10 + i); msleep(10); } + + i2c_put_adapter(a); } #else static void __init sh_eth_init(struct sh_eth_plat_data *pd) From bec9fb072f58a77a449c4bb3b1b036fcecc68663 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Mar 2010 02:01:53 +0000 Subject: [PATCH 183/478] sh: ms7724: Add tiny-document for sound Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/sh/boards/mach-se/7724/setup.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 66cdbc3c7af..ccaa290e9ab 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -52,6 +52,13 @@ * and change SW41 to use 720p */ +/* + * about sound + * + * This setup.c supports FSI slave mode. + * Please change J20, J21, J22 pin to 1-2 connection. + */ + /* Heartbeat */ static struct resource heartbeat_resource = { .start = PA_LED, @@ -276,6 +283,7 @@ static struct clk fsimcka_clk = { .rate = 0, /* unknown */ }; +/* change J20, J21, J22 pin to 1-2 connection to use slave mode */ struct sh_fsi_platform_info fsi_info = { .porta_flags = SH_FSI_BRS_INV | SH_FSI_OUT_SLAVE_MODE | From 67eaa3e4fb29a758f92c9296ca006264a034e9c2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Mar 2010 02:02:08 +0000 Subject: [PATCH 184/478] sh: Add watch-dog register address for SH7722/SH7723/SH7724 Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/sh/include/cpu-sh4/cpu/watchdog.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/sh/include/cpu-sh4/cpu/watchdog.h b/arch/sh/include/cpu-sh4/cpu/watchdog.h index 7672301d0c7..7f62b938093 100644 --- a/arch/sh/include/cpu-sh4/cpu/watchdog.h +++ b/arch/sh/include/cpu-sh4/cpu/watchdog.h @@ -21,6 +21,12 @@ #define WTCNT 0xffcc0000 /*WDTST*/ #define WTST WTCNT #define WTBST 0xffcc0008 /*WDTBST*/ +/* Register definitions */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7722) || \ + defined(CONFIG_CPU_SUBTYPE_SH7723) || \ + defined(CONFIG_CPU_SUBTYPE_SH7724) +#define WTCNT 0xa4520000 +#define WTCSR 0xa4520004 #else /* Register definitions */ #define WTCNT 0xffc00008 From 8d099d4446fcb23ca6cc054bde3c35b417e29b3b Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 16 Mar 2010 11:21:07 +0000 Subject: [PATCH 185/478] serial: sh-sci: fix SH-Mobile SH breakage The follwing commit breaks SH-Mobile on non-ARM platforms: "8a77b8d serial: sh-sci: Support ARM-based SH-Mobile CPUs." The commit assumed that CONFIG_ARCH_SHMOBILE only was set on ARM platforms, but it turns out that this kconfig is also set by all SH-based SoCs. Sh7724 and other older SH-Mobile SoCs are all broken without this fix. This patch converts the "defined(CONFIG_ARCH_SHMOBILE)" into one "defined()" per SoC model - similar to existing SH code. Reported-by: Guennadi Liakhovetski Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.h | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index fad67d33b0b..be6e1d2317a 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -31,7 +31,9 @@ # define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0 #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SHMOBILE) + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) # define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ # define PORT_PTCR 0xA405011EUL # define PORT_PVCR 0xA4050122UL @@ -230,7 +232,9 @@ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SHMOBILE) + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) # define SCIF_ORER 0x0200 # define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER) # define SCIF_RFDC_MASK 0x007f @@ -264,7 +268,9 @@ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SHMOBILE) + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) # define SCxSR_RDxF_CLEAR(port) (sci_in(port, SCxSR) & 0xfffc) # define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73) # define SCxSR_TDxE_CLEAR(port) (sci_in(port, SCxSR) & 0xffdf) @@ -359,7 +365,10 @@ SCI_OUT(sci_size, sci_offset, value); \ } -#if defined(CONFIG_CPU_SH3) || defined(CONFIG_ARCH_SHMOBILE) +#if defined(CONFIG_CPU_SH3) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) #if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) #define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ @@ -370,7 +379,9 @@ #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SHMOBILE) + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) #define SCIF_FNS(name, scif_offset, scif_size) \ CPU_SCIF_FNS(name, scif_offset, scif_size) #else @@ -406,7 +417,9 @@ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SHMOBILE) + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) SCIF_FNS(SCSMR, 0x00, 16) SCIF_FNS(SCBRR, 0x04, 8) @@ -589,7 +602,9 @@ static inline int sci_rxd_in(struct uart_port *port) #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SHMOBILE) + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ defined(CONFIG_CPU_SUBTYPE_SH7724) From d7bbf7f50e03c427debb6d7d960c48b9b934e7e2 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 19 Mar 2010 13:52:35 +0000 Subject: [PATCH 186/478] SH: fix SCIFA SCASCR register bit definitions Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index be6e1d2317a..f70c49f915f 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -96,7 +96,9 @@ # define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7724) # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCSCR_INIT(port) ((port)->type == PORT_SCIFA ? \ + 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ + 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) #elif defined(CONFIG_CPU_SUBTYPE_SH4_202) # define SCSPTR2 0xffe80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ @@ -199,6 +201,8 @@ defined(CONFIG_CPU_SUBTYPE_SH7786) || \ defined(CONFIG_CPU_SUBTYPE_SHX3) #define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7724) +#define SCI_CTRL_FLAGS_REIE ((port)->type == PORT_SCIFA ? 0 : 8) #else #define SCI_CTRL_FLAGS_REIE 0 #endif From 0a60a210ede8942c5149526bf6847176cee5c184 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 19 Mar 2010 13:53:36 +0000 Subject: [PATCH 187/478] SH: remove superfluous warning from the serial driver This warning has been introduced during the SCI DMA support developmenr and is not needed any more. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index f7b9aff88f4..309de6be820 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -779,10 +779,6 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) if ((ssr_status & SCxSR_BRK(port)) && err_enabled) ret = sci_br_interrupt(irq, ptr); - WARN_ONCE(ret == IRQ_NONE, - "%s: %d IRQ %d, status %x, control %x\n", __func__, - irq, port->line, ssr_status, scr_status); - return ret; } From 685abecfc2a6036b713229617570980c566c7500 Mon Sep 17 00:00:00 2001 From: Andreas Bombe Date: Sat, 20 Mar 2010 00:38:01 +0000 Subject: [PATCH 188/478] sh64: Remove long unused mid_sched macro interruptible_sleep_on() is referenced for use in the mid_sched macro which is not used anywhere. Remove reference and macro as well as the comment which appears to belong with them. Signed-off-by: Andreas Bombe Signed-off-by: Paul Mundt --- arch/sh/kernel/process_64.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index c90957a459a..c0d40f671ec 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -504,13 +504,6 @@ out: return error; } -/* - * These bracket the sleeping functions.. - */ -extern void interruptible_sleep_on(wait_queue_head_t *q); - -#define mid_sched ((unsigned long) interruptible_sleep_on) - #ifdef CONFIG_FRAME_POINTER static int in_sh64_switch_to(unsigned long pc) { From a9eb4f6d1a168c830a206306dfbb1f95a7fed6b3 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Sun, 21 Mar 2010 19:51:43 +0000 Subject: [PATCH 189/478] sh: Flush ITLB too in PTEAEX's flush_tlb_page() flush_tlb_page() can be used to flush TLB entries that map executable pages. Therefore, we need to ensure that the ITLB is also flushed in local_flush_tlb_page(). Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/include/cpu-sh4/cpu/mmu_context.h | 2 ++ arch/sh/mm/tlb-pteaex.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/sh/include/cpu-sh4/cpu/mmu_context.h b/arch/sh/include/cpu-sh4/cpu/mmu_context.h index 03ea75c5315..310ec92f275 100644 --- a/arch/sh/include/cpu-sh4/cpu/mmu_context.h +++ b/arch/sh/include/cpu-sh4/cpu/mmu_context.h @@ -19,6 +19,8 @@ #define MMUCR 0xFF000010 /* MMU Control Register */ +#define MMU_ITLB_ADDRESS_ARRAY 0xF2000000 +#define MMU_ITLB_ADDRESS_ARRAY2 0xF2800000 #define MMU_UTLB_ADDRESS_ARRAY 0xF6000000 #define MMU_UTLB_ADDRESS_ARRAY2 0xF6800000 #define MMU_PAGE_ASSOC_BIT 0x80 diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c index 32dc674c550..bdd0982b56e 100644 --- a/arch/sh/mm/tlb-pteaex.c +++ b/arch/sh/mm/tlb-pteaex.c @@ -73,5 +73,7 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page) jump_to_uncached(); __raw_writel(page, MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT); __raw_writel(asid, MMU_UTLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT); + __raw_writel(page, MMU_ITLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT); + __raw_writel(asid, MMU_ITLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT); back_to_cached(); } From b5b6c7eea1124de5b110a48ac62650a690ed2419 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Sun, 21 Mar 2010 19:51:52 +0000 Subject: [PATCH 190/478] sh: Replace unsafe manipulation of MMUCR Setting the TI in MMUCR causes all the TLB bits in MMUCR to be cleared. Unfortunately, the TLB wired bits are also cleared when setting the TI bit, causing any wired TLB entries to become unwired. Use local_flush_tlb_all() which implements TLB flushing in a safer manner by using the memory-mapped TLB registers. As each CPU has its own PMB the modifications in pmb_init() only affect the local CPU, so only flush the local CPU's TLB. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/mm/pmb.c | 2 +- arch/sh/mm/tlbflush_32.c | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index a4662e2782c..0b14dcf05da 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -802,7 +802,7 @@ void __init pmb_init(void) writel_uncached(0, PMB_IRMCR); /* Flush out the TLB */ - __raw_writel(__raw_readl(MMUCR) | MMUCR_TI, MMUCR); + local_flush_tlb_all(); ctrl_barrier(); } diff --git a/arch/sh/mm/tlbflush_32.c b/arch/sh/mm/tlbflush_32.c index 004bb3f25b5..77dc5efa712 100644 --- a/arch/sh/mm/tlbflush_32.c +++ b/arch/sh/mm/tlbflush_32.c @@ -123,18 +123,27 @@ void local_flush_tlb_mm(struct mm_struct *mm) void local_flush_tlb_all(void) { unsigned long flags, status; + int i; /* * Flush all the TLB. - * - * Write to the MMU control register's bit: - * TF-bit for SH-3, TI-bit for SH-4. - * It's same position, bit #2. */ local_irq_save(flags); + jump_to_uncached(); + status = __raw_readl(MMUCR); - status |= 0x04; - __raw_writel(status, MMUCR); + status = ((status & MMUCR_URB) >> MMUCR_URB_SHIFT); + + if (status == 0) + status = MMUCR_URB_NENTRIES; + + for (i = 0; i < status; i++) + __raw_writel(0x0, MMU_UTLB_ADDRESS_ARRAY | (i << 8)); + + for (i = 0; i < 4; i++) + __raw_writel(0x0, MMU_ITLB_ADDRESS_ARRAY | (i << 8)); + + back_to_cached(); ctrl_barrier(); local_irq_restore(flags); } From 3fe0f36c7edcd20af0a3cafc68bdd62534c0a7f0 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Mon, 22 Mar 2010 22:09:58 +0000 Subject: [PATCH 191/478] sh: Fix build after dynamic PMB rework set_pmb_entry() is now only used by a function that is wrapped in #ifdef CONFIG_PM, so wrap set_pmb_entry() in CONFIG_PM too. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/mm/pmb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 0b14dcf05da..3cc21933063 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -323,6 +323,7 @@ static void __clear_pmb_entry(struct pmb_entry *pmbe) writel_uncached(data_val & ~PMB_V, data); } +#ifdef CONFIG_PM static void set_pmb_entry(struct pmb_entry *pmbe) { unsigned long flags; @@ -331,6 +332,7 @@ static void set_pmb_entry(struct pmb_entry *pmbe) __set_pmb_entry(pmbe); spin_unlock_irqrestore(&pmbe->lock, flags); } +#endif /* CONFIG_PM */ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys, unsigned long size, pgprot_t prot) From 90851c40769791a6ddeef691c482ecf69bae4a5c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 23 Mar 2010 17:06:47 +0900 Subject: [PATCH 192/478] sh: Tidy up a couple of section mismatches. select_idle_routine() and register_sh_pmu() both needed their annotations fixed up to silence section mismatch warnings. Signed-off-by: Paul Mundt --- arch/sh/kernel/idle.c | 2 +- arch/sh/kernel/perf_event.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c index 0fd7b41f0a2..273f890b17a 100644 --- a/arch/sh/kernel/idle.c +++ b/arch/sh/kernel/idle.c @@ -112,7 +112,7 @@ void cpu_idle(void) } } -void __cpuinit select_idle_routine(void) +void __init select_idle_routine(void) { /* * If a platform has set its own idle routine, leave it alone. diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c index 9f253e9cce0..81b6de41ae5 100644 --- a/arch/sh/kernel/perf_event.c +++ b/arch/sh/kernel/perf_event.c @@ -315,7 +315,7 @@ void hw_perf_disable(void) sh_pmu->disable_all(); } -int register_sh_pmu(struct sh_pmu *pmu) +int __cpuinit register_sh_pmu(struct sh_pmu *pmu) { if (sh_pmu) return -EBUSY; From 4e1a2594094020bdb41c18681c1765671138d06a Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 23 Mar 2010 17:07:41 +0900 Subject: [PATCH 193/478] sh: Silence unintialized variable warnings in dwarf unwinder. The parent rb_node needs to be initialized to shut up the compiler, even though we're unlikely to ever hit this issue at run time. Signed-off-by: Paul Mundt --- arch/sh/kernel/dwarf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index bd1c497280a..94739ee7aa7 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c @@ -727,7 +727,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len, unsigned char *end, struct module *mod) { struct rb_node **rb_node = &cie_root.rb_node; - struct rb_node *parent; + struct rb_node *parent = *rb_node; struct dwarf_cie *cie; unsigned long flags; int count; @@ -856,7 +856,7 @@ static int dwarf_parse_fde(void *entry, u32 entry_type, unsigned char *end, struct module *mod) { struct rb_node **rb_node = &fde_root.rb_node; - struct rb_node *parent; + struct rb_node *parent = *rb_node; struct dwarf_fde *fde; struct dwarf_cie *cie; unsigned long flags; From 332ac7ff77cdc6a183d78ab129545d7b14a1d57c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 23 Mar 2010 12:24:08 +0900 Subject: [PATCH 194/478] libata-sff: fix spurious IRQ handling Commit 27943620cbd960f710a385ff4a538e14ed3f1922 introduced spurious IRQ handling but it has a race condition where valid completion can be lost while trying to clear spurious IRQ leading to occassional command timeouts. This patch improves SFF interrupt handler such that 1. Once BMDMA HSM is stopped, the condition is never considered spurious. As there's no way to resume stopped BMDMA HSM, if device status doesn't agree with BMDMA status, the only way out is aborting the command (otherwise, it will just end up timing out). 2. ap->ops->sff_check_status() can be safely called to clear spurious device IRQ as it atomically returns completion status but BMDMA IRQ status can't be cleared in safe way if command is in flight. After a spurious IRQ, call ap->ops->sff_irq_clear() only if the respective device is idle and retry completion if sff_check_status() indicates command completion. Please note that ata_piix uses bmdma_status for sff_irq_check() and #2 won't weaken spurious IRQ handling even with in-flight command because if bmdma_status indicates IRQ pending but device status is not on spurious check, the next IRQ handler invocation will abort the command due to #1. This fixes bko#15537. https://bugzilla.kernel.org/show_bug.cgi?id=15537 Signed-off-by: Tejun Heo Cc: Andrew Benton Cc: Petr Uzel Cc: Rafael J. Wysocki Signed-off-by: Jeff Garzik --- drivers/ata/libata-sff.c | 43 +++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 561dec2481c..277477251a8 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1667,6 +1667,7 @@ unsigned int ata_sff_host_intr(struct ata_port *ap, { struct ata_eh_info *ehi = &ap->link.eh_info; u8 status, host_stat = 0; + bool bmdma_stopped = false; VPRINTK("ata%u: protocol %d task_state %d\n", ap->print_id, qc->tf.protocol, ap->hsm_task_state); @@ -1699,6 +1700,7 @@ unsigned int ata_sff_host_intr(struct ata_port *ap, /* before we do anything else, clear DMA-Start bit */ ap->ops->bmdma_stop(qc); + bmdma_stopped = true; if (unlikely(host_stat & ATA_DMA_ERR)) { /* error when transfering data to/from memory */ @@ -1716,8 +1718,14 @@ unsigned int ata_sff_host_intr(struct ata_port *ap, /* check main status, clearing INTRQ if needed */ status = ata_sff_irq_status(ap); - if (status & ATA_BUSY) - goto idle_irq; + if (status & ATA_BUSY) { + if (bmdma_stopped) { + /* BMDMA engine is already stopped, we're screwed */ + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + } else + goto idle_irq; + } /* ack bmdma irq events */ ap->ops->sff_irq_clear(ap); @@ -1762,13 +1770,16 @@ EXPORT_SYMBOL_GPL(ata_sff_host_intr); irqreturn_t ata_sff_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; + bool retried = false; unsigned int i; - unsigned int handled = 0, polling = 0; + unsigned int handled, idle, polling; unsigned long flags; /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */ spin_lock_irqsave(&host->lock, flags); +retry: + handled = idle = polling = 0; for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; struct ata_queued_cmd *qc; @@ -1782,7 +1793,8 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance) handled |= ata_sff_host_intr(ap, qc); else polling |= 1 << i; - } + } else + idle |= 1 << i; } /* @@ -1790,7 +1802,9 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance) * asserting IRQ line, nobody cared will ensue. Check IRQ * pending status if available and clear spurious IRQ. */ - if (!handled) { + if (!handled && !retried) { + bool retry = false; + for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; @@ -1805,8 +1819,23 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance) ata_port_printk(ap, KERN_INFO, "clearing spurious IRQ\n"); - ap->ops->sff_check_status(ap); - ap->ops->sff_irq_clear(ap); + if (idle & (1 << i)) { + ap->ops->sff_check_status(ap); + ap->ops->sff_irq_clear(ap); + } else { + /* clear INTRQ and check if BUSY cleared */ + if (!(ap->ops->sff_check_status(ap) & ATA_BUSY)) + retry |= true; + /* + * With command in flight, we can't do + * sff_irq_clear() w/o racing with completion. + */ + } + } + + if (retry) { + retried = true; + goto retry; } } From 0a990e7093566ceb07e38951e1a01686923d4f09 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 15 Mar 2010 16:12:25 -0700 Subject: [PATCH 195/478] ceph: clean up service ticket decoding Previously we would decode state directly into our current ticket_handler. This is problematic if for some reason we fail to decode, because we end up with half new state and half old state. We are probably already in bad shape if we get an update we can't decode, but we may as well be tidy anyway. Decode into new_* temporaries and update the ticket_handler only on success. Signed-off-by: Sage Weil --- fs/ceph/auth_x.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/fs/ceph/auth_x.c b/fs/ceph/auth_x.c index 33d3ad4dc45..8d8a8496476 100644 --- a/fs/ceph/auth_x.c +++ b/fs/ceph/auth_x.c @@ -156,7 +156,11 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, struct timespec validity; struct ceph_crypto_key old_key; void *tp, *tpend; + struct ceph_timespec new_validity; + struct ceph_crypto_key new_session_key; struct ceph_buffer *new_ticket_blob; + unsigned long new_expires, new_renew_after; + u64 new_secret_id; ceph_decode_need(&p, end, sizeof(u32) + 1, bad); @@ -189,16 +193,16 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, goto bad; memcpy(&old_key, &th->session_key, sizeof(old_key)); - ret = ceph_crypto_key_decode(&th->session_key, &dp, dend); + ret = ceph_crypto_key_decode(&new_session_key, &dp, dend); if (ret) goto out; - ceph_decode_copy(&dp, &th->validity, sizeof(th->validity)); - ceph_decode_timespec(&validity, &th->validity); - th->expires = get_seconds() + validity.tv_sec; - th->renew_after = th->expires - (validity.tv_sec / 4); - dout(" expires=%lu renew_after=%lu\n", th->expires, - th->renew_after); + ceph_decode_copy(&dp, &new_validity, sizeof(new_validity)); + ceph_decode_timespec(&validity, &new_validity); + new_expires = get_seconds() + validity.tv_sec; + new_renew_after = new_expires - (validity.tv_sec / 4); + dout(" expires=%lu renew_after=%lu\n", new_expires, + new_renew_after); /* ticket blob for service */ ceph_decode_8_safe(&p, end, is_enc, bad); @@ -223,13 +227,21 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, dout(" ticket blob is %d bytes\n", dlen); ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad); struct_v = ceph_decode_8(&tp); - th->secret_id = ceph_decode_64(&tp); + new_secret_id = ceph_decode_64(&tp); ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend); if (ret) goto out; + + /* all is well, update our ticket */ + ceph_crypto_key_destroy(&th->session_key); if (th->ticket_blob) ceph_buffer_put(th->ticket_blob); + th->session_key = new_session_key; th->ticket_blob = new_ticket_blob; + th->validity = new_validity; + th->secret_id = new_secret_id; + th->expires = new_expires; + th->renew_after = new_renew_after; dout(" got ticket service %d (%s) secret_id %lld len %d\n", type, ceph_entity_type_name(type), th->secret_id, (int)th->ticket_blob->vec.iov_len); From 12eadc190038e68b5884a4aa313b6ab89ba60f5e Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 15 Mar 2010 22:20:39 -0700 Subject: [PATCH 196/478] ceph: fix null pointer deref of r_osd in debug output This causes an oops when debug output is enabled and we kick an osd request with no current r_osd (sometime after an osd failure). Check the pointer before dereferencing. Signed-off-by: Sage Weil --- fs/ceph/osd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c index dbe63db9762..221038253e6 100644 --- a/fs/ceph/osd_client.c +++ b/fs/ceph/osd_client.c @@ -913,7 +913,7 @@ static int __kick_requests(struct ceph_osd_client *osdc, kick: dout("kicking %p tid %llu osd%d\n", req, req->r_tid, - req->r_osd->o_osd); + req->r_osd ? req->r_osd->o_osd : -1); req->r_flags |= CEPH_OSD_FLAG_RETRY; err = __send_request(osdc, req); if (err) { From 4ea0043a29c82ca52ca54728d837314563bec574 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 16 Mar 2010 10:36:40 -0700 Subject: [PATCH 197/478] ceph: drop unnecessary WARN_ON in caps migration If we don't have the exported cap it's because we already released it. No need to WARN. Signed-off-by: Sage Weil --- fs/ceph/caps.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 57d9b44a882..726c8d44599 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2550,9 +2550,8 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, ci->i_cap_exporting_issued = cap->issued; } __ceph_remove_cap(cap); - } else { - WARN_ON(!cap); } + /* else, we already released it */ spin_unlock(&inode->i_lock); } From cdc2ce056a3620139056b60ad7f6d355ad13f445 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 16 Mar 2010 13:39:28 -0700 Subject: [PATCH 198/478] ceph: fix session locking in handle_caps, ceph_check_caps Passing a session pointer to ceph_check_caps() used to mean it would leave the session mutex locked. That wasn't always possible if it wasn't passed CHECK_CAPS_AUTHONLY. If could unlock the passed session and lock a differet session mutex, which was clearly wrong, and also emitted a warning when it a racing CPU retook it and we did an unlock from the wrong context. This was only a problem when there was more than one MDS. First, make ceph_check_caps unconditionally drop the session mutex, so that it is free to lock other sessions as needed. Then adjust the one caller that passes in a session (handle_cap_grant) accordingly. Signed-off-by: Sage Weil --- fs/ceph/caps.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 726c8d44599..782848632e8 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1407,6 +1407,7 @@ static int try_nonblocking_invalidate(struct inode *inode) */ void ceph_check_caps(struct ceph_inode_info *ci, int flags, struct ceph_mds_session *session) + __releases(session->s_mutex) { struct ceph_client *client = ceph_inode_to_client(&ci->vfs_inode); struct ceph_mds_client *mdsc = &client->mdsc; @@ -1414,7 +1415,6 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, struct ceph_cap *cap; int file_wanted, used; int took_snap_rwsem = 0; /* true if mdsc->snap_rwsem held */ - int drop_session_lock = session ? 0 : 1; int issued, implemented, want, retain, revoking, flushing = 0; int mds = -1; /* keep track of how far we've gone through i_caps list to avoid an infinite loop on retry */ @@ -1639,7 +1639,7 @@ ack: if (queue_invalidate) ceph_queue_invalidate(inode); - if (session && drop_session_lock) + if (session) mutex_unlock(&session->s_mutex); if (took_snap_rwsem) up_read(&mdsc->snap_rwsem); @@ -2688,14 +2688,17 @@ void ceph_handle_caps(struct ceph_mds_session *session, case CEPH_CAP_OP_REVOKE: case CEPH_CAP_OP_GRANT: r = handle_cap_grant(inode, h, session, cap, msg->middle); - if (r == 1) + if (r == 1) { ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY, session); - else if (r == 2) + session = NULL; + } else if (r == 2) { ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, session); + session = NULL; + } break; case CEPH_CAP_OP_FLUSH_ACK: @@ -2713,7 +2716,8 @@ void ceph_handle_caps(struct ceph_mds_session *session, } done: - mutex_unlock(&session->s_mutex); + if (session) + mutex_unlock(&session->s_mutex); if (check_caps) ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, NULL); From 15637c8b1251c38694c32214eba69b72a30e9d9b Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 16 Mar 2010 13:42:00 -0700 Subject: [PATCH 199/478] ceph: clean up handle_cap_grant, handle_caps wrt session mutex Drop session mutex unconditionally in handle_cap_grant, and do the check_caps from the handle_cap_grant helper. This avoids using a magic return value. Also avoid using a flag variable in the IMPORT case and call check_caps at the appropriate point. Signed-off-by: Sage Weil --- fs/ceph/caps.c | 57 ++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 782848632e8..d9e860ff9f3 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2195,18 +2195,19 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, * Handle a cap GRANT message from the MDS. (Note that a GRANT may * actually be a revocation if it specifies a smaller cap set.) * - * caller holds s_mutex. + * caller holds s_mutex and i_lock, we drop both. + * * return value: * 0 - ok * 1 - check_caps on auth cap only (writeback) * 2 - check_caps (ack revoke) */ -static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, - struct ceph_mds_session *session, - struct ceph_cap *cap, - struct ceph_buffer *xattr_buf) +static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, + struct ceph_mds_session *session, + struct ceph_cap *cap, + struct ceph_buffer *xattr_buf) __releases(inode->i_lock) - + __releases(session->s_mutex) { struct ceph_inode_info *ci = ceph_inode(inode); int mds = session->s_mds; @@ -2216,7 +2217,7 @@ static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, u64 size = le64_to_cpu(grant->size); u64 max_size = le64_to_cpu(grant->max_size); struct timespec mtime, atime, ctime; - int reply = 0; + int check_caps = 0; int wake = 0; int writeback = 0; int revoked_rdcache = 0; @@ -2329,10 +2330,10 @@ static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, if ((used & ~newcaps) & CEPH_CAP_FILE_BUFFER) writeback = 1; /* will delay ack */ else if (dirty & ~newcaps) - reply = 1; /* initiate writeback in check_caps */ + check_caps = 1; /* initiate writeback in check_caps */ else if (((used & ~newcaps) & CEPH_CAP_FILE_CACHE) == 0 || revoked_rdcache) - reply = 2; /* send revoke ack in check_caps */ + check_caps = 2; /* send revoke ack in check_caps */ cap->issued = newcaps; cap->implemented |= newcaps; } else if (cap->issued == newcaps) { @@ -2361,7 +2362,14 @@ static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, ceph_queue_invalidate(inode); if (wake) wake_up(&ci->i_cap_wq); - return reply; + + if (check_caps == 1) + ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY, + session); + else if (check_caps == 2) + ceph_check_caps(ci, CHECK_CAPS_NODELAY, session); + else + mutex_unlock(&session->s_mutex); } /* @@ -2622,9 +2630,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, u64 cap_id; u64 size, max_size; u64 tid; - int check_caps = 0; void *snaptrace; - int r; dout("handle_caps from mds%d\n", mds); @@ -2669,8 +2675,9 @@ void ceph_handle_caps(struct ceph_mds_session *session, case CEPH_CAP_OP_IMPORT: handle_cap_import(mdsc, inode, h, session, snaptrace, le32_to_cpu(h->snap_trace_len)); - check_caps = 1; /* we may have sent a RELEASE to the old auth */ - goto done; + ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, + session); + goto done_unlocked; } /* the rest require a cap */ @@ -2687,19 +2694,8 @@ void ceph_handle_caps(struct ceph_mds_session *session, switch (op) { case CEPH_CAP_OP_REVOKE: case CEPH_CAP_OP_GRANT: - r = handle_cap_grant(inode, h, session, cap, msg->middle); - if (r == 1) { - ceph_check_caps(ceph_inode(inode), - CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY, - session); - session = NULL; - } else if (r == 2) { - ceph_check_caps(ceph_inode(inode), - CHECK_CAPS_NODELAY, - session); - session = NULL; - } - break; + handle_cap_grant(inode, h, session, cap, msg->middle); + goto done_unlocked; case CEPH_CAP_OP_FLUSH_ACK: handle_cap_flush_ack(inode, tid, h, session, cap); @@ -2716,11 +2712,8 @@ void ceph_handle_caps(struct ceph_mds_session *session, } done: - if (session) - mutex_unlock(&session->s_mutex); - - if (check_caps) - ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, NULL); + mutex_unlock(&session->s_mutex); +done_unlocked: if (inode) iput(inode); return; From 916623da10e270c7e9e802a7ddfe1ec8f890982d Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 16 Mar 2010 15:01:07 -0700 Subject: [PATCH 200/478] ceph: only release unused caps with mds requests We were releasing used caps (e.g. FILE_CACHE) from encode_inode_release with MDS requests (e.g. setattr). We don't carry refs on most caps, so this code worked most of the time, but for setattr (utimes) we try to drop Fscr. This causes cap state to get slightly out of sync with reality, and may result in subsequent mds revoke messages getting ignored. Fix by only releasing unused caps. Signed-off-by: Sage Weil --- fs/ceph/caps.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index d9e860ff9f3..7d0a0d0adc1 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2836,11 +2836,18 @@ int ceph_encode_inode_release(void **p, struct inode *inode, struct ceph_cap *cap; struct ceph_mds_request_release *rel = *p; int ret = 0; - - dout("encode_inode_release %p mds%d drop %s unless %s\n", inode, - mds, ceph_cap_string(drop), ceph_cap_string(unless)); + int used = 0; spin_lock(&inode->i_lock); + used = __ceph_caps_used(ci); + + dout("encode_inode_release %p mds%d used %s drop %s unless %s\n", inode, + mds, ceph_cap_string(used), ceph_cap_string(drop), + ceph_cap_string(unless)); + + /* only drop unused caps */ + drop &= ~used; + cap = __get_cap_for_mds(ci, mds); if (cap && __cap_is_valid(cap)) { if (force || From 80fc7314a7e26e8d2e4ba5b3d8cc2d4aeb750015 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 16 Mar 2010 15:28:54 -0700 Subject: [PATCH 201/478] ceph: fix mds sync() race with completing requests The wait_unsafe_requests() helper dropped the mdsc mutex to wait for each request to complete, and then examined r_node to get the next request after retaking the lock. But the request completion removes the request from the tree, so r_node was always undefined at this point. Since it's a small race, it usually led to a valid request, but not always. The result was an occasional crash in rb_next() while dereferencing node->rb_left. Fix this by clearing the rb_node when removing the request from the request tree, and not walking off into the weeds when we are done waiting for a request. Since the request we waited on will _always_ be out of the request tree, take a ref on the next request, in the hopes that it won't be. But if it is, it's ok: we can start over from the beginning (and traverse over older read requests again). Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index a2600101ec2..5ec86419836 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -529,6 +529,7 @@ static void __unregister_request(struct ceph_mds_client *mdsc, { dout("__unregister_request %p tid %lld\n", req, req->r_tid); rb_erase(&req->r_node, &mdsc->request_tree); + RB_CLEAR_NODE(&req->r_node); ceph_mdsc_put_request(req); if (req->r_unsafe_dir) { @@ -2682,29 +2683,41 @@ void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc) */ static void wait_unsafe_requests(struct ceph_mds_client *mdsc, u64 want_tid) { - struct ceph_mds_request *req = NULL; + struct ceph_mds_request *req = NULL, *nextreq; struct rb_node *n; mutex_lock(&mdsc->mutex); dout("wait_unsafe_requests want %lld\n", want_tid); +restart: req = __get_oldest_req(mdsc); while (req && req->r_tid <= want_tid) { + /* find next request */ + n = rb_next(&req->r_node); + if (n) + nextreq = rb_entry(n, struct ceph_mds_request, r_node); + else + nextreq = NULL; if ((req->r_op & CEPH_MDS_OP_WRITE)) { /* write op */ ceph_mdsc_get_request(req); + if (nextreq) + ceph_mdsc_get_request(nextreq); mutex_unlock(&mdsc->mutex); dout("wait_unsafe_requests wait on %llu (want %llu)\n", req->r_tid, want_tid); wait_for_completion(&req->r_safe_completion); mutex_lock(&mdsc->mutex); - n = rb_next(&req->r_node); ceph_mdsc_put_request(req); - } else { - n = rb_next(&req->r_node); + if (!nextreq) + break; /* next dne before, so we're done! */ + if (RB_EMPTY_NODE(&nextreq->r_node)) { + /* next request was removed from tree */ + ceph_mdsc_put_request(nextreq); + goto restart; + } + ceph_mdsc_put_request(nextreq); /* won't go away */ } - if (!n) - break; - req = rb_entry(n, struct ceph_mds_request, r_node); + req = nextreq; } mutex_unlock(&mdsc->mutex); dout("wait_unsafe_requests done\n"); From efd7576b2392cc5a0934352936d793e8884c46bf Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 17 Mar 2010 10:05:28 -0700 Subject: [PATCH 202/478] ceph: fix pg pool decoding from incremental osdmap update The incremental map decoding of pg pool updates wasn't skipping the snaps and removed_snaps vectors. This caused osd requests to stall when pool snapshots were created or fs snapshots were deleted. Use a common helper for full and incremental map decoders that decodes pools properly. Signed-off-by: Sage Weil --- fs/ceph/osdmap.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/ceph/osdmap.c b/fs/ceph/osdmap.c index b83f2692b83..d82fe87c2a6 100644 --- a/fs/ceph/osdmap.c +++ b/fs/ceph/osdmap.c @@ -480,6 +480,14 @@ static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, int id) return NULL; } +void __decode_pool(void **p, struct ceph_pg_pool_info *pi) +{ + ceph_decode_copy(p, &pi->v, sizeof(pi->v)); + calc_pg_masks(pi); + *p += le32_to_cpu(pi->v.num_snaps) * sizeof(u64); + *p += le32_to_cpu(pi->v.num_removed_snap_intervals) * sizeof(u64) * 2; +} + /* * decode a full map. */ @@ -526,12 +534,8 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) ev, CEPH_PG_POOL_VERSION); goto bad; } - ceph_decode_copy(p, &pi->v, sizeof(pi->v)); + __decode_pool(p, pi); __insert_pg_pool(&map->pg_pools, pi); - calc_pg_masks(pi); - *p += le32_to_cpu(pi->v.num_snaps) * sizeof(u64); - *p += le32_to_cpu(pi->v.num_removed_snap_intervals) - * sizeof(u64) * 2; } ceph_decode_32_safe(p, end, map->pool_max, bad); @@ -714,8 +718,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, pi->id = pool; __insert_pg_pool(&map->pg_pools, pi); } - ceph_decode_copy(p, &pi->v, sizeof(pi->v)); - calc_pg_masks(pi); + __decode_pool(p, pi); } /* old_pool */ From e4cb4cb8a03adde1aa4b874623c50b9a5b56e635 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 18 Mar 2010 13:43:09 -0700 Subject: [PATCH 203/478] ceph: prevent dup stale messages to console for restarting mds Prevent duplicate 'mds0 caps stale' message from spamming the console every few seconds while the MDS restarts. Set s_renew_requested earlier, so that we only print the message once, even if we don't send an actual request. Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 5ec86419836..5cbf46abfee 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -863,6 +863,7 @@ static int send_renew_caps(struct ceph_mds_client *mdsc, if (time_after_eq(jiffies, session->s_cap_ttl) && time_after_eq(session->s_cap_ttl, session->s_renew_requested)) pr_info("mds%d caps stale\n", session->s_mds); + session->s_renew_requested = jiffies; /* do not try to renew caps until a recovering mds has reconnected * with its clients. */ @@ -875,7 +876,6 @@ static int send_renew_caps(struct ceph_mds_client *mdsc, dout("send_renew_caps to mds%d (%s)\n", session->s_mds, ceph_mds_state_name(state)); - session->s_renew_requested = jiffies; msg = create_session_msg(CEPH_SESSION_REQUEST_RENEWCAPS, ++session->s_renew_seq); if (IS_ERR(msg)) From 3c3f2e32effd4c6acc3a9434bd7eecb0af653d89 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 18 Mar 2010 15:20:53 -0700 Subject: [PATCH 204/478] ceph: fix connection fault con_work reentrancy problem The messenger fault was clearing the BUSY bit, for reasons unclear. This made it possible for the con->ops->fault function to reopen the connection, and requeue work in the workqueue--even though the current thread was already in con_work. This avoids a problem where the client busy loops with connection failures on an unreachable OSD, but doesn't address the root cause of that problem. Signed-off-by: Sage Weil --- fs/ceph/messenger.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ceph/messenger.c b/fs/ceph/messenger.c index 203c4359b54..98328554094 100644 --- a/fs/ceph/messenger.c +++ b/fs/ceph/messenger.c @@ -1836,8 +1836,6 @@ static void ceph_fault(struct ceph_connection *con) goto out; } - clear_bit(BUSY, &con->state); /* to avoid an improbable race */ - mutex_lock(&con->mutex); if (test_bit(CLOSED, &con->state)) goto out_unlock; From 3dd72fc0e6dc49c79fa9e7cd7c654deac7ccaa29 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 22 Mar 2010 14:42:30 -0700 Subject: [PATCH 205/478] ceph: rename r_sent_stamp r_stamp Make variable name slightly more generic, since it will (soon) reflect either the time the request was sent OR the time it was last determined to be still retrying. Signed-off-by: Sage Weil --- fs/ceph/osd_client.c | 12 ++++++------ fs/ceph/osd_client.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c index 221038253e6..04359217ea6 100644 --- a/fs/ceph/osd_client.c +++ b/fs/ceph/osd_client.c @@ -633,7 +633,7 @@ static int __send_request(struct ceph_osd_client *osdc, reqhead->flags |= cpu_to_le32(req->r_flags); /* e.g., RETRY */ reqhead->reassert_version = req->r_reassert_version; - req->r_sent_stamp = jiffies; + req->r_stamp = jiffies; list_move_tail(&osdc->req_lru, &req->r_req_lru_item); ceph_msg_get(req->r_request); /* send consumes a ref */ @@ -660,7 +660,7 @@ static void handle_timeout(struct work_struct *work) unsigned long timeout = osdc->client->mount_args->osd_timeout * HZ; unsigned long keepalive = osdc->client->mount_args->osd_keepalive_timeout * HZ; - unsigned long last_sent = 0; + unsigned long last_stamp = 0; struct rb_node *p; struct list_head slow_osds; @@ -697,12 +697,12 @@ static void handle_timeout(struct work_struct *work) req = list_entry(osdc->req_lru.next, struct ceph_osd_request, r_req_lru_item); - if (time_before(jiffies, req->r_sent_stamp + timeout)) + if (time_before(jiffies, req->r_stamp + timeout)) break; - BUG_ON(req == last_req && req->r_sent_stamp == last_sent); + BUG_ON(req == last_req && req->r_stamp == last_stamp); last_req = req; - last_sent = req->r_sent_stamp; + last_stamp = req->r_stamp; osd = req->r_osd; BUG_ON(!osd); @@ -718,7 +718,7 @@ static void handle_timeout(struct work_struct *work) */ INIT_LIST_HEAD(&slow_osds); list_for_each_entry(req, &osdc->req_lru, r_req_lru_item) { - if (time_before(jiffies, req->r_sent_stamp + keepalive)) + if (time_before(jiffies, req->r_stamp + keepalive)) break; osd = req->r_osd; diff --git a/fs/ceph/osd_client.h b/fs/ceph/osd_client.h index 1b1a3ca43af..b0759911e7c 100644 --- a/fs/ceph/osd_client.h +++ b/fs/ceph/osd_client.h @@ -70,7 +70,7 @@ struct ceph_osd_request { char r_oid[40]; /* object name */ int r_oid_len; - unsigned long r_sent_stamp; + unsigned long r_stamp; /* send OR check time */ bool r_resend; /* msg send failed, needs retry */ struct ceph_file_layout r_file_layout; From 87b315a5b5cec5d7086494b203577602f5befc8c Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 22 Mar 2010 14:51:18 -0700 Subject: [PATCH 206/478] ceph: avoid reopening osd connections when address hasn't changed We get a fault callback on _every_ tcp connection fault. Normally, we want to reopen the connection when that happens. If the address we have is bad, however, and connection attempts always result in a connection refused or similar error, explicitly closing and reopening the msgr connection just prevents the messenger's backoff logic from kicking in. The result can be a console full of [ 3974.417106] ceph: osd11 10.3.14.138:6800 connection failed [ 3974.423295] ceph: osd11 10.3.14.138:6800 connection failed [ 3974.429709] ceph: osd11 10.3.14.138:6800 connection failed Instead, if we get a fault, and have outstanding requests, but the osd address hasn't changed and the connection never successfully connected in the first place, do nothing to the osd connection. The messenger layer will back off and retry periodically, because we never connected and thus the lossy bit is not set. Instead, touch each request's r_stamp so that handle_timeout can tell the request is still alive and kicking. Signed-off-by: Sage Weil --- fs/ceph/messenger.c | 8 ++++++++ fs/ceph/messenger.h | 1 + fs/ceph/osd_client.c | 15 ++++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/fs/ceph/messenger.c b/fs/ceph/messenger.c index 98328554094..a32f0f896d9 100644 --- a/fs/ceph/messenger.c +++ b/fs/ceph/messenger.c @@ -365,6 +365,14 @@ void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr) queue_con(con); } +/* + * return true if this connection ever successfully opened + */ +bool ceph_con_opened(struct ceph_connection *con) +{ + return con->connect_seq > 0; +} + /* * generic get/put */ diff --git a/fs/ceph/messenger.h b/fs/ceph/messenger.h index 4caaa591111..a343dae73cd 100644 --- a/fs/ceph/messenger.h +++ b/fs/ceph/messenger.h @@ -223,6 +223,7 @@ extern void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con); extern void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr); +extern bool ceph_con_opened(struct ceph_connection *con); extern void ceph_con_close(struct ceph_connection *con); extern void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg); extern void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg); diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c index 04359217ea6..c7b4dedaace 100644 --- a/fs/ceph/osd_client.c +++ b/fs/ceph/osd_client.c @@ -413,11 +413,22 @@ static void remove_old_osds(struct ceph_osd_client *osdc, int remove_all) */ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) { + struct ceph_osd_request *req; int ret = 0; dout("__reset_osd %p osd%d\n", osd, osd->o_osd); if (list_empty(&osd->o_requests)) { __remove_osd(osdc, osd); + } else if (memcmp(&osdc->osdmap->osd_addr[osd->o_osd], + &osd->o_con.peer_addr, + sizeof(osd->o_con.peer_addr)) == 0 && + !ceph_con_opened(&osd->o_con)) { + dout(" osd addr hasn't changed and connection never opened," + " letting msgr retry"); + /* touch each r_stamp for handle_timeout()'s benfit */ + list_for_each_entry(req, &osd->o_requests, r_osd_item) + req->r_stamp = jiffies; + ret = -EAGAIN; } else { ceph_con_close(&osd->o_con); ceph_con_open(&osd->o_con, &osdc->osdmap->osd_addr[osd->o_osd]); @@ -862,7 +873,9 @@ static int __kick_requests(struct ceph_osd_client *osdc, dout("kick_requests osd%d\n", kickosd ? kickosd->o_osd : -1); if (kickosd) { - __reset_osd(osdc, kickosd); + err = __reset_osd(osdc, kickosd); + if (err == -EAGAIN) + return 1; } else { for (p = rb_first(&osdc->osds); p; p = n) { struct ceph_osd *osd = From ec4318bcb4c59d8b8bf7037c9f444a9887ccb265 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 19 Mar 2010 13:24:39 -0700 Subject: [PATCH 207/478] ceph: fix snap rebuild condition We were rebuilding the snap context when it was not necessary (i.e. when the realm seq hadn't changed _and_ the parent seq was still older), which caused page snapc pointers to not match the realm's snapc pointer (even though the snap context itself was identical). This confused begin_write and put it into an endless loop. The correct logic is: rebuild snapc if _my_ realm seq changed, or if my parent realm's seq is newer than mine (and thus mine needs to be rebuilt too). Signed-off-by: Sage Weil --- fs/ceph/snap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 8a43bc8675e..df04e210a05 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -314,9 +314,9 @@ static int build_snap_context(struct ceph_snap_realm *realm) because we rebuild_snap_realms() works _downward_ in hierarchy after each update.) */ if (realm->cached_context && - realm->cached_context->seq <= realm->seq && + realm->cached_context->seq == realm->seq && (!parent || - realm->cached_context->seq <= parent->cached_context->seq)) { + realm->cached_context->seq >= parent->cached_context->seq)) { dout("build_snap_context %llx %p: %p seq %lld (%d snaps)" " (unchanged)\n", realm->ino, realm, realm->cached_context, From 8f883c24de33ba929c95e018ac0ba66e4f46734b Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 19 Mar 2010 13:27:53 -0700 Subject: [PATCH 208/478] ceph: make write_begin wait propagate ERESTARTSYS Currently, if the wait_event_interruptible is interrupted, we return EAGAIN unconditionally and loop, such that we aren't, in fact, interruptible. So, propagate ERESTARTSYS if we get it. Signed-off-by: Sage Weil --- fs/ceph/addr.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 23bb0ceabe3..ce8ef610772 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -919,6 +919,10 @@ static int context_is_writeable_or_written(struct inode *inode, /* * We are only allowed to write into/dirty the page if the page is * clean, or already dirty within the same snap context. + * + * called with page locked. + * return success with page locked, + * or any failure (incl -EAGAIN) with page unlocked. */ static int ceph_update_writeable_page(struct file *file, loff_t pos, unsigned len, @@ -961,9 +965,11 @@ retry_locked: snapc = ceph_get_snap_context((void *)page->private); unlock_page(page); ceph_queue_writeback(inode); - wait_event_interruptible(ci->i_cap_wq, + r = wait_event_interruptible(ci->i_cap_wq, context_is_writeable_or_written(inode, snapc)); ceph_put_snap_context(snapc); + if (r == -ERESTARTSYS) + return r; return -EAGAIN; } @@ -1035,7 +1041,7 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, int r; do { - /* get a page*/ + /* get a page */ page = grab_cache_page_write_begin(mapping, index, 0); if (!page) return -ENOMEM; From 9c423956b8a495f0c048143abc5da955a70eac97 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sat, 20 Mar 2010 20:43:28 -0700 Subject: [PATCH 209/478] ceph: propagate mds session allocation failures to caller Return error to original caller if register_session() fails. Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 5cbf46abfee..b6b5348055f 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1567,8 +1567,13 @@ static int __do_request(struct ceph_mds_client *mdsc, /* get, open session */ session = __ceph_lookup_mds_session(mdsc, mds); - if (!session) + if (!session) { session = register_session(mdsc, mds); + if (IS_ERR(session)) { + err = PTR_ERR(session); + goto finish; + } + } dout("do_request mds%d session %p state %s\n", mds, session, session_state_name(session->s_state)); if (session->s_state != CEPH_MDS_SESSION_OPEN && From 4736b009b880b7c19bea36327a71032a6dbee402 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 20 Mar 2010 15:30:16 +0300 Subject: [PATCH 210/478] ceph: handle kmalloc() failure Return ERR_PTR(-ENOMEM) if kmalloc() fails. We handle allocation failures the same way later in the function. Signed-off-by: Dan Carpenter Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index b6b5348055f..ad0fbc3128d 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -328,6 +328,8 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, struct ceph_mds_session *s; s = kzalloc(sizeof(*s), GFP_NOFS); + if (!s) + return ERR_PTR(-ENOMEM); s->s_mdsc = mdsc; s->s_mds = mds; s->s_state = CEPH_MDS_SESSION_NEW; From d96d60498ff748c5a88c72ec5d1cc4ba9a583e7e Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sat, 20 Mar 2010 20:50:58 -0700 Subject: [PATCH 211/478] ceph: fix session check on mds reply Fix a broken check that a reply came back from the same MDS we sent the request to. I don't think a case that actually triggers this would ever come up in practice, but it's clearly wrong and easy to fix. Reported-by: Dan Carpenter Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index ad0fbc3128d..5268d404963 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1778,7 +1778,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) dout("handle_reply %p\n", req); /* correct session? */ - if (!req->r_session && req->r_session != session) { + if (req->r_session != session) { pr_err("mdsc_handle_reply got %llu on session mds%d" " not mds%d\n", tid, session->s_mds, req->r_session ? req->r_session->s_mds : -1); From 393f66209669ad23f4f6d4191234c1df4367df3c Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 10 Mar 2010 12:03:32 -0800 Subject: [PATCH 212/478] ceph: fix possible double-free of mds request reference Clear pointer to mds request after dropping the reference to ensure we don't drop it again, as there is at least one error path through this function that does not reset fi->last_readdir to a new value. Signed-off-by: Sage Weil --- fs/ceph/dir.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 5107384ee02..8a9116e15b7 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -288,8 +288,10 @@ more: CEPH_MDS_OP_LSSNAP : CEPH_MDS_OP_READDIR; /* discard old result, if any */ - if (fi->last_readdir) + if (fi->last_readdir) { ceph_mdsc_put_request(fi->last_readdir); + fi->last_readdir = NULL; + } /* requery frag tree, as the frag topology may have changed */ frag = ceph_choose_frag(ceph_inode(inode), frag, NULL, NULL); From 23ab15ad7a9d042afa7303b735b6e24faa607241 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 22 Mar 2010 09:37:14 -0700 Subject: [PATCH 213/478] ceph: avoid loaded term 'OSD' in documention 'OSD' means different things to different people; avoid it here to avoid confusion. Signed-off-by: Sage Weil --- Documentation/filesystems/ceph.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/filesystems/ceph.txt b/Documentation/filesystems/ceph.txt index 6e03917316b..523fdf0828d 100644 --- a/Documentation/filesystems/ceph.txt +++ b/Documentation/filesystems/ceph.txt @@ -115,7 +115,7 @@ Mount Options number of entries in that directory. nocrc - Disable CRC32C calculation for data writes. If set, the OSD + Disable CRC32C calculation for data writes. If set, the storage node must rely on TCP's error correction to detect data corruption in the data payload. From 110d735a0ae69bdd11af9acb6ea3b979137eb118 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 22 Mar 2010 21:36:06 +0900 Subject: [PATCH 214/478] nilfs2: fix hang-up of cleaner after log writer returned with error According to the report from Andreas Beckmann (Message-ID: <4BA54677.3090902@abeckmann.de>), nilfs in 2.6.33 kernel got stuck after a disk full error. This turned out to be a regression by log writer updates merged at kernel 2.6.33. nilfs_segctor_abort_construction, which is a cleanup function for erroneous cases, was skipping writeback completion for some logs. This fixes the bug and would resolve the hang issue. Reported-by: Andreas Beckmann Signed-off-by: Ryusuke Konishi Tested-by: Ryusuke Konishi Cc: stable [2.6.33.x] --- fs/nilfs2/segment.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index b6221230f84..c161d89061b 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -1897,8 +1897,7 @@ static void nilfs_segctor_abort_construction(struct nilfs_sc_info *sci, list_splice_tail_init(&sci->sc_write_logs, &logs); ret = nilfs_wait_on_logs(&logs); - if (ret) - nilfs_abort_logs(&logs, NULL, sci->sc_super_root, ret); + nilfs_abort_logs(&logs, NULL, sci->sc_super_root, ret ? : err); list_splice_tail_init(&sci->sc_segbufs, &logs); nilfs_cancel_segusage(&logs, nilfs->ns_sufile); From 5cbb2b941d2cc77e6b915e8e55d375be632c9f6a Mon Sep 17 00:00:00 2001 From: Komuro Date: Sat, 20 Mar 2010 06:39:19 +0900 Subject: [PATCH 215/478] pd6729: Coding Style fixes Signed-off-by: Komuro Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pd6729.c | 64 +++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 7ba57a565cd..47f342f1b0f 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -14,13 +14,13 @@ #include #include #include +#include #include #include #include #include -#include #include "pd6729.h" #include "i82365.h" @@ -222,9 +222,9 @@ static irqreturn_t pd6729_interrupt(int irq, void *dev) ? SS_READY : 0; } - if (events) { + if (events) pcmcia_parse_events(&socket[i].socket, events); - } + active |= events; } @@ -256,9 +256,8 @@ static int pd6729_get_status(struct pcmcia_socket *sock, u_int *value) status = indirect_read(socket, I365_STATUS); *value = 0; - if ((status & I365_CS_DETECT) == I365_CS_DETECT) { + if ((status & I365_CS_DETECT) == I365_CS_DETECT) *value |= SS_DETECT; - } /* * IO cards have a different meaning of bits 0,1 @@ -308,7 +307,7 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) socket->card_irq = state->io_irq; reg = 0; - /* The reset bit has "inverse" logic */ + /* The reset bit has "inverse" logic */ if (!(state->flags & SS_RESET)) reg |= I365_PC_RESET; if (state->flags & SS_IOCARD) @@ -380,7 +379,7 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) indirect_write(socket, I365_POWER, reg); if (irq_mode == 1) { - /* all interrupts are to be done as PCI interrupts */ + /* all interrupts are to be done as PCI interrupts */ data = PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ; } else data = 0; @@ -391,9 +390,9 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) /* Enable specific interrupt events */ reg = 0x00; - if (state->csc_mask & SS_DETECT) { + if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; - } + if (state->flags & SS_IOCARD) { if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG; @@ -450,9 +449,12 @@ static int pd6729_set_io_map(struct pcmcia_socket *sock, ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map); - if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); - if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); - if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); + if (io->flags & MAP_0WS) + ioctl |= I365_IOCTL_0WS(map); + if (io->flags & MAP_16BIT) + ioctl |= I365_IOCTL_16BIT(map); + if (io->flags & MAP_AUTOSZ) + ioctl |= I365_IOCTL_IOCS16(map); indirect_write(socket, I365_IOCTL, ioctl); @@ -497,7 +499,7 @@ static int pd6729_set_mem_map(struct pcmcia_socket *sock, /* write the stop address */ - i= (mem->res->end >> 12) & 0x0fff; + i = (mem->res->end >> 12) & 0x0fff; switch (to_cycles(mem->speed)) { case 0: break; @@ -563,7 +565,7 @@ static int pd6729_init(struct pcmcia_socket *sock) /* the pccard structure and its functions */ static struct pccard_operations pd6729_operations = { - .init = pd6729_init, + .init = pd6729_init, .get_status = pd6729_get_status, .set_socket = pd6729_set_socket, .set_io_map = pd6729_set_io_map, @@ -578,8 +580,13 @@ static irqreturn_t pd6729_test(int irq, void *dev) static int pd6729_check_irq(int irq) { - if (request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x", pd6729_test) - != 0) return -1; + int ret; + + ret = request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x", + pd6729_test); + if (ret) + return -1; + free_irq(irq, pd6729_test); return 0; } @@ -591,7 +598,7 @@ static u_int __devinit pd6729_isa_scan(void) if (irq_mode == 1) { printk(KERN_INFO "pd6729: PCI card interrupts, " - "PCI status changes\n"); + "PCI status changes\n"); return 0; } @@ -607,9 +614,10 @@ static u_int __devinit pd6729_isa_scan(void) if (mask & (1<dev, "failed to kzalloc socket.\n"); return -ENOMEM; + } - if ((ret = pci_enable_device(dev))) + ret = pci_enable_device(dev); + if (ret) { + dev_warn(&dev->dev, "failed to enable pci_device.\n"); goto err_out_free_mem; + } if (!pci_resource_start(dev, 0)) { dev_warn(&dev->dev, "refusing to load the driver as the " @@ -639,7 +652,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, dev_info(&dev->dev, "Cirrus PD6729 PCI to PCMCIA Bridge at 0x%llx " "on irq %d\n", (unsigned long long)pci_resource_start(dev, 0), dev->irq); - /* + /* * Since we have no memory BARs some firmware may not * have had PCI_COMMAND_MEMORY enabled, yet the device needs it. */ @@ -685,8 +698,9 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, pci_set_drvdata(dev, socket); if (irq_mode == 1) { /* Register the interrupt handler */ - if ((ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED, - "pd6729", socket))) { + ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED, + "pd6729", socket); + if (ret) { dev_err(&dev->dev, "Failed to register irq %d\n", dev->irq); goto err_out_free_res; From 830ec0458c390f29c6c99e1ff7feab9e36368d12 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Thu, 18 Mar 2010 14:47:30 -0700 Subject: [PATCH 216/478] time: Fix accumulation bug triggered by long delay. The logarithmic accumulation done in the timekeeping has some overflow protection that limits the max shift value. That means it will take more then shift loops to accumulate all of the cycles. This causes the shift decrement to underflow, which causes the loop to never exit. The simplest fix would be simply to do a: if (shift) shift--; However that is not optimal, as we know the cycle offset is larger then the interval << shift, the above would make shift drop to zero, then we would be spinning for quite awhile accumulating at interval chunks at a time. Instead, this patch only decreases shift if the offset is smaller then cycle_interval << shift. This makes sure we accumulate using the largest chunks possible without overflowing tick_length, and limits the number of iterations through the loop. This issue was found and reported by Sonic Zhang, who also tested the fix. Many thanks your explanation and testing! Reported-by: Sonic Zhang Signed-off-by: John Stultz Tested-by: Sonic Zhang LKML-Reference: <1268948850-5225-1-git-send-email-johnstul@us.ibm.com> Signed-off-by: Thomas Gleixner --- kernel/time/timekeeping.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 16736379a9c..39f6177fafa 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -818,7 +818,8 @@ void update_wall_time(void) shift = min(shift, maxshift); while (offset >= timekeeper.cycle_interval) { offset = logarithmic_accumulation(offset, shift); - shift--; + if(offset < timekeeper.cycle_interval< Date: Mon, 22 Mar 2010 19:33:43 +0900 Subject: [PATCH 217/478] nilfs2: fix imperfect completion wait in nilfs_wait_on_logs nilfs_wait_on_logs has a potential to slip out before completion of all bio requests when it met an error. This synchronization fault may cause unexpected results, for instance, violative access to freed segment buffers from an end-bio callback routine. This fixes the issue by ensuring that nilfs_wait_on_logs waits all given logs. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/segbuf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 636eaafd6ea..6129a431aa3 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -323,14 +323,14 @@ int nilfs_write_logs(struct list_head *logs, struct the_nilfs *nilfs) int nilfs_wait_on_logs(struct list_head *logs) { struct nilfs_segment_buffer *segbuf; - int err; + int err, ret = 0; list_for_each_entry(segbuf, logs, sb_list) { err = nilfs_segbuf_wait(segbuf); - if (err) - return err; + if (err && !ret) + ret = err; } - return 0; + return ret; } /* From 9705c3961e73054b656720884f0da0a5a438fbae Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 8 Mar 2010 15:25:29 -0800 Subject: [PATCH 218/478] [ARM] Kirkwood: WPS button keycode mapping Commit "Input: add KEY_WPS_BUTTON definition" added a generic keycode for WPS button. Let's use it, instead of "F1" mapping. Signed-off-by: Christian Lamparter Signed-off-by: Nicolas Pitre --- arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c index 0358f45766c..5e6f711b1c6 100644 --- a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c +++ b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c @@ -74,9 +74,9 @@ static struct gpio_keys_button mv88f6281gtw_ge_button_pins[] = { .desc = "SWR Button", .active_low = 1, }, { - .code = KEY_F1, + .code = KEY_WPS_BUTTON, .gpio = 46, - .desc = "WPS Button(F1)", + .desc = "WPS Button", .active_low = 1, }, }; From bb456928913fda2b360376afb13d9a0bc72c761c Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 8 Mar 2010 15:26:35 -0800 Subject: [PATCH 219/478] [ARM] Orion5x: replace KEY_WLAN with KEY_WPS_BUTTON "Input: add KEY_WPS_BUTTON definition" introduced a generic keycode for WPS input events. Signed-off-by: Christian Lamparter Signed-off-by: Nicolas Pitre --- arch/arm/mach-orion5x/wrt350n-v2-setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c index cb0feca193d..f9f222ebb7e 100644 --- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c +++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c @@ -77,7 +77,7 @@ static struct gpio_keys_button wrt350n_v2_buttons[] = { .desc = "Reset Button", .active_low = 1, }, { - .code = KEY_WLAN, + .code = KEY_WPS_BUTTON, .gpio = 2, .desc = "WPS Button", .active_low = 1, From 9713ab28ec92d0c44b2ac5765dfc26c619d9cadd Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 23 Mar 2010 16:05:00 +0100 Subject: [PATCH 220/478] pcmcia: do not use ioports < 0x100 on x86 On x86 systems using ACPI _CRS information -- now the default for post-2008 systems -- the PCI root bus no longer pretends to be offering the root ioport_resource. To avoid accidentally hitting some platform / system device, use only I/O ports >= 0x100 for PCMCIA devices on x86. Reported-by: Komuro CC: Bjorn Helgaas Signed-off-by: Dominik Brodowski --- drivers/pcmcia/rsrc_nonstatic.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 4663b3fa9f9..dcc602134d9 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -810,6 +810,13 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long unsigned long size = end - start + 1; int ret = 0; +#if defined(CONFIG_X86) + /* on x86, avoid anything < 0x100 for it is often used for + * legacy platform devices */ + if (start < 0x100) + start = 0x100; +#endif + if (end < start) return -EINVAL; From 6e6c822868f113dabe3c33bdd91e883cc28fa11b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 17 Mar 2010 13:48:06 -0700 Subject: [PATCH 221/478] drm/i915: Stop trying to use ACPI lid status to determine LVDS connection. I've been getting more and more quirk reports about this. It seems clear at this point that other OSes are not using this for determining whether the integrated panel should be turned on, and it is not reliable for doing so. Better to light up an unintended panel than to not light up the only usable output on the system. Signed-off-by: Eric Anholt Acked-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_lvds.c | 52 +------------------------------ 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 14e516fdc2d..2b3fa7a3c02 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -607,53 +607,6 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control); } -/* Some lid devices report incorrect lid status, assume they're connected */ -static const struct dmi_system_id bad_lid_status[] = { - { - .ident = "Compaq nx9020", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_BOARD_NAME, "3084"), - }, - }, - { - .ident = "Samsung SX20S", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), - DMI_MATCH(DMI_BOARD_NAME, "SX20S"), - }, - }, - { - .ident = "Aspire One", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire one"), - }, - }, - { - .ident = "Aspire 1810T", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1810T"), - }, - }, - { - .ident = "PC-81005", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "MALATA"), - DMI_MATCH(DMI_PRODUCT_NAME, "PC-81005"), - }, - }, - { - .ident = "Clevo M5x0N", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."), - DMI_MATCH(DMI_BOARD_NAME, "M5x0N"), - }, - }, - { } -}; - /** * Detect the LVDS connection. * @@ -669,12 +622,9 @@ static enum drm_connector_status intel_lvds_detect(struct drm_connector *connect /* ACPI lid methods were generally unreliable in this generation, so * don't even bother. */ - if (IS_GEN2(dev)) + if (IS_GEN2(dev) || IS_GEN3(dev)) return connector_status_connected; - if (!dmi_check_system(bad_lid_status) && !acpi_lid_open()) - status = connector_status_disconnected; - return status; } From 8e039d84b323c4503c4d56863faa47c783660826 Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Tue, 23 Mar 2010 05:24:03 +0000 Subject: [PATCH 222/478] cgroups: net_cls as module Allows the net_cls cgroup subsystem to be compiled as a module This patch modifies net/sched/cls_cgroup.c to allow the net_cls subsystem to be optionally compiled as a module instead of builtin. The cgroup_subsys struct is moved around a bit to allow the subsys_id to be either declared as a compile-time constant by the cgroup_subsys.h include in cgroup.h, or, if it's a module, initialized within the struct by cgroup_load_subsys. Signed-off-by: Ben Blum Acked-by: Li Zefan Cc: Paul Menage Cc: "David S. Miller" Cc: KAMEZAWA Hiroyuki Cc: Lai Jiangshan Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/sched/Kconfig | 5 ++++- net/sched/cls_cgroup.c | 36 +++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 21f9c7678aa..2f691fb180d 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -328,13 +328,16 @@ config NET_CLS_FLOW module will be called cls_flow. config NET_CLS_CGROUP - bool "Control Group Classifier" + tristate "Control Group Classifier" select NET_CLS depends on CGROUPS ---help--- Say Y here if you want to classify packets based on the control cgroup of their process. + To compile this code as a module, choose M here: the + module will be called cls_cgroup. + config NET_EMATCH bool "Extended Matches" select NET_CLS diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index e4877ca6727..7f27d2c15e0 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -24,6 +24,25 @@ struct cgroup_cls_state u32 classid; }; +static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, + struct cgroup *cgrp); +static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); +static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp); + +struct cgroup_subsys net_cls_subsys = { + .name = "net_cls", + .create = cgrp_create, + .destroy = cgrp_destroy, + .populate = cgrp_populate, +#ifdef CONFIG_NET_CLS_CGROUP + .subsys_id = net_cls_subsys_id, +#else +#define net_cls_subsys_id net_cls_subsys.subsys_id +#endif + .module = THIS_MODULE, +}; + + static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp) { return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id), @@ -79,14 +98,6 @@ static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp) return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); } -struct cgroup_subsys net_cls_subsys = { - .name = "net_cls", - .create = cgrp_create, - .destroy = cgrp_destroy, - .populate = cgrp_populate, - .subsys_id = net_cls_subsys_id, -}; - struct cls_cgroup_head { u32 handle; @@ -277,12 +288,19 @@ static struct tcf_proto_ops cls_cgroup_ops __read_mostly = { static int __init init_cgroup_cls(void) { - return register_tcf_proto_ops(&cls_cgroup_ops); + int ret = register_tcf_proto_ops(&cls_cgroup_ops); + if (ret) + return ret; + ret = cgroup_load_subsys(&net_cls_subsys); + if (ret) + unregister_tcf_proto_ops(&cls_cgroup_ops); + return ret; } static void __exit exit_cgroup_cls(void) { unregister_tcf_proto_ops(&cls_cgroup_ops); + cgroup_unload_subsys(&net_cls_subsys); } module_init(init_cgroup_cls); From 4881a4f89a95cc5fef6d32953954bcc3443eefd5 Mon Sep 17 00:00:00 2001 From: Jens Rottmann Date: Tue, 23 Mar 2010 04:23:50 +0000 Subject: [PATCH 223/478] ksz884x: fix return value of netdev_set_eeprom ksz884x: fix return value of netdev_set_eeprom netdev_set_eeprom() confused ethtool by just returning 1 on error instead of a proper -EINVAL. Signed-off-by: Jens Rottmann Signed-off-by: David S. Miller --- drivers/net/ksz884x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 0f59099ee72..6c5327af1bf 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -6322,7 +6322,7 @@ static int netdev_set_eeprom(struct net_device *dev, int len; if (eeprom->magic != EEPROM_MAGIC) - return 1; + return -EINVAL; len = (eeprom->offset + eeprom->len + 1) / 2; for (i = eeprom->offset / 2; i < len; i++) From 66f1207bce10fd80ee8ce99b67d617644612f05e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 11 Mar 2010 17:01:09 -0700 Subject: [PATCH 224/478] resources: add interfaces that return conflict information request_resource() and insert_resource() only return success or failure, which no information about what existing resource conflicted with the proposed new reservation. This patch adds request_resource_conflict() and insert_resource_conflict(), which return the conflicting resource. Callers may use this for better error messages or to adjust the new resource and retry the request. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- include/linux/ioport.h | 2 ++ kernel/resource.c | 44 +++++++++++++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 71ab79da7e7..26fad187d66 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -112,12 +112,14 @@ struct resource_list { extern struct resource ioport_resource; extern struct resource iomem_resource; +extern struct resource *request_resource_conflict(struct resource *root, struct resource *new); extern int request_resource(struct resource *root, struct resource *new); extern int release_resource(struct resource *new); void release_child_resources(struct resource *new); extern void reserve_region_with_split(struct resource *root, resource_size_t start, resource_size_t end, const char *name); +extern struct resource *insert_resource_conflict(struct resource *parent, struct resource *new); extern int insert_resource(struct resource *parent, struct resource *new); extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new); extern int allocate_resource(struct resource *root, struct resource *new, diff --git a/kernel/resource.c b/kernel/resource.c index 2d5be5d9bf5..9c358e26353 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -218,6 +218,23 @@ void release_child_resources(struct resource *r) write_unlock(&resource_lock); } +/** + * request_resource_conflict - request and reserve an I/O or memory resource + * @root: root resource descriptor + * @new: resource descriptor desired by caller + * + * Returns 0 for success, conflict resource on error. + */ +struct resource *request_resource_conflict(struct resource *root, struct resource *new) +{ + struct resource *conflict; + + write_lock(&resource_lock); + conflict = __request_resource(root, new); + write_unlock(&resource_lock); + return conflict; +} + /** * request_resource - request and reserve an I/O or memory resource * @root: root resource descriptor @@ -229,9 +246,7 @@ int request_resource(struct resource *root, struct resource *new) { struct resource *conflict; - write_lock(&resource_lock); - conflict = __request_resource(root, new); - write_unlock(&resource_lock); + conflict = request_resource_conflict(root, new); return conflict ? -EBUSY : 0; } @@ -474,25 +489,40 @@ static struct resource * __insert_resource(struct resource *parent, struct resou } /** - * insert_resource - Inserts a resource in the resource tree + * insert_resource_conflict - Inserts resource in the resource tree * @parent: parent of the new resource * @new: new resource to insert * - * Returns 0 on success, -EBUSY if the resource can't be inserted. + * Returns 0 on success, conflict resource if the resource can't be inserted. * - * This function is equivalent to request_resource when no conflict + * This function is equivalent to request_resource_conflict when no conflict * happens. If a conflict happens, and the conflicting resources * entirely fit within the range of the new resource, then the new * resource is inserted and the conflicting resources become children of * the new resource. */ -int insert_resource(struct resource *parent, struct resource *new) +struct resource *insert_resource_conflict(struct resource *parent, struct resource *new) { struct resource *conflict; write_lock(&resource_lock); conflict = __insert_resource(parent, new); write_unlock(&resource_lock); + return conflict; +} + +/** + * insert_resource - Inserts a resource in the resource tree + * @parent: parent of the new resource + * @new: new resource to insert + * + * Returns 0 on success, -EBUSY if the resource can't be inserted. + */ +int insert_resource(struct resource *parent, struct resource *new) +{ + struct resource *conflict; + + conflict = insert_resource_conflict(parent, new); return conflict ? -EBUSY : 0; } From b4414eea0e7b9c134262c801a87e338bf675962c Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Thu, 11 Mar 2010 18:31:09 -0800 Subject: [PATCH 225/478] ocfs2: Clear undo bits when local alloc is freed When the local alloc file changes windows, unused bits are freed back to the global bitmap. By defnition, those bits can not be in use by any file. Also, the local alloc will never have been able to allocate those bits if they were part of a previous truncate. Therefore it makes sense that we should clear unused local alloc bits in the undo buffer so that they can be used immediatly. [ Modified to call it ocfs2_release_clusters() -- Joel ] Signed-off-by: Mark Fasheh Signed-off-by: Joel Becker --- fs/ocfs2/localalloc.c | 6 ++- fs/ocfs2/ocfs2.h | 14 ++++- fs/ocfs2/suballoc.c | 116 +++++++++++++++++++++++++++--------------- fs/ocfs2/suballoc.h | 5 ++ 4 files changed, 95 insertions(+), 46 deletions(-) diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index 171c691b42a..c983715d8d8 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -872,8 +872,10 @@ static int ocfs2_sync_local_to_main(struct ocfs2_super *osb, (unsigned long long)la_start_blk, (unsigned long long)blkno); - status = ocfs2_free_clusters(handle, main_bm_inode, - main_bm_bh, blkno, count); + status = ocfs2_release_clusters(handle, + main_bm_inode, + main_bm_bh, blkno, + count); if (status < 0) { mlog_errno(status); goto bail; diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 1238b491db9..adf5e2ebc2c 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -763,8 +763,18 @@ static inline unsigned int ocfs2_megabytes_to_clusters(struct super_block *sb, return megs << (20 - OCFS2_SB(sb)->s_clustersize_bits); } -#define ocfs2_set_bit ext2_set_bit -#define ocfs2_clear_bit ext2_clear_bit +static inline void _ocfs2_set_bit(unsigned int bit, unsigned long *bitmap) +{ + ext2_set_bit(bit, bitmap); +} +#define ocfs2_set_bit(bit, addr) _ocfs2_set_bit((bit), (unsigned long *)(addr)) + +static inline void _ocfs2_clear_bit(unsigned int bit, unsigned long *bitmap) +{ + ext2_clear_bit(bit, bitmap); +} +#define ocfs2_clear_bit(bit, addr) _ocfs2_clear_bit((bit), (unsigned long *)(addr)) + #define ocfs2_test_bit ext2_test_bit #define ocfs2_find_next_zero_bit ext2_find_next_zero_bit #define ocfs2_find_next_bit ext2_find_next_bit diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 0016503d83e..19ba00f2854 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -95,13 +95,6 @@ static inline int ocfs2_block_group_set_bits(handle_t *handle, struct buffer_head *group_bh, unsigned int bit_off, unsigned int num_bits); -static inline int ocfs2_block_group_clear_bits(handle_t *handle, - struct inode *alloc_inode, - struct ocfs2_group_desc *bg, - struct buffer_head *group_bh, - unsigned int bit_off, - unsigned int num_bits); - static int ocfs2_relink_block_group(handle_t *handle, struct inode *alloc_inode, struct buffer_head *fe_bh, @@ -1978,18 +1971,18 @@ int ocfs2_claim_clusters(struct ocfs2_super *osb, bits_wanted, cluster_start, num_clusters); } -static inline int ocfs2_block_group_clear_bits(handle_t *handle, - struct inode *alloc_inode, - struct ocfs2_group_desc *bg, - struct buffer_head *group_bh, - unsigned int bit_off, - unsigned int num_bits) +static int ocfs2_block_group_clear_bits(handle_t *handle, + struct inode *alloc_inode, + struct ocfs2_group_desc *bg, + struct buffer_head *group_bh, + unsigned int bit_off, + unsigned int num_bits, + void (*undo_fn)(unsigned int bit, + unsigned long *bmap)) { int status; unsigned int tmp; - int journal_type = OCFS2_JOURNAL_ACCESS_WRITE; struct ocfs2_group_desc *undo_bg = NULL; - int cluster_bitmap = 0; mlog_entry_void(); @@ -1999,20 +1992,18 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, mlog(0, "off = %u, num = %u\n", bit_off, num_bits); - if (ocfs2_is_cluster_bitmap(alloc_inode)) - journal_type = OCFS2_JOURNAL_ACCESS_UNDO; - + BUG_ON(undo_fn && !ocfs2_is_cluster_bitmap(alloc_inode)); status = ocfs2_journal_access_gd(handle, INODE_CACHE(alloc_inode), - group_bh, journal_type); + group_bh, + undo_fn ? + OCFS2_JOURNAL_ACCESS_UNDO : + OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } - if (ocfs2_is_cluster_bitmap(alloc_inode)) - cluster_bitmap = 1; - - if (cluster_bitmap) { + if (undo_fn) { jbd_lock_bh_state(group_bh); undo_bg = (struct ocfs2_group_desc *) bh2jh(group_bh)->b_committed_data; @@ -2023,13 +2014,13 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, while(tmp--) { ocfs2_clear_bit((bit_off + tmp), (unsigned long *) bg->bg_bitmap); - if (cluster_bitmap) - ocfs2_set_bit(bit_off + tmp, - (unsigned long *) undo_bg->bg_bitmap); + if (undo_fn) + undo_fn(bit_off + tmp, + (unsigned long *) undo_bg->bg_bitmap); } le16_add_cpu(&bg->bg_free_bits_count, num_bits); - if (cluster_bitmap) + if (undo_fn) jbd_unlock_bh_state(group_bh); status = ocfs2_journal_dirty(handle, group_bh); @@ -2042,12 +2033,14 @@ bail: /* * expects the suballoc inode to already be locked. */ -int ocfs2_free_suballoc_bits(handle_t *handle, - struct inode *alloc_inode, - struct buffer_head *alloc_bh, - unsigned int start_bit, - u64 bg_blkno, - unsigned int count) +static int _ocfs2_free_suballoc_bits(handle_t *handle, + struct inode *alloc_inode, + struct buffer_head *alloc_bh, + unsigned int start_bit, + u64 bg_blkno, + unsigned int count, + void (*undo_fn)(unsigned int bit, + unsigned long *bitmap)) { int status = 0; u32 tmp_used; @@ -2082,7 +2075,7 @@ int ocfs2_free_suballoc_bits(handle_t *handle, status = ocfs2_block_group_clear_bits(handle, alloc_inode, group, group_bh, - start_bit, count); + start_bit, count, undo_fn); if (status < 0) { mlog_errno(status); goto bail; @@ -2113,6 +2106,17 @@ bail: return status; } +int ocfs2_free_suballoc_bits(handle_t *handle, + struct inode *alloc_inode, + struct buffer_head *alloc_bh, + unsigned int start_bit, + u64 bg_blkno, + unsigned int count) +{ + return _ocfs2_free_suballoc_bits(handle, alloc_inode, alloc_bh, + start_bit, bg_blkno, count, NULL); +} + int ocfs2_free_dinode(handle_t *handle, struct inode *inode_alloc_inode, struct buffer_head *inode_alloc_bh, @@ -2126,11 +2130,13 @@ int ocfs2_free_dinode(handle_t *handle, inode_alloc_bh, bit, bg_blkno, 1); } -int ocfs2_free_clusters(handle_t *handle, - struct inode *bitmap_inode, - struct buffer_head *bitmap_bh, - u64 start_blk, - unsigned int num_clusters) +static int _ocfs2_free_clusters(handle_t *handle, + struct inode *bitmap_inode, + struct buffer_head *bitmap_bh, + u64 start_blk, + unsigned int num_clusters, + void (*undo_fn)(unsigned int bit, + unsigned long *bitmap)) { int status; u16 bg_start_bit; @@ -2157,9 +2163,9 @@ int ocfs2_free_clusters(handle_t *handle, mlog(0, "bg_blkno = %llu, bg_start_bit = %u\n", (unsigned long long)bg_blkno, bg_start_bit); - status = ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh, - bg_start_bit, bg_blkno, - num_clusters); + status = _ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh, + bg_start_bit, bg_blkno, + num_clusters, undo_fn); if (status < 0) { mlog_errno(status); goto out; @@ -2173,6 +2179,32 @@ out: return status; } +int ocfs2_free_clusters(handle_t *handle, + struct inode *bitmap_inode, + struct buffer_head *bitmap_bh, + u64 start_blk, + unsigned int num_clusters) +{ + return _ocfs2_free_clusters(handle, bitmap_inode, bitmap_bh, + start_blk, num_clusters, + _ocfs2_set_bit); +} + +/* + * Give never-used clusters back to the global bitmap. We don't need + * to protect these bits in the undo buffer. + */ +int ocfs2_release_clusters(handle_t *handle, + struct inode *bitmap_inode, + struct buffer_head *bitmap_bh, + u64 start_blk, + unsigned int num_clusters) +{ + return _ocfs2_free_clusters(handle, bitmap_inode, bitmap_bh, + start_blk, num_clusters, + _ocfs2_clear_bit); +} + static inline void ocfs2_debug_bg(struct ocfs2_group_desc *bg) { printk("Block Group:\n"); diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index fa60723c43e..e0f46df357e 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h @@ -127,6 +127,11 @@ int ocfs2_free_clusters(handle_t *handle, struct buffer_head *bitmap_bh, u64 start_blk, unsigned int num_clusters); +int ocfs2_release_clusters(handle_t *handle, + struct inode *bitmap_inode, + struct buffer_head *bitmap_bh, + u64 start_blk, + unsigned int num_clusters); static inline u64 ocfs2_which_suballoc_group(u64 block, unsigned int bit) { From 3939fda4b389993caf8741df5739b3e49f33a263 Mon Sep 17 00:00:00 2001 From: Tristan Ye Date: Fri, 19 Mar 2010 09:21:09 +0800 Subject: [PATCH 226/478] Ocfs2: Journaling i_flags and i_orphaned_slot when adding inode to orphan dir. Currently, some callers were missing to journal the dirty inode after adding it to orphan dir. Now we're going to journal such modifications within the ocfs2_orphan_add() itself, It's safe to do so, though some existing caller may duplicate this, and it makes the logic look more straightforward anyway. Signed-off-by: Tristan Ye Signed-off-by: Joel Becker --- fs/ocfs2/namei.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index d9cd4e373a5..b1eb50ae409 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -84,7 +84,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, static int ocfs2_orphan_add(struct ocfs2_super *osb, handle_t *handle, struct inode *inode, - struct ocfs2_dinode *fe, + struct buffer_head *fe_bh, char *name, struct ocfs2_dir_lookup_result *lookup, struct inode *orphan_dir_inode); @@ -879,7 +879,7 @@ static int ocfs2_unlink(struct inode *dir, fe = (struct ocfs2_dinode *) fe_bh->b_data; if (inode_is_unlinkable(inode)) { - status = ocfs2_orphan_add(osb, handle, inode, fe, orphan_name, + status = ocfs2_orphan_add(osb, handle, inode, fe_bh, orphan_name, &orphan_insert, orphan_dir); if (status < 0) { mlog_errno(status); @@ -1300,7 +1300,7 @@ static int ocfs2_rename(struct inode *old_dir, if (S_ISDIR(new_inode->i_mode) || (ocfs2_read_links_count(newfe) == 1)) { status = ocfs2_orphan_add(osb, handle, new_inode, - newfe, orphan_name, + newfe_bh, orphan_name, &orphan_insert, orphan_dir); if (status < 0) { mlog_errno(status); @@ -1911,7 +1911,7 @@ leave: static int ocfs2_orphan_add(struct ocfs2_super *osb, handle_t *handle, struct inode *inode, - struct ocfs2_dinode *fe, + struct buffer_head *fe_bh, char *name, struct ocfs2_dir_lookup_result *lookup, struct inode *orphan_dir_inode) @@ -1919,6 +1919,7 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb, struct buffer_head *orphan_dir_bh = NULL; int status = 0; struct ocfs2_dinode *orphan_fe; + struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data; mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino); @@ -1959,6 +1960,21 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb, goto leave; } + /* + * We're going to journal the change of i_flags and i_orphaned_slot. + * It's safe anyway, though some callers may duplicate the journaling. + * Journaling within the func just make the logic look more + * straightforward. + */ + status = ocfs2_journal_access_di(handle, + INODE_CACHE(inode), + fe_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { + mlog_errno(status); + goto leave; + } + le32_add_cpu(&fe->i_flags, OCFS2_ORPHANED_FL); /* Record which orphan dir our inode now resides @@ -1966,6 +1982,8 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb, * dir to lock. */ fe->i_orphaned_slot = cpu_to_le16(osb->slot_num); + ocfs2_journal_dirty(handle, fe_bh); + mlog(0, "Inode %llu orphaned in slot %d\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num); @@ -2123,7 +2141,7 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, } di = (struct ocfs2_dinode *)new_di_bh->b_data; - status = ocfs2_orphan_add(osb, handle, inode, di, orphan_name, + status = ocfs2_orphan_add(osb, handle, inode, new_di_bh, orphan_name, &orphan_insert, orphan_dir); if (status < 0) { mlog_errno(status); From b54c2ca475fa7d7450a45b6d778dae9dbe0bcbfe Mon Sep 17 00:00:00 2001 From: Tristan Ye Date: Fri, 19 Mar 2010 09:21:10 +0800 Subject: [PATCH 227/478] Ocfs2: Handle deletion of reflinked oprhan inodes correctly. The rule is that all inodes in the orphan dir have ORPHANED_FL, otherwise we treated it as an ERROR. This rule works well except for some rare cases of reflink operation: http://oss.oracle.com/bugzilla/show_bug.cgi?id=1215 The problem is caused by how reflink and our orphan_scan thread interact. * The orphan scan pulls the orphans into a queue first, then runs the queue at a later time. We only hold the orphan_dir's lock during scanning. * Reflink create a oprhaned target in orphan_dir as its first step. It removes the target and clears the flag as the final step. These two steps take the orphan_dir's lock, but it is not held for the duration. Based on the above semantics, a reflink inode can be moved out of the orphan dir and have its ORPHANED_FL cleared before the queue of orphans is run. This leads to a ERROR in ocfs2_query_wipde_inode(). This patch teaches ocfs2_query_wipe_inode() to detect previously orphaned reflink targets. If a reflink fails or a crash occurs during the relfink operation, the inode will retain ORPHANED_FL and will be properly wiped. Signed-off-by: Tristan Ye Signed-off-by: Joel Becker --- fs/ocfs2/inode.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 278a223aae1..ab207901d32 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -891,6 +891,21 @@ static int ocfs2_query_inode_wipe(struct inode *inode, /* Do some basic inode verification... */ di = (struct ocfs2_dinode *) di_bh->b_data; if (!(di->i_flags & cpu_to_le32(OCFS2_ORPHANED_FL))) { + /* + * Inodes in the orphan dir must have ORPHANED_FL. The only + * inodes that come back out of the orphan dir are reflink + * targets. A reflink target may be moved out of the orphan + * dir between the time we scan the directory and the time we + * process it. This would lead to HAS_REFCOUNT_FL being set but + * ORPHANED_FL not. + */ + if (di->i_dyn_features & cpu_to_le16(OCFS2_HAS_REFCOUNT_FL)) { + mlog(0, "Reflinked inode %llu is no longer orphaned. " + "it shouldn't be deleted\n", + (unsigned long long)oi->ip_blkno); + goto bail; + } + /* for lack of a better error? */ status = -EEXIST; mlog(ML_ERROR, From 14741472a05245ed5778aa0aec055e1f920b6ef8 Mon Sep 17 00:00:00 2001 From: Srinivas Eeda Date: Mon, 22 Mar 2010 16:50:47 -0700 Subject: [PATCH 228/478] ocfs2: Fix a race in o2dlm lockres mastery In o2dlm, the master of a lock resource keeps a map of all interested nodes. This prevents the master from purging the resource before an interested node can create a lock. A race between the mastery thread and the mastery handler allowed an interested node to discover who the master is without informing the master directly. This is easily fixed by holding the dlm spinlock a little longer in the mastery handler. Signed-off-by: Srinivas Eeda Signed-off-by: Joel Becker --- fs/ocfs2/dlm/dlmmaster.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index a659606dcb9..9289b4357d2 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -1875,7 +1875,6 @@ int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data, ok: spin_unlock(&res->spinlock); } - spin_unlock(&dlm->spinlock); // mlog(0, "woo! got an assert_master from node %u!\n", // assert->node_idx); @@ -1926,7 +1925,6 @@ ok: /* master is known, detach if not already detached. * ensures that only one assert_master call will happen * on this mle. */ - spin_lock(&dlm->spinlock); spin_lock(&dlm->master_lock); rr = atomic_read(&mle->mle_refs.refcount); @@ -1959,7 +1957,6 @@ ok: __dlm_put_mle(mle); } spin_unlock(&dlm->master_lock); - spin_unlock(&dlm->spinlock); } else if (res) { if (res->owner != assert->node_idx) { mlog(0, "assert_master from %u, but current " @@ -1967,6 +1964,7 @@ ok: res->owner, namelen, name); } } + spin_unlock(&dlm->spinlock); done: ret = 0; From 37f328eb60a94779dd020084209fc4db2d6444a0 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 24 Mar 2010 20:06:41 -0400 Subject: [PATCH 229/478] ext4: Fix spelling of CONTIG_FS_EXT3 to CONFIG_FS_EXT3 Oops. (Blush.) Thanks to Sedat Dilek for pointing this out. Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index ce84a6ed4a4..f4b038f51f3 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4068,7 +4068,7 @@ static int ext4_get_sb(struct file_system_type *fs_type, int flags, return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super,mnt); } -#if !defined(CONTIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) +#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) static struct file_system_type ext2_fs_type = { .owner = THIS_MODULE, .name = "ext2", @@ -4095,7 +4095,7 @@ static inline void register_as_ext2(void) { } static inline void unregister_as_ext2(void) { } #endif -#if !defined(CONTIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) +#if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) static struct file_system_type ext3_fs_type = { .owner = THIS_MODULE, .name = "ext3", From ba69f9ab7df844125898104e854e063b47c26637 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 24 Mar 2010 20:18:37 -0400 Subject: [PATCH 230/478] ext4: Don't use delayed allocation by default when used instead of ext3 When ext4 driver is used to mount a filesystem instead of the ext3 file system driver (through CONFIG_EXT4_USE_FOR_EXT23), do not enable delayed allocation by default since some ext3 users and application writers have developed unfortunate expectations about the safety of writing files on systems subject to sudden and violent death without using fsync(). Signed-off-by: Jan Kara Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index f4b038f51f3..29c6875d9b4 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -68,7 +68,21 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); static int ext4_unfreeze(struct super_block *sb); static void ext4_write_super(struct super_block *sb); static int ext4_freeze(struct super_block *sb); +static int ext4_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct vfsmount *mnt); +#if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) +static struct file_system_type ext3_fs_type = { + .owner = THIS_MODULE, + .name = "ext3", + .get_sb = ext4_get_sb, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, +}; +#define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type) +#else +#define IS_EXT3_SB(sb) (0) +#endif ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, struct ext4_group_desc *bg) @@ -2539,7 +2553,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) * enable delayed allocation by default * Use -o nodelalloc to turn it off */ - set_opt(sbi->s_mount_opt, DELALLOC); + if (!IS_EXT3_SB(sb)) + set_opt(sbi->s_mount_opt, DELALLOC); if (!parse_options((char *) data, sb, &journal_devnum, &journal_ioprio, NULL, 0)) @@ -4096,14 +4111,6 @@ static inline void unregister_as_ext2(void) { } #endif #if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) -static struct file_system_type ext3_fs_type = { - .owner = THIS_MODULE, - .name = "ext3", - .get_sb = ext4_get_sb, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; - static inline void register_as_ext3(void) { int err = register_filesystem(&ext3_fs_type); From c4caae25187ff3f5e837c6f04eb1acc2723c72d3 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 23 Mar 2010 21:32:00 -0400 Subject: [PATCH 231/478] ext4: Fixed inode allocator to correctly track a flex_bg's used_dirs When used_dirs was introduced for the flex_groups struct, it looks like the accounting was not put into place properly, in some places manipulating free_inodes rather than used_dirs. Signed-off-by: Eric Sandeen Signed-off-by: "Theodore Ts'o" --- fs/ext4/ialloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 361c0b9962a..57f6eef6ccd 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -263,7 +263,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) ext4_group_t f; f = ext4_flex_group(sbi, block_group); - atomic_dec(&sbi->s_flex_groups[f].free_inodes); + atomic_dec(&sbi->s_flex_groups[f].used_dirs); } } @@ -773,7 +773,7 @@ static int ext4_claim_inode(struct super_block *sb, if (sbi->s_log_groups_per_flex) { ext4_group_t f = ext4_flex_group(sbi, group); - atomic_inc(&sbi->s_flex_groups[f].free_inodes); + atomic_inc(&sbi->s_flex_groups[f].used_dirs); } } gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); From 4327ba435a56ada13eedf3eb332e583c7a0586a9 Mon Sep 17 00:00:00 2001 From: Benjamin Li Date: Tue, 23 Mar 2010 13:13:11 +0000 Subject: [PATCH 232/478] bnx2: Fix netpoll crash. The bnx2 driver calls netif_napi_add() for all the NAPI structs during ->probe() time but not all of them will be used if we're not in MSI-X mode. This creates a problem for netpoll since it will poll all the NAPI structs in the dev_list whether or not they are scheduled, resulting in a crash when we access structure fields not initialized for that vector. We fix it by moving the netif_napi_add() call to ->open() after the number of IRQ vectors has been determined. Signed-off-by: Benjamin Li Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 381887ba677..417de1cb2d4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -246,6 +246,8 @@ static const struct flash_spec flash_5709 = { MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); +static void bnx2_init_napi(struct bnx2 *bp); + static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr) { u32 diff; @@ -6197,6 +6199,7 @@ bnx2_open(struct net_device *dev) bnx2_disable_int(bp); bnx2_setup_int_mode(bp, disable_msi); + bnx2_init_napi(bp); bnx2_napi_enable(bp); rc = bnx2_alloc_mem(bp); if (rc) @@ -8207,7 +8210,7 @@ bnx2_init_napi(struct bnx2 *bp) { int i; - for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { + for (i = 0; i < bp->irq_nvecs; i++) { struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; int (*poll)(struct napi_struct *, int); @@ -8276,7 +8279,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->ethtool_ops = &bnx2_ethtool_ops; bp = netdev_priv(dev); - bnx2_init_napi(bp); pci_set_drvdata(pdev, dev); From 1bf1e347ef254ed8a13e7971a30e1bf3983da3d1 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 23 Mar 2010 13:13:12 +0000 Subject: [PATCH 233/478] bnx2: Use proper handler during netpoll. Netpoll needs to call the proper handler depending on the IRQ mode and the vector. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 417de1cb2d4..a257babd1bb 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -7646,9 +7646,11 @@ poll_bnx2(struct net_device *dev) int i; for (i = 0; i < bp->irq_nvecs; i++) { - disable_irq(bp->irq_tbl[i].vector); - bnx2_interrupt(bp->irq_tbl[i].vector, &bp->bnx2_napi[i]); - enable_irq(bp->irq_tbl[i].vector); + struct bnx2_irq *irq = &bp->irq_tbl[i]; + + disable_irq(irq->vector); + irq->handler(irq->vector, &bp->bnx2_napi[i]); + enable_irq(irq->vector); } } #endif From fa3d9a6d55014b5bce5575aeab1cf711cff748ab Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Tue, 23 Mar 2010 18:34:38 +0000 Subject: [PATCH 234/478] igb: count Rx FIFO errors correctly Don't aggregate rx_no_buffer_count into rx_fifo_errors. RNBC counts packets that get queued temporarily in the adapter's FIFO. These packets are not dropped and are not errors. The correct counter is rx_missed_errors (MPC). Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/igb_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 45a0e4fd587..70dc03bb9cb 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3963,7 +3963,7 @@ void igb_update_stats(struct igb_adapter *adapter) struct net_device_stats *net_stats = igb_get_stats(adapter->netdev); struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; - u32 rnbc, reg; + u32 reg, mpc; u16 phy_tmp; int i; u64 bytes, packets; @@ -4021,7 +4021,9 @@ void igb_update_stats(struct igb_adapter *adapter) adapter->stats.symerrs += rd32(E1000_SYMERRS); adapter->stats.sec += rd32(E1000_SEC); - adapter->stats.mpc += rd32(E1000_MPC); + mpc = rd32(E1000_MPC); + adapter->stats.mpc += mpc; + net_stats->rx_fifo_errors += mpc; adapter->stats.scc += rd32(E1000_SCC); adapter->stats.ecol += rd32(E1000_ECOL); adapter->stats.mcc += rd32(E1000_MCC); @@ -4036,9 +4038,7 @@ void igb_update_stats(struct igb_adapter *adapter) adapter->stats.gptc += rd32(E1000_GPTC); adapter->stats.gotc += rd32(E1000_GOTCL); rd32(E1000_GOTCH); /* clear GOTCL */ - rnbc = rd32(E1000_RNBC); - adapter->stats.rnbc += rnbc; - net_stats->rx_fifo_errors += rnbc; + adapter->stats.rnbc += rd32(E1000_RNBC); adapter->stats.ruc += rd32(E1000_RUC); adapter->stats.rfc += rd32(E1000_RFC); adapter->stats.rjc += rd32(E1000_RJC); From d07f3e375f608e52a1f8958fbde105bb27b7629a Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Tue, 23 Mar 2010 18:34:57 +0000 Subject: [PATCH 235/478] igb: do not modify tx_queue_len on link speed change Previously the driver tweaked txqueuelen to avoid false Tx hang reports seen at half duplex. This had the effect of overriding user set values on link change/reset. Testing shows that adjusting only the timeout factor is sufficient to prevent Tx hang reports at half duplex. Based on e1000e patch by Franco Fichtner Signed-off-by: Emil Tantilov Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/igb.h | 1 - drivers/net/igb/igb_main.c | 10 +--------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index a1775705b24..3b772b822a5 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -267,7 +267,6 @@ struct igb_adapter { /* TX */ struct igb_ring *tx_ring[16]; - unsigned long tx_queue_len; u32 tx_timeout_count; /* RX */ diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 70dc03bb9cb..e72760c2448 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1105,9 +1105,6 @@ static void igb_configure(struct igb_adapter *adapter) struct igb_ring *ring = adapter->rx_ring[i]; igb_alloc_rx_buffers_adv(ring, igb_desc_unused(ring)); } - - - adapter->tx_queue_len = netdev->tx_queue_len; } /** @@ -1213,7 +1210,6 @@ void igb_down(struct igb_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); - netdev->tx_queue_len = adapter->tx_queue_len; netif_carrier_off(netdev); /* record the stats before reset*/ @@ -3106,17 +3102,13 @@ static void igb_watchdog_task(struct work_struct *work) ((ctrl & E1000_CTRL_RFCE) ? "RX" : ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None"))); - /* tweak tx_queue_len according to speed/duplex and - * adjust the timeout factor */ - netdev->tx_queue_len = adapter->tx_queue_len; + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { case SPEED_10: - netdev->tx_queue_len = 10; adapter->tx_timeout_factor = 14; break; case SPEED_100: - netdev->tx_queue_len = 100; /* maybe add some timeout factor ? */ break; } From 31b24b955c3ebbb6f3008a6374e61cf7c05a193c Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 23 Mar 2010 18:35:18 +0000 Subject: [PATCH 236/478] igb: only use vlan_gro_receive if vlans are registered This change makes it so that vlan_gro_receive is only used if vlans have been registered to the adapter structure. Previously we were just sending all vlan tagged frames in via this function but this results in a null pointer dereference when vlans are not registered. [ This fixes bugzilla entry 15582 -Eric Dumazet] Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/igb/igb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index e72760c2448..01c65c7447e 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -5102,7 +5102,7 @@ static void igb_receive_skb(struct igb_q_vector *q_vector, { struct igb_adapter *adapter = q_vector->adapter; - if (vlan_tag) + if (vlan_tag && adapter->vlgrp) vlan_gro_receive(&q_vector->napi, adapter->vlgrp, vlan_tag, skb); else From 1c583063a5c769fe2ec604752e383972c69e6d9b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 24 Mar 2010 07:10:54 +0100 Subject: [PATCH 237/478] ALSA: cmipci: work around invalid PCM pointer When the CMI8738 FRAME2 register is read, the chip sometimes (probably when wrapping around) returns an invalid value that would be outside the programmed DMA buffer. This leads to an inconsistent PCM pointer that is likely to result in an underrun. To work around this, read the register multiple times until we get a valid value; the error state seems to be very short-lived. Signed-off-by: Clemens Ladisch Reported-and-tested-by: Matija Nalis Cc: Signed-off-by: Takashi Iwai --- sound/pci/cmipci.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 1ded64e0564..329968edca9 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -941,13 +941,21 @@ static snd_pcm_uframes_t snd_cmipci_pcm_pointer(struct cmipci *cm, struct cmipci struct snd_pcm_substream *substream) { size_t ptr; - unsigned int reg; + unsigned int reg, rem, tries; + if (!rec->running) return 0; #if 1 // this seems better.. reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2; - ptr = rec->dma_size - (snd_cmipci_read_w(cm, reg) + 1); - ptr >>= rec->shift; + for (tries = 0; tries < 3; tries++) { + rem = snd_cmipci_read_w(cm, reg); + if (rem < rec->dma_size) + goto ok; + } + printk(KERN_ERR "cmipci: invalid PCM pointer: %#x\n", rem); + return SNDRV_PCM_POS_XRUN; +ok: + ptr = (rec->dma_size - (rem + 1)) >> rec->shift; #else reg = rec->ch ? CM_REG_CH1_FRAME1 : CM_REG_CH0_FRAME1; ptr = snd_cmipci_read(cm, reg) - rec->offset; From 7d7ba8d31eb293016bc91a5c8fc36b21fd917265 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Wed, 24 Mar 2010 10:49:14 +0100 Subject: [PATCH 238/478] pcmcia: allow for four multifunction subdevices (again) Commit aa584ca4 broke what 6cf5be51 had already fixed: there may be four multifunction devices, but just two pseudo-multifunction devices per PCMCIA card. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ds.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index ad93ebd7b2a..52d33b2a5bc 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -509,8 +509,12 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu p_dev->device_no = (s->device_count++); mutex_unlock(&s->ops_mutex); - /* max of 2 devices per card */ - if (p_dev->device_no >= 2) + /* max of 2 PFC devices */ + if ((p_dev->device_no >= 2) && (function == 0)) + goto err_free; + + /* max of 4 devices overall */ + if (p_dev->device_no >= 4) goto err_free; p_dev->socket = s; From e7176a37d436a214f6a7727ea7986c654cbee8f0 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Mon, 15 Mar 2010 21:43:11 +0100 Subject: [PATCH 239/478] power: support _noirq actions on device types and classes The new-style dev_pm_ops provide callbacks for both IRQs enabled and disabled. However, the _noirq variants were only called for buses registered with a device, not for classes and types. In order to properly use dev_pm_ops in class pcmcia_socket_class, support _noirq actions also on classes and types. Signed-off-by: Dominik Brodowski Acked-by: Rafael J. Wysocki --- drivers/base/power/main.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index d477f4dc5e5..941fcb87e52 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -439,8 +439,23 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->bus && dev->bus->pm) { pm_dev_dbg(dev, state, "EARLY "); error = pm_noirq_op(dev, dev->bus->pm, state); + if (error) + goto End; } + if (dev->type && dev->type->pm) { + pm_dev_dbg(dev, state, "EARLY type "); + error = pm_noirq_op(dev, dev->type->pm, state); + if (error) + goto End; + } + + if (dev->class && dev->class->pm) { + pm_dev_dbg(dev, state, "EARLY class "); + error = pm_noirq_op(dev, dev->class->pm, state); + } + +End: TRACE_RESUME(error); return error; } @@ -735,10 +750,26 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) { int error = 0; + if (dev->class && dev->class->pm) { + pm_dev_dbg(dev, state, "LATE class "); + error = pm_noirq_op(dev, dev->class->pm, state); + if (error) + goto End; + } + + if (dev->type && dev->type->pm) { + pm_dev_dbg(dev, state, "LATE type "); + error = pm_noirq_op(dev, dev->type->pm, state); + if (error) + goto End; + } + if (dev->bus && dev->bus->pm) { pm_dev_dbg(dev, state, "LATE "); error = pm_noirq_op(dev, dev->bus->pm, state); } + +End: return error; } From d7646f7632549124fe70fec8af834c7c1246f365 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Mon, 15 Mar 2010 21:46:34 +0100 Subject: [PATCH 240/478] pcmcia: use dev_pm_ops for class pcmcia_socket_class Instead of requiring PCMCIA socket drivers to call various functions during their (bus) resume and suspend functions, register an own dev_pm_ops for this class. This fixes several suspend/resume bugs seen on db1xxx-ss, and probably on some other socket drivers, too. With regard to the asymmetry with only _noirq suspend, but split up resume, please see bug 14334 and commit 9905d1b411946fb3 . Signed-off-by: Dominik Brodowski --- drivers/pcmcia/at91_cf.c | 2 - drivers/pcmcia/au1000_generic.c | 13 ---- drivers/pcmcia/bfin_cf_pcmcia.c | 12 ---- drivers/pcmcia/cs.c | 124 ++++++++++++++++---------------- drivers/pcmcia/db1xxx_ss.c | 27 ------- drivers/pcmcia/i82092.c | 16 ----- drivers/pcmcia/i82365.c | 11 --- drivers/pcmcia/m32r_cfc.c | 11 --- drivers/pcmcia/m32r_pcc.c | 12 ---- drivers/pcmcia/m8xx_pcmcia.c | 17 ----- drivers/pcmcia/omap_cf.c | 12 ---- drivers/pcmcia/pd6729.c | 16 ----- drivers/pcmcia/pxa2xx_base.c | 8 +-- drivers/pcmcia/sa1100_generic.c | 13 ---- drivers/pcmcia/sa1111_generic.c | 12 ---- drivers/pcmcia/tcic.c | 12 ---- drivers/pcmcia/vrc4171_card.c | 13 ---- drivers/pcmcia/yenta_socket.c | 17 +---- include/pcmcia/ss.h | 6 -- 19 files changed, 66 insertions(+), 288 deletions(-) diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index 5d228071ec6..fb904f444d9 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -361,7 +361,6 @@ static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg) struct at91_cf_socket *cf = platform_get_drvdata(pdev); struct at91_cf_data *board = cf->board; - pcmcia_socket_dev_suspend(&pdev->dev); if (device_may_wakeup(&pdev->dev)) { enable_irq_wake(board->det_pin); if (board->irq_pin) @@ -381,7 +380,6 @@ static int at91_cf_resume(struct platform_device *pdev) disable_irq_wake(board->irq_pin); } - pcmcia_socket_dev_resume(&pdev->dev); return 0; } diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index 171c8a65488..ac4d089430f 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c @@ -510,17 +510,6 @@ static int au1x00_drv_pcmcia_probe(struct platform_device *dev) return ret; } -static int au1x00_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int au1x00_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} - static struct platform_driver au1x00_pcmcia_driver = { .driver = { .name = "au1x00-pcmcia", @@ -528,8 +517,6 @@ static struct platform_driver au1x00_pcmcia_driver = { }, .probe = au1x00_drv_pcmcia_probe, .remove = au1x00_drv_pcmcia_remove, - .suspend = au1x00_drv_pcmcia_suspend, - .resume = au1x00_drv_pcmcia_resume, }; diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c index 2482ce7ac6d..93f9ddeb0c3 100644 --- a/drivers/pcmcia/bfin_cf_pcmcia.c +++ b/drivers/pcmcia/bfin_cf_pcmcia.c @@ -300,16 +300,6 @@ static int __devexit bfin_cf_remove(struct platform_device *pdev) return 0; } -static int bfin_cf_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - return pcmcia_socket_dev_suspend(&pdev->dev); -} - -static int bfin_cf_resume(struct platform_device *pdev) -{ - return pcmcia_socket_dev_resume(&pdev->dev); -} - static struct platform_driver bfin_cf_driver = { .driver = { .name = (char *)driver_name, @@ -317,8 +307,6 @@ static struct platform_driver bfin_cf_driver = { }, .probe = bfin_cf_probe, .remove = __devexit_p(bfin_cf_remove), - .suspend = bfin_cf_suspend, - .resume = bfin_cf_resume, }; static int __init bfin_cf_init(void) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index e679e708db6..75ed866e695 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -76,65 +76,6 @@ DECLARE_RWSEM(pcmcia_socket_list_rwsem); EXPORT_SYMBOL(pcmcia_socket_list_rwsem); -/* - * Low-level PCMCIA socket drivers need to register with the PCCard - * core using pcmcia_register_socket. - * - * socket drivers are expected to use the following callbacks in their - * .drv struct: - * - pcmcia_socket_dev_suspend - * - pcmcia_socket_dev_resume - * These functions check for the appropriate struct pcmcia_soket arrays, - * and pass them to the low-level functions pcmcia_{suspend,resume}_socket - */ -static int socket_early_resume(struct pcmcia_socket *skt); -static int socket_late_resume(struct pcmcia_socket *skt); -static int socket_resume(struct pcmcia_socket *skt); -static int socket_suspend(struct pcmcia_socket *skt); - -static void pcmcia_socket_dev_run(struct device *dev, - int (*cb)(struct pcmcia_socket *)) -{ - struct pcmcia_socket *socket; - - down_read(&pcmcia_socket_list_rwsem); - list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { - if (socket->dev.parent != dev) - continue; - mutex_lock(&socket->skt_mutex); - cb(socket); - mutex_unlock(&socket->skt_mutex); - } - up_read(&pcmcia_socket_list_rwsem); -} - -int pcmcia_socket_dev_suspend(struct device *dev) -{ - pcmcia_socket_dev_run(dev, socket_suspend); - return 0; -} -EXPORT_SYMBOL(pcmcia_socket_dev_suspend); - -void pcmcia_socket_dev_early_resume(struct device *dev) -{ - pcmcia_socket_dev_run(dev, socket_early_resume); -} -EXPORT_SYMBOL(pcmcia_socket_dev_early_resume); - -void pcmcia_socket_dev_late_resume(struct device *dev) -{ - pcmcia_socket_dev_run(dev, socket_late_resume); -} -EXPORT_SYMBOL(pcmcia_socket_dev_late_resume); - -int pcmcia_socket_dev_resume(struct device *dev) -{ - pcmcia_socket_dev_run(dev, socket_resume); - return 0; -} -EXPORT_SYMBOL(pcmcia_socket_dev_resume); - - struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt) { struct device *dev = get_device(&skt->dev); @@ -578,12 +519,18 @@ static int socket_early_resume(struct pcmcia_socket *skt) static int socket_late_resume(struct pcmcia_socket *skt) { + int ret; + mutex_lock(&skt->ops_mutex); skt->state &= ~SOCKET_SUSPEND; mutex_unlock(&skt->ops_mutex); - if (!(skt->state & SOCKET_PRESENT)) - return socket_insert(skt); + if (!(skt->state & SOCKET_PRESENT)) { + ret = socket_insert(skt); + if (ret == -ENODEV) + ret = 0; + return ret; + } if (skt->resume_status) { socket_shutdown(skt); @@ -919,11 +866,66 @@ static void pcmcia_release_socket_class(struct class *data) } +#ifdef CONFIG_PM + +static int __pcmcia_pm_op(struct device *dev, + int (*callback) (struct pcmcia_socket *skt)) +{ + struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); + int ret; + + mutex_lock(&s->skt_mutex); + ret = callback(s); + mutex_unlock(&s->skt_mutex); + + return ret; +} + +static int pcmcia_socket_dev_suspend_noirq(struct device *dev) +{ + return __pcmcia_pm_op(dev, socket_suspend); +} + +static int pcmcia_socket_dev_resume_noirq(struct device *dev) +{ + return __pcmcia_pm_op(dev, socket_early_resume); +} + +static int pcmcia_socket_dev_resume(struct device *dev) +{ + return __pcmcia_pm_op(dev, socket_late_resume); +} + +static const struct dev_pm_ops pcmcia_socket_pm_ops = { + /* dev_resume may be called with IRQs enabled */ + SET_SYSTEM_SLEEP_PM_OPS(NULL, + pcmcia_socket_dev_resume) + + /* late suspend must be called with IRQs disabled */ + .suspend_noirq = pcmcia_socket_dev_suspend_noirq, + .freeze_noirq = pcmcia_socket_dev_suspend_noirq, + .poweroff_noirq = pcmcia_socket_dev_suspend_noirq, + + /* early resume must be called with IRQs disabled */ + .resume_noirq = pcmcia_socket_dev_resume_noirq, + .thaw_noirq = pcmcia_socket_dev_resume_noirq, + .restore_noirq = pcmcia_socket_dev_resume_noirq, +}; + +#define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops) + +#else /* CONFIG_PM */ + +#define PCMCIA_SOCKET_CLASS_PM_OPS NULL + +#endif /* CONFIG_PM */ + struct class pcmcia_socket_class = { .name = "pcmcia_socket", .dev_uevent = pcmcia_socket_uevent, .dev_release = pcmcia_release_socket, .class_release = pcmcia_release_socket_class, + .pm = PCMCIA_SOCKET_CLASS_PM_OPS, }; EXPORT_SYMBOL(pcmcia_socket_class); diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c index 9254ab0b29b..a520193b645 100644 --- a/drivers/pcmcia/db1xxx_ss.c +++ b/drivers/pcmcia/db1xxx_ss.c @@ -558,37 +558,10 @@ static int __devexit db1x_pcmcia_socket_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int db1x_pcmcia_suspend(struct device *dev) -{ - return pcmcia_socket_dev_suspend(dev); -} - -static int db1x_pcmcia_resume(struct device *dev) -{ - return pcmcia_socket_dev_resume(dev); -} - -static struct dev_pm_ops db1x_pcmcia_pmops = { - .resume = db1x_pcmcia_resume, - .suspend = db1x_pcmcia_suspend, - .thaw = db1x_pcmcia_resume, - .freeze = db1x_pcmcia_suspend, -}; - -#define DB1XXX_SS_PMOPS &db1x_pcmcia_pmops - -#else - -#define DB1XXX_SS_PMOPS NULL - -#endif - static struct platform_driver db1x_pcmcia_socket_driver = { .driver = { .name = "db1xxx_pcmcia", .owner = THIS_MODULE, - .pm = DB1XXX_SS_PMOPS }, .probe = db1x_pcmcia_socket_probe, .remove = __devexit_p(db1x_pcmcia_socket_remove), diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index f5da6265331..3003bb3dfcc 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -39,27 +39,11 @@ static struct pci_device_id i82092aa_pci_ids[] = { }; MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids); -#ifdef CONFIG_PM -static int i82092aa_socket_suspend (struct pci_dev *dev, pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int i82092aa_socket_resume (struct pci_dev *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} -#endif - static struct pci_driver i82092aa_pci_driver = { .name = "i82092aa", .id_table = i82092aa_pci_ids, .probe = i82092aa_pci_probe, .remove = __devexit_p(i82092aa_pci_remove), -#ifdef CONFIG_PM - .suspend = i82092aa_socket_suspend, - .resume = i82092aa_socket_resume, -#endif }; diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index c13fd936051..d53d9b5659c 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -1223,16 +1223,7 @@ static int pcic_init(struct pcmcia_socket *s) return 0; } -static int i82365_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} -static int i82365_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} static struct pccard_operations pcic_operations = { .init = pcic_init, .get_status = pcic_get_status, @@ -1248,8 +1239,6 @@ static struct platform_driver i82365_driver = { .name = "i82365", .owner = THIS_MODULE, }, - .suspend = i82365_drv_pcmcia_suspend, - .resume = i82365_drv_pcmcia_resume, }; static struct platform_device *i82365_device; diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 0ece2cd4a85..ab21264468d 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -685,16 +685,7 @@ static struct pccard_operations pcc_operations = { .set_mem_map = pcc_set_mem_map, }; -static int cfc_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} -static int cfc_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} /*====================================================================*/ static struct platform_driver pcc_driver = { @@ -702,8 +693,6 @@ static struct platform_driver pcc_driver = { .name = "cfc", .owner = THIS_MODULE, }, - .suspend = cfc_drv_pcmcia_suspend, - .resume = cfc_drv_pcmcia_resume, }; static struct platform_device pcc_device = { diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 72844c5a6d0..0caf3db7c70 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -663,16 +663,6 @@ static struct pccard_operations pcc_operations = { .set_mem_map = pcc_set_mem_map, }; -static int pcc_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int pcc_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} /*====================================================================*/ static struct platform_driver pcc_driver = { @@ -680,8 +670,6 @@ static struct platform_driver pcc_driver = { .name = "pcc", .owner = THIS_MODULE, }, - .suspend = pcc_drv_pcmcia_suspend, - .resume = pcc_drv_pcmcia_resume, }; static struct platform_device pcc_device = { diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 61c21591812..01ef7de1532 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -1288,21 +1288,6 @@ static int m8xx_remove(struct of_device *ofdev) return 0; } -#ifdef CONFIG_PM -static int m8xx_suspend(struct platform_device *pdev, pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&pdev->dev); -} - -static int m8xx_resume(struct platform_device *pdev) -{ - return pcmcia_socket_dev_resume(&pdev->dev); -} -#else -#define m8xx_suspend NULL -#define m8xx_resume NULL -#endif - static const struct of_device_id m8xx_pcmcia_match[] = { { .type = "pcmcia", @@ -1318,8 +1303,6 @@ static struct of_platform_driver m8xx_pcmcia_driver = { .match_table = m8xx_pcmcia_match, .probe = m8xx_probe, .remove = m8xx_remove, - .suspend = m8xx_suspend, - .resume = m8xx_resume, }; static int __init m8xx_init(void) diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 3ef99155239..9edc396577b 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -330,24 +330,12 @@ static int __exit omap_cf_remove(struct platform_device *pdev) return 0; } -static int omap_cf_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - return pcmcia_socket_dev_suspend(&pdev->dev); -} - -static int omap_cf_resume(struct platform_device *pdev) -{ - return pcmcia_socket_dev_resume(&pdev->dev); -} - static struct platform_driver omap_cf_driver = { .driver = { .name = (char *) driver_name, .owner = THIS_MODULE, }, .remove = __exit_p(omap_cf_remove), - .suspend = omap_cf_suspend, - .resume = omap_cf_resume, }; static int __init omap_cf_init(void) diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 47f342f1b0f..4a34268cc51 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -764,18 +764,6 @@ static void __devexit pd6729_pci_remove(struct pci_dev *dev) kfree(socket); } -#ifdef CONFIG_PM -static int pd6729_socket_suspend(struct pci_dev *dev, pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int pd6729_socket_resume(struct pci_dev *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} -#endif - static struct pci_device_id pd6729_pci_ids[] = { { .vendor = PCI_VENDOR_ID_CIRRUS, @@ -792,10 +780,6 @@ static struct pci_driver pd6729_pci_driver = { .id_table = pd6729_pci_ids, .probe = pd6729_pci_probe, .remove = __devexit_p(pd6729_pci_remove), -#ifdef CONFIG_PM - .suspend = pd6729_socket_suspend, - .resume = pd6729_socket_resume, -#endif }; static int pd6729_module_init(void) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 76e640bccde..0a876fabfe4 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -325,19 +325,13 @@ static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev) return 0; } -static int pxa2xx_drv_pcmcia_suspend(struct device *dev) -{ - return pcmcia_socket_dev_suspend(dev); -} - static int pxa2xx_drv_pcmcia_resume(struct device *dev) { pxa2xx_configure_sockets(dev); - return pcmcia_socket_dev_resume(dev); + return 0; } static const struct dev_pm_ops pxa2xx_drv_pcmcia_pm_ops = { - .suspend = pxa2xx_drv_pcmcia_suspend, .resume = pxa2xx_drv_pcmcia_resume, }; diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 8db86b90c20..51889624142 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -95,17 +95,6 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev) return 0; } -static int sa11x0_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int sa11x0_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} - static struct platform_driver sa11x0_pcmcia_driver = { .driver = { .name = "sa11x0-pcmcia", @@ -113,8 +102,6 @@ static struct platform_driver sa11x0_pcmcia_driver = { }, .probe = sa11x0_drv_pcmcia_probe, .remove = sa11x0_drv_pcmcia_remove, - .suspend = sa11x0_drv_pcmcia_suspend, - .resume = sa11x0_drv_pcmcia_resume, }; /* sa11x0_pcmcia_init() diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index db79ca61cf9..799e9793e49 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -213,16 +213,6 @@ static int __devexit pcmcia_remove(struct sa1111_dev *dev) return 0; } -static int pcmcia_suspend(struct sa1111_dev *dev, pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int pcmcia_resume(struct sa1111_dev *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} - static struct sa1111_driver pcmcia_driver = { .drv = { .name = "sa1111-pcmcia", @@ -230,8 +220,6 @@ static struct sa1111_driver pcmcia_driver = { .devid = SA1111_DEVID_PCMCIA, .probe = pcmcia_probe, .remove = __devexit_p(pcmcia_remove), - .suspend = pcmcia_suspend, - .resume = pcmcia_resume, }; static int __init sa1111_drv_pcmcia_init(void) diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index 12c49ee135e..bac85f3236b 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -348,16 +348,6 @@ static int __init get_tcic_id(void) return id; } -static int tcic_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int tcic_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} /*====================================================================*/ static struct platform_driver tcic_driver = { @@ -365,8 +355,6 @@ static struct platform_driver tcic_driver = { .name = "tcic-pcmcia", .owner = THIS_MODULE, }, - .suspend = tcic_drv_pcmcia_suspend, - .resume = tcic_drv_pcmcia_resume, }; static struct platform_device tcic_device = { diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index aaccdb9f4ba..86e4a1a3c64 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -705,24 +705,11 @@ static int __devinit vrc4171_card_setup(char *options) __setup("vrc4171_card=", vrc4171_card_setup); -static int vrc4171_card_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int vrc4171_card_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} - static struct platform_driver vrc4171_card_driver = { .driver = { .name = vrc4171_card_name, .owner = THIS_MODULE, }, - .suspend = vrc4171_card_suspend, - .resume = vrc4171_card_resume, }; static int __devinit vrc4171_card_init(void) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 418988ab6ed..f19ad02374d 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1290,12 +1290,9 @@ static int yenta_dev_suspend_noirq(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct yenta_socket *socket = pci_get_drvdata(pdev); - int ret; - - ret = pcmcia_socket_dev_suspend(dev); if (!socket) - return ret; + return 0; if (socket->type && socket->type->save_state) socket->type->save_state(socket); @@ -1312,7 +1309,7 @@ static int yenta_dev_suspend_noirq(struct device *dev) */ /* pci_set_power_state(dev, 3); */ - return ret; + return 0; } static int yenta_dev_resume_noirq(struct device *dev) @@ -1336,26 +1333,16 @@ static int yenta_dev_resume_noirq(struct device *dev) if (socket->type && socket->type->restore_state) socket->type->restore_state(socket); - pcmcia_socket_dev_early_resume(dev); - return 0; -} - -static int yenta_dev_resume(struct device *dev) -{ - pcmcia_socket_dev_late_resume(dev); return 0; } static const struct dev_pm_ops yenta_pm_ops = { .suspend_noirq = yenta_dev_suspend_noirq, .resume_noirq = yenta_dev_resume_noirq, - .resume = yenta_dev_resume, .freeze_noirq = yenta_dev_suspend_noirq, .thaw_noirq = yenta_dev_resume_noirq, - .thaw = yenta_dev_resume, .poweroff_noirq = yenta_dev_suspend_noirq, .restore_noirq = yenta_dev_resume_noirq, - .restore = yenta_dev_resume, }; #define YENTA_PM_OPS (¥ta_pm_ops) diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 32896a77391..2e488b60bc7 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -277,12 +277,6 @@ extern struct pccard_resource_ops pccard_nonstatic_ops; #endif -/* socket drivers are expected to use these callbacks in their .drv struct */ -extern int pcmcia_socket_dev_suspend(struct device *dev); -extern void pcmcia_socket_dev_early_resume(struct device *dev); -extern void pcmcia_socket_dev_late_resume(struct device *dev); -extern int pcmcia_socket_dev_resume(struct device *dev); - /* socket drivers use this callback in their IRQ handler */ extern void pcmcia_parse_events(struct pcmcia_socket *socket, unsigned int events); From 92fe31329cb3a2b02f1c7616965872d6a34bcf08 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Wed, 24 Mar 2010 11:49:50 +0100 Subject: [PATCH 241/478] [S390] zcore: CPU registers are not saved under LPAR To save the registers for all CPUs a sigp "store status" is done that stores the registers to address absolute zero. To access storage at absolute zero, normally the address of the prefix register of the accessing CPU has to be used. This does not work when large pages are active (currently only under LPAR). In order to fix that problem, instead of memcpy memcpy_real is used, which switches to real mode where prefixing works. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/system.h | 1 + arch/s390/kernel/smp.c | 6 +++--- arch/s390/mm/maccess.c | 26 ++++++++++++++++++++++++++ drivers/s390/char/zcore.c | 31 ++----------------------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 67ee6c3c6bb..12be42baa05 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h @@ -110,6 +110,7 @@ extern void pfault_fini(void); #endif /* CONFIG_PFAULT */ extern void cmma_init(void); +extern int memcpy_real(void *, void *, size_t); #define finish_arch_switch(prev) do { \ set_fs(current->thread.mm_segment); \ diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 29f65bce55e..d7d24fc3d6b 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -292,9 +292,9 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) zfcpdump_save_areas[cpu] = kmalloc(sizeof(struct save_area), GFP_KERNEL); while (raw_sigp(phy_cpu, sigp_stop_and_store_status) == sigp_busy) cpu_relax(); - memcpy(zfcpdump_save_areas[cpu], - (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE, - sizeof(struct save_area)); + memcpy_real(zfcpdump_save_areas[cpu], + (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE, + sizeof(struct save_area)); } struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c index 81756271dc4..a8c2af8c650 100644 --- a/arch/s390/mm/maccess.c +++ b/arch/s390/mm/maccess.c @@ -59,3 +59,29 @@ long probe_kernel_write(void *dst, void *src, size_t size) } return copied < 0 ? -EFAULT : 0; } + +int memcpy_real(void *dest, void *src, size_t count) +{ + register unsigned long _dest asm("2") = (unsigned long) dest; + register unsigned long _len1 asm("3") = (unsigned long) count; + register unsigned long _src asm("4") = (unsigned long) src; + register unsigned long _len2 asm("5") = (unsigned long) count; + unsigned long flags; + int rc = -EFAULT; + + if (!count) + return 0; + flags = __raw_local_irq_stnsm(0xf8UL); + asm volatile ( + "0: mvcle %1,%2,0x0\n" + "1: jo 0b\n" + " lhi %0,0x0\n" + "2:\n" + EX_TABLE(1b,2b) + : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1), + "+d" (_len2), "=m" (*((long *) dest)) + : "m" (*((long *) src)) + : "cc", "memory"); + __raw_local_irq_ssm(flags); + return rc; +} diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 3438658b66b..3166d85914f 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -141,33 +141,6 @@ static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count) return memcpy_hsa(dest, src, count, TO_KERNEL); } -static int memcpy_real(void *dest, unsigned long src, size_t count) -{ - unsigned long flags; - int rc = -EFAULT; - register unsigned long _dest asm("2") = (unsigned long) dest; - register unsigned long _len1 asm("3") = (unsigned long) count; - register unsigned long _src asm("4") = src; - register unsigned long _len2 asm("5") = (unsigned long) count; - - if (count == 0) - return 0; - flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */ - asm volatile ( - "0: mvcle %1,%2,0x0\n" - "1: jo 0b\n" - " lhi %0,0x0\n" - "2:\n" - EX_TABLE(1b,2b) - : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1), - "+d" (_len2), "=m" (*((long*)dest)) - : "m" (*((long*)src)) - : "cc", "memory"); - __raw_local_irq_ssm(flags); - - return rc; -} - static int memcpy_real_user(void __user *dest, unsigned long src, size_t count) { static char buf[4096]; @@ -175,7 +148,7 @@ static int memcpy_real_user(void __user *dest, unsigned long src, size_t count) while (offs < count) { size = min(sizeof(buf), count - offs); - if (memcpy_real(buf, src + offs, size)) + if (memcpy_real(buf, (void *) src + offs, size)) return -EFAULT; if (copy_to_user(dest + offs, buf, size)) return -EFAULT; @@ -663,7 +636,7 @@ static int __init zcore_reipl_init(void) if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE) rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE); else - rc = memcpy_real(ipl_block, ipib_info.ipib, PAGE_SIZE); + rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE); if (rc) { free_page((unsigned long) ipl_block); return rc; From a08786568a7e334d8a07a7bb8f4fafa3f7afb89c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 24 Mar 2010 11:49:51 +0100 Subject: [PATCH 242/478] [S390] smp: fix lowcore allocation The intermediate lowcore for CONFIG_SMP is allocated using a call to __alloc_bootmem() with a goal of 0. That however doesn't guarantee that the allocated piece of memory is below 2GB. Instead we should call __alloc_bootmem_low(). Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 77a63ae419f..ba363d99de4 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -401,7 +401,7 @@ setup_lowcore(void) * Setup lowcore for boot cpu */ BUILD_BUG_ON(sizeof(struct _lowcore) != LC_PAGES * 4096); - lc = __alloc_bootmem(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0); + lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0); lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) restart_int_handler; @@ -433,7 +433,7 @@ setup_lowcore(void) #ifndef CONFIG_64BIT if (MACHINE_HAS_IEEE) { lc->extended_save_area_addr = (__u32) - __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0); + __alloc_bootmem_low(PAGE_SIZE, PAGE_SIZE, 0); /* enable extended save area */ __ctl_set_bit(14, 29); } From 1bff779285f89cd0b62955c20cca70ada4074236 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 24 Mar 2010 11:49:52 +0100 Subject: [PATCH 243/478] [S390] system.h: Fix compile error for 1 and 2 byte cmpxchg commit 024914477e15ef8b17f271ec47f1bb8a589f0806 "memcg: move charges of anonymous swap" revealed that the 1 byte and 2 byte cmpxchg is currently broken: arch/s390/include/asm/system.h: Assembler messages: arch/s390/include/asm/system.h:241: Error: junk at end of line: `(%r5)' make[1]: *** [mm/page_cgroup.o] Error 1 make[1]: *** Waiting for unfinished jobs.... It turned out that commit 987bcdacb18a3adc2a48d85c9b005069c2f4dd7b ([S390] use inline assembly contraints available with gcc 3.3.3) broke the inline assembly. The or operands are now in constraint 3 and 4 instead of 2 and 3. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/system.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 12be42baa05..1741c1556a4 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h @@ -219,8 +219,8 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) " l %0,%2\n" "0: nr %0,%5\n" " lr %1,%0\n" - " or %0,%2\n" - " or %1,%3\n" + " or %0,%3\n" + " or %1,%4\n" " cs %0,%1,%2\n" " jnl 1f\n" " xr %1,%0\n" @@ -240,8 +240,8 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) " l %0,%2\n" "0: nr %0,%5\n" " lr %1,%0\n" - " or %0,%2\n" - " or %1,%3\n" + " or %0,%3\n" + " or %1,%4\n" " cs %0,%1,%2\n" " jnl 1f\n" " xr %1,%0\n" From 4a31ba57cae853ce1ac00a22c0f5d80bd36685ed Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Wed, 24 Mar 2010 11:49:53 +0100 Subject: [PATCH 244/478] [S390] dasd: fix alignment of transport mode recovery TCW All TCWs need to be aligned on a 64 byte boundary or the I/O will be rejected. For recovery requests we create fresh TCWs, so we need to do the proper alignment here as well. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_3990_erp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 51224f76b98..b3736b8aad3 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -2287,7 +2287,8 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) if (cqr->cpmode == 1) { cplength = 0; - datasize = sizeof(struct tcw) + sizeof(struct tsb); + /* TCW needs to be 64 byte aligned, so leave enough room */ + datasize = 64 + sizeof(struct tcw) + sizeof(struct tsb); } else { cplength = 2; datasize = 0; @@ -2316,8 +2317,8 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) if (cqr->cpmode == 1) { /* make a shallow copy of the original tcw but set new tsb */ erp->cpmode = 1; - erp->cpaddr = erp->data; - tcw = erp->data; + erp->cpaddr = PTR_ALIGN(erp->data, 64); + tcw = erp->cpaddr; tsb = (struct tsb *) &tcw[1]; *tcw = *((struct tcw *)cqr->cpaddr); tcw->tsb = (long)tsb; From b8fde7224d771ce55bfd67cb57d7c4c8f430972f Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 24 Mar 2010 11:49:54 +0100 Subject: [PATCH 245/478] [S390] dasd: check tsb validity Check tsb validity before the tcw_get_tsb function is called. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eckd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 01f4e7a34aa..0cb23311685 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -3155,11 +3155,11 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, tsb = NULL; sense = NULL; - if (irb->scsw.tm.tcw) + if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs == 0x01)) tsb = tcw_get_tsb( (struct tcw *)(unsigned long)irb->scsw.tm.tcw); - if (tsb && (irb->scsw.tm.fcxs == 0x01)) { + if (tsb) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER " tsb->length %d\n", tsb->length); len += sprintf(page + len, KERN_ERR PRINTK_HEADER From 9c95258c0d5911ae263bf50d854e402ce973ab32 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 24 Mar 2010 11:49:55 +0100 Subject: [PATCH 246/478] [S390] sclp: avoid 64 bit division Avoid 64 bit division to fix this compile error on 32 bit: drivers/s390/char/sclp_cmd.c:711: undefined reference to `__udivdi3' Also move the whole arch_get_memory_phys_device function to the memory hotplug related functions. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_cmd.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index fc7ae05ce48..4b60ede07f0 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -308,6 +308,13 @@ struct assign_storage_sccb { u16 rn; } __packed; +int arch_get_memory_phys_device(unsigned long start_pfn) +{ + if (!rzm) + return 0; + return PFN_PHYS(start_pfn) >> ilog2(rzm); +} + static unsigned long long rn2addr(u16 rn) { return (unsigned long long) (rn - 1) * rzm; @@ -704,13 +711,6 @@ int sclp_chp_deconfigure(struct chp_id chpid) return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8); } -int arch_get_memory_phys_device(unsigned long start_pfn) -{ - if (!rzm) - return 0; - return PFN_PHYS(start_pfn) / rzm; -} - struct chp_info_sccb { struct sccb_header header; u8 recognized[SCLP_CHP_INFO_MASK_SIZE]; From 7b26d82f5ea7de5667f87bb5ac6570111d7bff9f Mon Sep 17 00:00:00 2001 From: Hans-Joachim Picht Date: Wed, 24 Mar 2010 11:49:56 +0100 Subject: [PATCH 247/478] [S390] fix broken proc interface for sclp_async This patch now allows the use of the proc interface to either activate or deactivate call home on panic. e.g. echo 1 > /proc/sys/kernel/callhome strict_strtoul() requires _either_'\n\0' _or_ '\0' termination. This was missing and therefore the interface did not recognise valid input. Signed-off-by: Hans-Joachim Picht Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_async.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c index 740fe405c39..f449c696e50 100644 --- a/drivers/s390/char/sclp_async.c +++ b/drivers/s390/char/sclp_async.c @@ -84,6 +84,7 @@ static int proc_handler_callhome(struct ctl_table *ctl, int write, rc = copy_from_user(buf, buffer, sizeof(buf)); if (rc != 0) return -EFAULT; + buf[len - 1] = '\0'; if (strict_strtoul(buf, 0, &val) != 0) return -EINVAL; if (val != 0 && val != 1) From 06c0dd72aea3985d0ea036f771ebb1d1083bf69f Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 24 Mar 2010 11:49:57 +0100 Subject: [PATCH 248/478] [S390] fix boot failures with compressed kernels Fix two bugs with the kernel image compression: 1) reset the bss section of the compressed vmlinux 2) clear the high half of the registers for 64 bit early enough for the decompression step Signed-off-by: Martin Schwidefsky --- arch/s390/boot/compressed/misc.c | 8 ++++---- arch/s390/kernel/head.S | 3 +++ arch/s390/kernel/head64.S | 2 -- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index a97d6952582..14e0479d388 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c @@ -24,8 +24,8 @@ /* Symbols defined by linker scripts */ extern char input_data[]; extern int input_len; -extern int _text; -extern int _end; +extern char _text, _end; +extern char _bss, _ebss; static void error(char *m); @@ -129,12 +129,12 @@ unsigned long decompress_kernel(void) unsigned long output_addr; unsigned char *output; + check_ipl_parmblock((void *) 0, (unsigned long) output + SZ__bss_start); + memset(&_bss, 0, &_ebss - &_bss); free_mem_ptr = (unsigned long)&_end; free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; output = (unsigned char *) ((free_mem_end_ptr + 4095UL) & -4096UL); - check_ipl_parmblock((void *) 0, (unsigned long) output + SZ__bss_start); - #ifdef CONFIG_BLK_DEV_INITRD /* * Move the initrd right behind the end of the decompressed diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index ca4a62bd862..9d1f76702d4 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -517,7 +517,10 @@ startup: lhi %r1,2 # mode 2 = esame (dump) sigp %r1,%r0,0x12 # switch to esame mode sam64 # switch to 64 bit mode + larl %r13,4f + lmh %r0,%r15,0(%r13) # clear high-order half jg startup_continue +4: .fill 16,4,0x0 #else mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) l %r13,4f-.LPG0(%r13) diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 39580e76865..1f70970de0a 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -21,7 +21,6 @@ startup_continue: larl %r1,sched_clock_base_cc mvc 0(8,%r1),__LC_LAST_UPDATE_CLOCK larl %r13,.LPG1 # get base - lmh %r0,%r15,.Lzero64-.LPG1(%r13) # clear high-order half lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area # move IPL device to lowcore @@ -67,7 +66,6 @@ startup_continue: .L4malign:.quad 0xffffffffffc00000 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8 .Lnop: .long 0x07000700 -.Lzero64:.fill 16,4,0x0 .Lparmaddr: .quad PARMAREA .align 64 From cc8c3b78433222e5dbc1fdfcfdde29e1743f181a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Mar 2010 22:40:53 +0100 Subject: [PATCH 249/478] genirq: Protect access to irq_desc->action in can_request_irq() can_request_irq() accesses and dereferences irq_desc->action w/o holding irq_desc->lock. So action can be freed on another CPU before it's dereferenced. Unlikely, but ... Protect it with desc->lock. Signed-off-by: Thomas Gleixner --- kernel/irq/manage.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 69a3d7b9414..398fda155f6 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -382,6 +382,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) { struct irq_desc *desc = irq_to_desc(irq); struct irqaction *action; + unsigned long flags; if (!desc) return 0; @@ -389,11 +390,14 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) if (desc->status & IRQ_NOREQUEST) return 0; + raw_spin_lock_irqsave(&desc->lock, flags); action = desc->action; if (action) if (irqflags & action->flags & IRQF_SHARED) action = NULL; + raw_spin_unlock_irqrestore(&desc->lock, flags); + return !action; } From 860652bfb890bd861c999ec39fcffabe5b712f85 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Wed, 24 Mar 2010 12:59:20 +0100 Subject: [PATCH 250/478] genirq: Move two IRQ functions from .init.text to .text Both functions should not be marked as __init, since they be called from modules after the init section is freed. Signed-off-by: Henrik Kretzschmar Cc: Yinghai Lu Cc: Peter Zijlstra Cc: Jiri Kosina LKML-Reference: <1269431961-5731-1-git-send-email-henne@nachtwindheim.de> Signed-off-by: Thomas Gleixner --- kernel/irq/chip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 71eba24a39a..3c2d6e7737f 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -729,7 +729,7 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, __set_irq_handler(irq, handle, 0, name); } -void __init set_irq_noprobe(unsigned int irq) +void set_irq_noprobe(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); unsigned long flags; @@ -744,7 +744,7 @@ void __init set_irq_noprobe(unsigned int irq) raw_spin_unlock_irqrestore(&desc->lock, flags); } -void __init set_irq_probe(unsigned int irq) +void set_irq_probe(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); unsigned long flags; From 222e82ac9ffbd3b80ab1b0b1d2c8c60ddb47d69d Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 24 Mar 2010 14:38:37 +0100 Subject: [PATCH 251/478] acpi: Support IBM SMBus CMI devices On some old IBM workstations and desktop computers, the BIOS presents in the DSDT an SMBus object that is missing the HID identifier that the i2c-scmi driver looks for. Modify the ACPI device scan code to insert the missing HID if it finds an IBM system with such an object. Affected machines: IntelliStation Z20/Z30. Note that the i2c-i801 driver no longer works on these machines because of ACPI resource conflicts. Signed-off-by: Darrick J. Wong Signed-off-by: Jean Delvare --- drivers/acpi/scan.c | 38 +++++++++++++++++++++++++++++++++++++ include/acpi/acpi_drivers.h | 2 ++ 2 files changed, 40 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fb7fc24fe72..189cbc2585f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -1032,6 +1033,41 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id) list_add_tail(&id->list, &device->pnp.ids); } +/* + * Old IBM workstations have a DSDT bug wherein the SMBus object + * lacks the SMBUS01 HID and the methods do not have the necessary "_" + * prefix. Work around this. + */ +static int acpi_ibm_smbus_match(struct acpi_device *device) +{ + acpi_handle h_dummy; + struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; + int result; + + if (!dmi_name_in_vendors("IBM")) + return -ENODEV; + + /* Look for SMBS object */ + result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path); + if (result) + return result; + + if (strcmp("SMBS", path.pointer)) { + result = -ENODEV; + goto out; + } + + /* Does it have the necessary (but misnamed) methods? */ + result = -ENODEV; + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy))) + result = 0; +out: + kfree(path.pointer); + return result; +} + static void acpi_device_set_id(struct acpi_device *device) { acpi_status status; @@ -1082,6 +1118,8 @@ static void acpi_device_set_id(struct acpi_device *device) acpi_add_id(device, ACPI_BAY_HID); else if (ACPI_SUCCESS(acpi_dock_match(device))) acpi_add_id(device, ACPI_DOCK_HID); + else if (!acpi_ibm_smbus_match(device)) + acpi_add_id(device, ACPI_SMBUS_IBM_HID); break; case ACPI_BUS_TYPE_POWER: diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 3a4767c01c5..4f7b44866b7 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -65,6 +65,8 @@ #define ACPI_VIDEO_HID "LNXVIDEO" #define ACPI_BAY_HID "LNXIOBAY" #define ACPI_DOCK_HID "LNXDOCK" +/* Quirk for broken IBM BIOSes */ +#define ACPI_SMBUS_IBM_HID "SMBUSIBM" /* * For fixed hardware buttons, we fabricate acpi_devices with HID From e82e15ddd322e4c5847536f044a40812b7ec12bd Mon Sep 17 00:00:00 2001 From: Crane Cai Date: Wed, 24 Mar 2010 14:38:38 +0100 Subject: [PATCH 252/478] i2c-scmi: Support IBM SMBus CMI devices *) add a new HID for IBM SMBus CMI devices *) add methods for IBM SMBus CMI devices *) hook different HID with different control methods set *) minor tweaks as suggested by Jean Delvare Slightly modified by Darrick to use #define'd IBM SMBUS HID from Darrick's ACPI scan quirk patch. Signed-off-by: Crane Cai Signed-off-by: Darrick J. Wong Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-scmi.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index 365e0becaf1..4c9fb4cd4bb 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -33,6 +33,7 @@ struct acpi_smbus_cmi { u8 cap_info:1; u8 cap_read:1; u8 cap_write:1; + struct smbus_methods_t *methods; }; static const struct smbus_methods_t smbus_methods = { @@ -41,8 +42,16 @@ static const struct smbus_methods_t smbus_methods = { .mt_sbw = "_SBW", }; +/* Some IBM BIOSes omit the leading underscore */ +static const struct smbus_methods_t ibm_smbus_methods = { + .mt_info = "SBI_", + .mt_sbr = "SBR_", + .mt_sbw = "SBW_", +}; + static const struct acpi_device_id acpi_smbus_cmi_ids[] = { - {"SMBUS01", 0}, + {"SMBUS01", (kernel_ulong_t)&smbus_methods}, + {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods}, {"", 0} }; @@ -150,11 +159,11 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, if (read_write == I2C_SMBUS_READ) { protocol |= ACPI_SMBUS_PRTCL_READ; - method = smbus_methods.mt_sbr; + method = smbus_cmi->methods->mt_sbr; input.count = 3; } else { protocol |= ACPI_SMBUS_PRTCL_WRITE; - method = smbus_methods.mt_sbw; + method = smbus_cmi->methods->mt_sbw; input.count = 5; } @@ -290,13 +299,13 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, union acpi_object *obj; acpi_status status; - if (!strcmp(name, smbus_methods.mt_info)) { + if (!strcmp(name, smbus_cmi->methods->mt_info)) { status = acpi_evaluate_object(smbus_cmi->handle, - smbus_methods.mt_info, + smbus_cmi->methods->mt_info, NULL, &buffer); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Evaluating %s: %i", - smbus_methods.mt_info, status)); + smbus_cmi->methods->mt_info, status)); return -EIO; } @@ -319,9 +328,9 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, kfree(buffer.pointer); smbus_cmi->cap_info = 1; - } else if (!strcmp(name, smbus_methods.mt_sbr)) + } else if (!strcmp(name, smbus_cmi->methods->mt_sbr)) smbus_cmi->cap_read = 1; - else if (!strcmp(name, smbus_methods.mt_sbw)) + else if (!strcmp(name, smbus_cmi->methods->mt_sbw)) smbus_cmi->cap_write = 1; else ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n", @@ -349,6 +358,7 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level, static int acpi_smbus_cmi_add(struct acpi_device *device) { struct acpi_smbus_cmi *smbus_cmi; + const struct acpi_device_id *id; smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL); if (!smbus_cmi) @@ -362,6 +372,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device) smbus_cmi->cap_read = 0; smbus_cmi->cap_write = 0; + for (id = acpi_smbus_cmi_ids; id->id[0]; id++) + if (!strcmp(id->id, acpi_device_hid(device))) + smbus_cmi->methods = + (struct smbus_methods_t *) id->driver_data; + acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1, acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL); From 0f5ed04cb365ce0117b0588c4d9ed89f2623650b Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 24 Mar 2010 14:38:39 +0100 Subject: [PATCH 253/478] i2c-scmi: Provide module aliases for automatic loading Provide module aliases for automatic loading. Signed-off-by: Darrick J. Wong Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-scmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index 4c9fb4cd4bb..388cbdc96db 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -54,6 +54,7 @@ static const struct acpi_device_id acpi_smbus_cmi_ids[] = { {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods}, {"", 0} }; +MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids); #define ACPI_SMBUS_STATUS_OK 0x00 #define ACPI_SMBUS_STATUS_FAIL 0x07 From 669d3e0babb40018dd6e78f4093c13a2eac73866 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 23 Mar 2010 14:41:45 +0000 Subject: [PATCH 254/478] vlan: adds vlan_dev_select_queue This is required to correctly select vlan tx queue for a driver supporting multi tx queue with ndo_select_queue implemented since currently selected vlan tx queue is unaligned to selected queue by real net_devce ndo_select_queue. Unaligned vlan tx queue selection causes thrash with higher vlan tx lock contention for least fcoe traffic and wrong socket tx queue_mapping for ixgbe having ndo_select_queue implemented. -v2 As per Eric Dumazet comments, mirrored vlan net_device_ops to have them with and without vlan_dev_select_queue and then select according to real dev ndo_select_queue present or not for a vlan net_device. This is to completely skip vlan_dev_select_queue calling for real net_device not supporting ndo_select_queue. Signed-off-by: Vasu Dev Signed-off-by: Jeff Kirsher Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/8021q/vlan_dev.c | 71 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 9e83272fc5b..2fd057c81bb 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -361,6 +361,14 @@ static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, return ret; } +static u16 vlan_dev_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + struct net_device *rdev = vlan_dev_info(dev)->real_dev; + const struct net_device_ops *ops = rdev->netdev_ops; + + return ops->ndo_select_queue(rdev, skb); +} + static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) { /* TODO: gotta make sure the underlying layer can handle it, @@ -688,7 +696,8 @@ static const struct header_ops vlan_header_ops = { .parse = eth_header_parse, }; -static const struct net_device_ops vlan_netdev_ops, vlan_netdev_accel_ops; +static const struct net_device_ops vlan_netdev_ops, vlan_netdev_accel_ops, + vlan_netdev_ops_sq, vlan_netdev_accel_ops_sq; static int vlan_dev_init(struct net_device *dev) { @@ -722,11 +731,17 @@ static int vlan_dev_init(struct net_device *dev) if (real_dev->features & NETIF_F_HW_VLAN_TX) { dev->header_ops = real_dev->header_ops; dev->hard_header_len = real_dev->hard_header_len; - dev->netdev_ops = &vlan_netdev_accel_ops; + if (real_dev->netdev_ops->ndo_select_queue) + dev->netdev_ops = &vlan_netdev_accel_ops_sq; + else + dev->netdev_ops = &vlan_netdev_accel_ops; } else { dev->header_ops = &vlan_header_ops; dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; - dev->netdev_ops = &vlan_netdev_ops; + if (real_dev->netdev_ops->ndo_select_queue) + dev->netdev_ops = &vlan_netdev_ops_sq; + else + dev->netdev_ops = &vlan_netdev_ops; } if (is_vlan_dev(real_dev)) @@ -865,6 +880,56 @@ static const struct net_device_ops vlan_netdev_accel_ops = { #endif }; +static const struct net_device_ops vlan_netdev_ops_sq = { + .ndo_select_queue = vlan_dev_select_queue, + .ndo_change_mtu = vlan_dev_change_mtu, + .ndo_init = vlan_dev_init, + .ndo_uninit = vlan_dev_uninit, + .ndo_open = vlan_dev_open, + .ndo_stop = vlan_dev_stop, + .ndo_start_xmit = vlan_dev_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = vlan_dev_set_mac_address, + .ndo_set_rx_mode = vlan_dev_set_rx_mode, + .ndo_set_multicast_list = vlan_dev_set_rx_mode, + .ndo_change_rx_flags = vlan_dev_change_rx_flags, + .ndo_do_ioctl = vlan_dev_ioctl, + .ndo_neigh_setup = vlan_dev_neigh_setup, + .ndo_get_stats = vlan_dev_get_stats, +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) + .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, + .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, + .ndo_fcoe_enable = vlan_dev_fcoe_enable, + .ndo_fcoe_disable = vlan_dev_fcoe_disable, + .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, +#endif +}; + +static const struct net_device_ops vlan_netdev_accel_ops_sq = { + .ndo_select_queue = vlan_dev_select_queue, + .ndo_change_mtu = vlan_dev_change_mtu, + .ndo_init = vlan_dev_init, + .ndo_uninit = vlan_dev_uninit, + .ndo_open = vlan_dev_open, + .ndo_stop = vlan_dev_stop, + .ndo_start_xmit = vlan_dev_hwaccel_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = vlan_dev_set_mac_address, + .ndo_set_rx_mode = vlan_dev_set_rx_mode, + .ndo_set_multicast_list = vlan_dev_set_rx_mode, + .ndo_change_rx_flags = vlan_dev_change_rx_flags, + .ndo_do_ioctl = vlan_dev_ioctl, + .ndo_neigh_setup = vlan_dev_neigh_setup, + .ndo_get_stats = vlan_dev_get_stats, +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) + .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, + .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, + .ndo_fcoe_enable = vlan_dev_fcoe_enable, + .ndo_fcoe_disable = vlan_dev_fcoe_disable, + .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, +#endif +}; + void vlan_setup(struct net_device *dev) { ether_setup(dev); From f6b9f4b263f3178fc0f23f0e67d04386528cc727 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 23 Mar 2010 14:42:05 +0000 Subject: [PATCH 255/478] vlan: updates vlan real_num_tx_queues Updates real_num_tx_queues in case underlying real device has changed real_num_tx_queues. -v2 As per Eric Dumazet comment:- -- adds BUG_ON to catch case of real_num_tx_queues exceeding num_tx_queues. -- created this self contained patch to just update real_num_tx_queues. Signed-off-by: Vasu Dev Signed-off-by: Jeff Kirsher Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/8021q/vlan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 453512266ea..db783d7af5a 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -378,6 +378,8 @@ static void vlan_transfer_features(struct net_device *dev, #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid; #endif + vlandev->real_num_tx_queues = dev->real_num_tx_queues; + BUG_ON(vlandev->real_num_tx_queues > vlandev->num_tx_queues); if (old_features != vlandev->features) netdev_features_change(vlandev); From 03e6d819c2cb2cc8ce5642669a0a7c72336ee7a2 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 23 Mar 2010 20:40:50 +0000 Subject: [PATCH 256/478] skbuff: remove unused dma_head & dma_maps fields The dma map fields in the skb_shared_info structure no longer has any users and can be dropped since it is making the skb_shared_info unecessarily larger. Running slabtop show that we were using 4K slabs for the skb->head on x86_64 w/ an allocation size of 1522. It turns out that the dma_head and dma_maps array made skb_shared large enough that we had crossed over the 2k boundary with standard frames and as such we were using 4k blocks of memory for all skbs. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/skbuff.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 03f816a9b65..124f90cd5a3 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -190,9 +190,6 @@ struct skb_shared_info { atomic_t dataref; unsigned short nr_frags; unsigned short gso_size; -#ifdef CONFIG_HAS_DMA - dma_addr_t dma_head; -#endif /* Warning: this field is not always filled in (UFO)! */ unsigned short gso_segs; unsigned short gso_type; @@ -201,9 +198,6 @@ struct skb_shared_info { struct sk_buff *frag_list; struct skb_shared_hwtstamps hwtstamps; skb_frag_t frags[MAX_SKB_FRAGS]; -#ifdef CONFIG_HAS_DMA - dma_addr_t dma_maps[MAX_SKB_FRAGS]; -#endif /* Intermediate layers must ensure that destructor_arg * remains valid until skb destructor */ void * destructor_arg; From c26f91a3df1999ec1b3298372d73f90cbab81106 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 22 Mar 2010 09:32:26 +0100 Subject: [PATCH 257/478] x86: Remove excessive early_res debug output Commit 08677214e318297 ("x86: Make 64 bit use early_res instead of bootmem before slab") introduced early_res replacement for bootmem, but left code in __free_pages_memory() which dumps all the ranges that are beeing freed, without any additional information, causing some noise in dmesg during bootup. Just remove printing of the ranges, that doesn't provide anything useful anyway. While at it, remove other commented-out KERN_DEBUG messages in the NO_BOOTMEM code as well. Signed-off-by: Jiri Kosina Found-OK-by: Andrew Morton Cc: Johannes Weiner Cc: Yinghai Lu LKML-Reference: Signed-off-by: Ingo Molnar --- mm/bootmem.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/mm/bootmem.c b/mm/bootmem.c index d7c791ef003..9b134460b01 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -180,19 +180,12 @@ static void __init __free_pages_memory(unsigned long start, unsigned long end) end_aligned = end & ~(BITS_PER_LONG - 1); if (end_aligned <= start_aligned) { -#if 1 - printk(KERN_DEBUG " %lx - %lx\n", start, end); -#endif for (i = start; i < end; i++) __free_pages_bootmem(pfn_to_page(i), 0); return; } -#if 1 - printk(KERN_DEBUG " %lx %lx - %lx %lx\n", - start, start_aligned, end_aligned, end); -#endif for (i = start; i < start_aligned; i++) __free_pages_bootmem(pfn_to_page(i), 0); @@ -428,9 +421,6 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, { #ifdef CONFIG_NO_BOOTMEM free_early(physaddr, physaddr + size); -#if 0 - printk(KERN_DEBUG "free %lx %lx\n", physaddr, size); -#endif #else unsigned long start, end; @@ -456,9 +446,6 @@ void __init free_bootmem(unsigned long addr, unsigned long size) { #ifdef CONFIG_NO_BOOTMEM free_early(addr, addr + size); -#if 0 - printk(KERN_DEBUG "free %lx %lx\n", addr, size); -#endif #else unsigned long start, end; From 966f3a7570447c5025d67a618d408e68a3ae3167 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 11 Mar 2010 17:01:19 -0700 Subject: [PATCH 258/478] PCI: for address space collisions, show conflicting resource With request_resource_conflict(), we can learn what the actual conflict is, so print that info for debugging purposes. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- drivers/pci/setup-res.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 7d678bb15ff..17bed18d24a 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -93,8 +93,7 @@ void pci_update_resource(struct pci_dev *dev, int resno) int pci_claim_resource(struct pci_dev *dev, int resource) { struct resource *res = &dev->resource[resource]; - struct resource *root; - int err; + struct resource *root, *conflict; root = pci_find_parent_resource(dev, res); if (!root) { @@ -103,12 +102,15 @@ int pci_claim_resource(struct pci_dev *dev, int resource) return -EINVAL; } - err = request_resource(root, res); - if (err) + conflict = request_resource_conflict(root, res); + if (conflict) { dev_err(&dev->dev, - "address space collision: %pR already in use\n", res); + "address space collision: %pR conflicts with %s %pR\n", + res, conflict->name, conflict); + return -EBUSY; + } - return err; + return 0; } EXPORT_SYMBOL(pci_claim_resource); From 99ddd552fef7e6e3b7dc76ba8fee9ea5869d1e14 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 16 Mar 2010 15:52:58 -0600 Subject: [PATCH 259/478] PCI: break out primary/secondary/subordinate for readability No functional change; just add names for the primary/secondary/subordinate bus numbers read from config space rather than repeatedly masking/shifting. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2a943090a3b..7feacf521e1 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -673,16 +673,20 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); u32 buses, i, j = 0; u16 bctl; + u8 primary, secondary, subordinate; int broken = 0; pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); + primary = buses & 0xFF; + secondary = (buses >> 8) & 0xFF; + subordinate = (buses >> 16) & 0xFF; - dev_dbg(&dev->dev, "scanning behind bridge, config %06x, pass %d\n", - buses & 0xffffff, pass); + dev_dbg(&dev->dev, "scanning [bus %02x-%02x] behind bridge, pass %d\n", + secondary, subordinate, pass); /* Check if setup is sensible at all */ if (!pass && - ((buses & 0xff) != bus->number || ((buses >> 8) & 0xff) <= bus->number)) { + (primary != bus->number || secondary <= bus->number)) { dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n"); broken = 1; } @@ -693,15 +697,15 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); - if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus && !broken) { - unsigned int cmax, busnr; + if ((secondary || subordinate) && !pcibios_assign_all_busses() && + !is_cardbus && !broken) { + unsigned int cmax; /* * Bus already configured by firmware, process it in the first * pass and just note the configuration. */ if (pass) goto out; - busnr = (buses >> 8) & 0xFF; /* * If we already got to this bus through a different bridge, @@ -710,13 +714,13 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, * However, we continue to descend down the hierarchy and * scan remaining child buses. */ - child = pci_find_bus(pci_domain_nr(bus), busnr); + child = pci_find_bus(pci_domain_nr(bus), secondary); if (!child) { - child = pci_add_new_bus(bus, dev, busnr); + child = pci_add_new_bus(bus, dev, secondary); if (!child) goto out; - child->primary = buses & 0xFF; - child->subordinate = (buses >> 16) & 0xFF; + child->primary = primary; + child->subordinate = subordinate; child->bridge_ctl = bctl; } From 7b8ff6da028232aadae6bcc7c7406c8966d0b3c4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 16 Mar 2010 15:53:03 -0600 Subject: [PATCH 260/478] PCI: make disabled window printk style match the enabled ones No functional change; this just tweaks the changes from 349e1823a405 so the new printks for disabled PCI-to-PCI bridge windows match the ones for the enabled windows. Signed-off-by: Bjorn Helgaas CC: Yinghai Lu Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 7feacf521e1..c82548afcd5 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -312,7 +312,7 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child) dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); } else { dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [io %04lx - %04lx] reg reading\n", + " bridge window [io %#06lx-%#06lx] (disabled)\n", base, limit); } } @@ -336,7 +336,7 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child) dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); } else { dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [mem 0x%08lx - 0x%08lx] reg reading\n", + " bridge window [mem %#010lx-%#010lx] (disabled)\n", base, limit + 0xfffff); } } @@ -387,7 +387,7 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child) dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); } else { dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [mem 0x%08lx - %08lx pref] reg reading\n", + " bridge window [mem %#010lx-%#010lx pref] (disabled)\n", base, limit + 0xfffff); } } From e1944c6b0fba80a7837c1cbc47dfbf46e1274a4b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 16 Mar 2010 15:53:08 -0600 Subject: [PATCH 261/478] PCI: print resources consistently with %pR No functional change; just print resources in the conventional style. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/pciehp_hpc.c | 5 ++--- drivers/pci/ioapic.c | 9 ++++----- drivers/pcmcia/rsrc_nonstatic.c | 12 ++++-------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 40b48f569b1..9665d6b17a2 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -832,9 +832,8 @@ static inline void dbg_ctrl(struct controller *ctrl) for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { if (!pci_resource_len(pdev, i)) continue; - ctrl_info(ctrl, " PCI resource [%d] : 0x%llx@0x%llx\n", - i, (unsigned long long)pci_resource_len(pdev, i), - (unsigned long long)pci_resource_start(pdev, i)); + ctrl_info(ctrl, " PCI resource [%d] : %pR\n", + i, &pdev->resource[i]); } ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); ctrl_info(ctrl, " Physical Slot Number : %d\n", PSN(ctrl)); diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c index 3e0d7b5dd1b..fb9fdf4a42b 100644 --- a/drivers/pci/ioapic.c +++ b/drivers/pci/ioapic.c @@ -31,9 +31,9 @@ static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent) acpi_status status; unsigned long long gsb; struct ioapic *ioapic; - u64 addr; int ret; char *type; + struct resource *res; handle = DEVICE_ACPI_HANDLE(&dev->dev); if (!handle) @@ -69,13 +69,12 @@ static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent) if (pci_request_region(dev, 0, type)) goto exit_disable; - addr = pci_resource_start(dev, 0); - if (acpi_register_ioapic(ioapic->handle, addr, ioapic->gsi_base)) + res = &dev->resource[0]; + if (acpi_register_ioapic(ioapic->handle, res->start, ioapic->gsi_base)) goto exit_release; pci_set_drvdata(dev, ioapic); - dev_info(&dev->dev, "%s at %#llx, GSI %u\n", type, addr, - ioapic->gsi_base); + dev_info(&dev->dev, "%s at %pR, GSI %u\n", type, res, ioapic->gsi_base); return 0; exit_release: diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 4663b3fa9f9..b4968ca5bc9 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -867,10 +867,8 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s) if (res == &ioport_resource) continue; dev_printk(KERN_INFO, &s->cb_dev->dev, - "pcmcia: parent PCI bridge I/O " - "window: 0x%llx - 0x%llx\n", - (unsigned long long)res->start, - (unsigned long long)res->end); + "pcmcia: parent PCI bridge window: %pR\n", + res); if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end)) done |= IORESOURCE_IO; @@ -880,10 +878,8 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s) if (res == &iomem_resource) continue; dev_printk(KERN_INFO, &s->cb_dev->dev, - "pcmcia: parent PCI bridge Memory " - "window: 0x%llx - 0x%llx\n", - (unsigned long long)res->start, - (unsigned long long)res->end); + "pcmcia: parent PCI bridge window: %pR\n", + res); if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end)) done |= IORESOURCE_MEM; } From c519a5a7dab2d8e9a114f003e2d369bcf8e913f3 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 19 Mar 2010 14:56:27 -0600 Subject: [PATCH 262/478] PCI: complain about devices that seem to be broken If we can tell that a device isn't working correctly, we should tell the user to make debugging easier. Otherwise, it can take a lot of work to determine whether the problem is in the driver, PCMCIA, PCI, hardware, etc., as in http://bugzilla.kernel.org/show_bug.cgi?id=12006 Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c82548afcd5..882bd8d29fe 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -174,14 +174,19 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, pci_read_config_dword(dev, pos, &sz); pci_write_config_dword(dev, pos, l); + if (!sz) + goto fail; /* BAR not implemented */ + /* * All bits set in sz means the device isn't working properly. - * If the BAR isn't implemented, all bits must be 0. If it's a - * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit - * 1 must be clear. + * If it's a memory BAR or a ROM, bit 0 must be clear; if it's + * an io BAR, bit 1 must be clear. */ - if (!sz || sz == 0xffffffff) + if (sz == 0xffffffff) { + dev_err(&dev->dev, "reg %x: invalid size %#x; broken device?\n", + pos, sz); goto fail; + } /* * I don't know how l can have all bits set. Copied from old code. @@ -244,13 +249,17 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, pos, res); } } else { - sz = pci_size(l, sz, mask); + u32 size = pci_size(l, sz, mask); - if (!sz) + if (!size) { + dev_err(&dev->dev, "reg %x: invalid size " + "(l %#x sz %#x mask %#x); broken device?", + pos, l, sz, mask); goto fail; + } res->start = l; - res->end = l + sz; + res->end = l + size; dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); } From ca8463926306580c25e62eb901a206530d480cae Mon Sep 17 00:00:00 2001 From: Tim Yamin Date: Fri, 19 Mar 2010 14:22:58 -0700 Subject: [PATCH 263/478] PCI quirk: only apply CX700 PCI bus parking quirk if external VT6212L is present Apply the CX700 quirk only when an external VT6212L is present (which is the case for the errant hardware the quirk was written for), don't touch the settings otherwise -- Hauppage PVR-500 tuners need PCI Bus Parking in order to work and when that's turned on everything seems to behave fine. I guess the underlying problem is a combination of an external VT6212L and the CX700 rather than the CX700's PCI being broken completely for all cases... Reported-by: Jeroen Roos Signed-off-by: Tim Yamin Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 81d19d5683a..8284958fc53 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1977,11 +1977,25 @@ static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) /* * Disable PCI Bus Parking and PCI Master read caching on CX700 * which causes unspecified timing errors with a VT6212L on the PCI - * bus leading to USB2.0 packet loss. The defaults are that these - * features are turned off but some BIOSes turn them on. + * bus leading to USB2.0 packet loss. + * + * This quirk is only enabled if a second (on the external PCI bus) + * VT6212L is found -- the CX700 core itself also contains a USB + * host controller with the same PCI ID as the VT6212L. */ + /* Count VT6212L instances */ + struct pci_dev *p = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_8235_USB_2, NULL); uint8_t b; + + /* p should contain the first (internal) VT6212L -- see if we have + an external one by searching again */ + p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235_USB_2, p); + if (!p) + return; + pci_dev_put(p); + if (pci_read_config_byte(dev, 0x76, &b) == 0) { if (b & 0x40) { /* Turn off PCI Bus Parking */ @@ -2008,7 +2022,7 @@ static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) } } } -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching); /* * For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the From a5ee4eb75413c145334c30e43f1af9875dad6fd7 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 22 Mar 2010 09:52:16 +0100 Subject: [PATCH 264/478] PCI quirk: RS780/RS880: work around missing MSI initialization AMD says in section 2.5.4 (GFX MSI Enable) of #43291 (AMD 780G Family Register Programming Requirements): The SBIOS must enable internal graphics MSI capability in GCCFG by setting the following: NBCFG.NB_CNTL.STRAP_MSI_ENABLE='1' Quite a few BIOS writers misinterpret this sentence and think that enabling MSI is an optional feature. However, clearing that bit just prevents delivery of MSI messages but does not remove the MSI PCI capabilities registers, and so leaves these devices unusable for any driver that attempts to use MSI. Setting that bit is not possible after the BIOS has locked down the configuration registers, so we have to manually disable MSI for the affected devices. This fixes the codec communication errors in the HDA driver when accessing the HDMI audio device, and allows us to get rid of the overcautious quirk in radeon_irq_kms.c. Signed-off-by: Clemens Ladisch Tested-by: Alex Deucher Cc: Signed-off-by: Jesse Barnes --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 8 +----- drivers/pci/quirks.c | 33 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 3cfd60fd008..ea4c645ece1 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -116,13 +116,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev) } /* enable msi */ rdev->msi_enabled = 0; - /* MSIs don't seem to work on my rs780; - * not sure about rs880 or other rs780s. - * Needs more investigation. - */ - if ((rdev->family >= CHIP_RV380) && - (rdev->family != CHIP_RS780) && - (rdev->family != CHIP_RS880)) { + if (rdev->family >= CHIP_RV380) { int ret = pci_enable_msi(rdev->pdev); if (!ret) { rdev->msi_enabled = 1; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 8284958fc53..bb5b46abc99 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2493,6 +2493,39 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4374, DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375, quirk_msi_intx_disable_bug); +/* + * MSI does not work with the AMD RS780/RS880 internal graphics and HDMI audio + * devices unless the BIOS has initialized the nb_cntl.strap_msi_enable bit. + */ +static void __init rs780_int_gfx_disable_msi(struct pci_dev *int_gfx_bridge) +{ + u32 nb_cntl; + + if (!int_gfx_bridge->subordinate) + return; + + pci_bus_write_config_dword(int_gfx_bridge->bus, PCI_DEVFN(0, 0), + 0x60, 0); + pci_bus_read_config_dword(int_gfx_bridge->bus, PCI_DEVFN(0, 0), + 0x64, &nb_cntl); + + if (!(nb_cntl & BIT(10))) { + dev_warn(&int_gfx_bridge->dev, + FW_WARN "RS780: MSI for internal graphics disabled\n"); + int_gfx_bridge->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; + } +} + +#define PCI_DEVICE_ID_AMD_RS780_P2P_INT_GFX 0x9602 + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_RS780_P2P_INT_GFX, + rs780_int_gfx_disable_msi); +/* wrong vendor ID on M4A785TD motherboard: */ +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ASUSTEK, + PCI_DEVICE_ID_AMD_RS780_P2P_INT_GFX, + rs780_int_gfx_disable_msi); + #endif /* CONFIG_PCI_MSI */ #ifdef CONFIG_PCI_IOV From 9a127aad4d60968fba96622008ea0d243688f2b0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 24 Mar 2010 01:47:00 +0000 Subject: [PATCH 265/478] af_key: return error if pfkey_xfrm_policy2msg_prep() fails The original code saved the error value but just returned 0 in the end. Signed-off-by: Dan Carpenter Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/key/af_key.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/key/af_key.c b/net/key/af_key.c index 36870788264..344145f23c3 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2129,10 +2129,9 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c int err; out_skb = pfkey_xfrm_policy2msg_prep(xp); - if (IS_ERR(out_skb)) { - err = PTR_ERR(out_skb); - goto out; - } + if (IS_ERR(out_skb)) + return PTR_ERR(out_skb); + err = pfkey_xfrm_policy2msg(out_skb, xp, dir); if (err < 0) return err; @@ -2148,7 +2147,6 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c out_hdr->sadb_msg_seq = c->seq; out_hdr->sadb_msg_pid = c->pid; pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp)); -out: return 0; } From 5ae73518cb39dd81e641dfa7ce20751c853579e0 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Fri, 19 Mar 2010 00:38:29 +0100 Subject: [PATCH 266/478] firewire: core: fix Model_ID in modalias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The modalias string of devices that represent units on a FireWire node did not show Module_ID entries within unit directories. This was because firewire-core searched only the root directory of the configuration ROM for a Model_ID entry. We now search first the root directory, then the unit directory. IOW honor a unit directory's Model_ID if present, otherwise fall back to the root directory's model ID (if present). Furthermore, apply the same change to Vendor_ID. This had the same issue but it was less apparent because most devices provide Vendor_ID only in the root directory. And finally, also use this strategy for the remaining two IDs in the modalias, Specifier_ID and Version. It does not actually make sense to look for them elsewhere than in the unit directory because they are mandatory there. However, a uniform search order simplifies the implementation and has no adverse affect in practice. Side notes: - The older counterpart of this, nodemgr.c of ieee1394, looked for Vendor_ID first in the root directory, then in the unit directory, and for Model_ID only in the unit directory. - There is a single mainline driver which requires Vendor_ID and Model_ID --- the firedtv driver. This one worked because FireDTVs provide Vendor_ID in the root directory and Model_ID identically in root directory and unit directory. - Apart from firedtv, there are currently no drivers known to me (including userspace drivers) that look at the Vendor_ID or Model_ID of the modalias. Reported-by: Maciej Żenczykowski Signed-off-by: Stefan Richter --- drivers/firewire/core-device.c | 52 +++++++++++++--------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 014cabd3afd..c91d7179eb9 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -180,44 +180,32 @@ static int fw_unit_match(struct device *dev, struct device_driver *drv) return 0; } +static void get_modalias_ids(const u32 *directory, int *id) +{ + struct fw_csr_iterator ci; + int key, value; + + fw_csr_iterator_init(&ci, directory); + while (fw_csr_iterator_next(&ci, &key, &value)) { + switch (key) { + case CSR_VENDOR: id[0] = value; break; + case CSR_MODEL: id[1] = value; break; + case CSR_SPECIFIER_ID: id[2] = value; break; + case CSR_VERSION: id[3] = value; break; + } + } +} + static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) { - struct fw_device *device = fw_parent_device(unit); - struct fw_csr_iterator ci; + int id[] = {0, 0, 0, 0}; - int key, value; - int vendor = 0; - int model = 0; - int specifier_id = 0; - int version = 0; - - fw_csr_iterator_init(&ci, &device->config_rom[5]); - while (fw_csr_iterator_next(&ci, &key, &value)) { - switch (key) { - case CSR_VENDOR: - vendor = value; - break; - case CSR_MODEL: - model = value; - break; - } - } - - fw_csr_iterator_init(&ci, unit->directory); - while (fw_csr_iterator_next(&ci, &key, &value)) { - switch (key) { - case CSR_SPECIFIER_ID: - specifier_id = value; - break; - case CSR_VERSION: - version = value; - break; - } - } + get_modalias_ids(&fw_parent_device(unit)->config_rom[5], id); + get_modalias_ids(unit->directory, id); return snprintf(buffer, buffer_size, "ieee1394:ven%08Xmo%08Xsp%08Xver%08X", - vendor, model, specifier_id, version); + id[0], id[1], id[2], id[3]); } static int fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) From fe43d6d9cf59d8f8cbfdcde2018de13ffd1285c7 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Fri, 19 Mar 2010 00:39:07 +0100 Subject: [PATCH 267/478] firewire: core: align driver match with modalias The driver match strategy was: - Match vendor/model/specifier/version of the unit directory. - If that was a miss, match vendor from the root directory and model/specifier/version of the unit directory. This was inconsistent with how the modalias string was constructed until recently (take vendor/model from root directory and specifier/ version from unit directory). It was also inconsistent with how it is done since the parent commit: - Use vendor/model/specifier/version of the unit directory if possible, - fall back to one or more of vendor/model/specifier/version from the root directory depending on which ones are not present at the unit directory. Fix this inconsistency by sharing the ROM scanner function between modalias printer function and driver match function. Signed-off-by: Stefan Richter --- drivers/firewire/core-device.c | 101 +++++++++++++++------------------ 1 file changed, 45 insertions(+), 56 deletions(-) diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index c91d7179eb9..92b633d643f 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -127,60 +127,7 @@ int fw_csr_string(const u32 *directory, int key, char *buf, size_t size) } EXPORT_SYMBOL(fw_csr_string); -static bool is_fw_unit(struct device *dev); - -static int match_unit_directory(const u32 *directory, u32 match_flags, - const struct ieee1394_device_id *id) -{ - struct fw_csr_iterator ci; - int key, value, match; - - match = 0; - fw_csr_iterator_init(&ci, directory); - while (fw_csr_iterator_next(&ci, &key, &value)) { - if (key == CSR_VENDOR && value == id->vendor_id) - match |= IEEE1394_MATCH_VENDOR_ID; - if (key == CSR_MODEL && value == id->model_id) - match |= IEEE1394_MATCH_MODEL_ID; - if (key == CSR_SPECIFIER_ID && value == id->specifier_id) - match |= IEEE1394_MATCH_SPECIFIER_ID; - if (key == CSR_VERSION && value == id->version) - match |= IEEE1394_MATCH_VERSION; - } - - return (match & match_flags) == match_flags; -} - -static int fw_unit_match(struct device *dev, struct device_driver *drv) -{ - struct fw_unit *unit = fw_unit(dev); - struct fw_device *device; - const struct ieee1394_device_id *id; - - /* We only allow binding to fw_units. */ - if (!is_fw_unit(dev)) - return 0; - - device = fw_parent_device(unit); - id = container_of(drv, struct fw_driver, driver)->id_table; - - for (; id->match_flags != 0; id++) { - if (match_unit_directory(unit->directory, id->match_flags, id)) - return 1; - - /* Also check vendor ID in the root directory. */ - if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) && - match_unit_directory(&device->config_rom[5], - IEEE1394_MATCH_VENDOR_ID, id) && - match_unit_directory(unit->directory, id->match_flags - & ~IEEE1394_MATCH_VENDOR_ID, id)) - return 1; - } - - return 0; -} - -static void get_modalias_ids(const u32 *directory, int *id) +static void get_ids(const u32 *directory, int *id) { struct fw_csr_iterator ci; int key, value; @@ -196,12 +143,54 @@ static void get_modalias_ids(const u32 *directory, int *id) } } +static void get_modalias_ids(struct fw_unit *unit, int *id) +{ + get_ids(&fw_parent_device(unit)->config_rom[5], id); + get_ids(unit->directory, id); +} + +static bool match_ids(const struct ieee1394_device_id *id_table, int *id) +{ + int match = 0; + + if (id[0] == id_table->vendor_id) + match |= IEEE1394_MATCH_VENDOR_ID; + if (id[1] == id_table->model_id) + match |= IEEE1394_MATCH_MODEL_ID; + if (id[2] == id_table->specifier_id) + match |= IEEE1394_MATCH_SPECIFIER_ID; + if (id[3] == id_table->version) + match |= IEEE1394_MATCH_VERSION; + + return (match & id_table->match_flags) == id_table->match_flags; +} + +static bool is_fw_unit(struct device *dev); + +static int fw_unit_match(struct device *dev, struct device_driver *drv) +{ + const struct ieee1394_device_id *id_table = + container_of(drv, struct fw_driver, driver)->id_table; + int id[] = {0, 0, 0, 0}; + + /* We only allow binding to fw_units. */ + if (!is_fw_unit(dev)) + return 0; + + get_modalias_ids(fw_unit(dev), id); + + for (; id_table->match_flags != 0; id_table++) + if (match_ids(id_table, id)) + return 1; + + return 0; +} + static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) { int id[] = {0, 0, 0, 0}; - get_modalias_ids(&fw_parent_device(unit)->config_rom[5], id); - get_modalias_ids(unit->directory, id); + get_modalias_ids(unit, id); return snprintf(buffer, buffer_size, "ieee1394:ven%08Xmo%08Xsp%08Xver%08X", From 5cfb80a73b5a52fb19d8b0611203e4dd58e8e9a2 Mon Sep 17 00:00:00 2001 From: Daisuke Nishimura Date: Tue, 23 Mar 2010 13:35:11 -0700 Subject: [PATCH 268/478] memcg: disable move charge in no mmu case In commit 02491447 ("memcg: move charges of anonymous swap"), I tried to disable move charge feature in no mmu case by enclosing all the related functions with "#ifdef CONFIG_MMU", but the commit places these ifdefs in wrong place. (it seems that it's mangled while handling some fixes...) This patch fixes it up. Signed-off-by: Daisuke Nishimura Cc: Balbir Singh Cc: KAMEZAWA Hiroyuki Cc: Daisuke Nishimura Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memcontrol.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 7973b5221fb..00dda352144 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -3946,28 +3946,6 @@ one_by_one: } return ret; } -#else /* !CONFIG_MMU */ -static int mem_cgroup_can_attach(struct cgroup_subsys *ss, - struct cgroup *cgroup, - struct task_struct *p, - bool threadgroup) -{ - return 0; -} -static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss, - struct cgroup *cgroup, - struct task_struct *p, - bool threadgroup) -{ -} -static void mem_cgroup_move_task(struct cgroup_subsys *ss, - struct cgroup *cont, - struct cgroup *old_cont, - struct task_struct *p, - bool threadgroup) -{ -} -#endif /** * is_target_pte_for_mc - check a pte whether it is valid for move charge @@ -4330,6 +4308,28 @@ static void mem_cgroup_move_task(struct cgroup_subsys *ss, } mem_cgroup_clear_mc(); } +#else /* !CONFIG_MMU */ +static int mem_cgroup_can_attach(struct cgroup_subsys *ss, + struct cgroup *cgroup, + struct task_struct *p, + bool threadgroup) +{ + return 0; +} +static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss, + struct cgroup *cgroup, + struct task_struct *p, + bool threadgroup) +{ +} +static void mem_cgroup_move_task(struct cgroup_subsys *ss, + struct cgroup *cont, + struct cgroup *old_cont, + struct task_struct *p, + bool threadgroup) +{ +} +#endif struct cgroup_subsys mem_cgroup_subsys = { .name = "memory", From 9d34706f42f9b8c15185423d9af98d37ba21d011 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Tue, 23 Mar 2010 13:35:12 -0700 Subject: [PATCH 269/478] cgroups: remove duplicate include commit e6a1105b ("cgroups: subsystem module loading interface") and commit c50cc752 ("sched, cgroups: Fix module export") result in duplicate including of module.h Signed-off-by: Li Zefan Acked-by: Paul Menage Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cgroup.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index ef909a32975..e2769e13980 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -27,7 +27,6 @@ */ #include -#include #include #include #include From e7bbcdf3747e3919c31cfa87853c69d178bce548 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 23 Mar 2010 13:35:12 -0700 Subject: [PATCH 270/478] memcontrol: fix potential null deref There was a potential null deref introduced in c62b1a3b31b5 ("memcg: use generic percpu instead of private implementation"). Signed-off-by: Dan Carpenter Acked-by: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memcontrol.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 00dda352144..9ed760dc744 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -3691,8 +3691,10 @@ static struct mem_cgroup *mem_cgroup_alloc(void) else mem = vmalloc(size); - if (mem) - memset(mem, 0, size); + if (!mem) + return NULL; + + memset(mem, 0, size); mem->stat = alloc_percpu(struct mem_cgroup_stat_cpu); if (!mem->stat) { if (size < PAGE_SIZE) From 05731b979476969d4d1cbbcb535fc0f5ea90dba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 23 Mar 2010 13:35:13 -0700 Subject: [PATCH 271/478] rtc/mc13783: fix use after free bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was introduced by v2.6.34-rc1~38: 4c014e8 (rtc/mc13783: protect rtc {,un}registration by mc13783 lock) Signed-off-by: Uwe Kleine-König Reported-by: Dan Carpenter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-mc13783.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c index d60c81b7b69..1379c7faa44 100644 --- a/drivers/rtc/rtc-mc13783.c +++ b/drivers/rtc/rtc-mc13783.c @@ -319,35 +319,38 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) { int ret; struct mc13783_rtc *priv; + struct mc13783 *mc13783; int rtcrst_pending; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->mc13783 = dev_get_drvdata(pdev->dev.parent); + mc13783 = dev_get_drvdata(pdev->dev.parent); + priv->mc13783 = mc13783; + platform_set_drvdata(pdev, priv); - mc13783_lock(priv->mc13783); + mc13783_lock(mc13783); - ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_RTCRST, + ret = mc13783_irq_request(mc13783, MC13783_IRQ_RTCRST, mc13783_rtc_reset_handler, DRIVER_NAME, priv); if (ret) goto err_reset_irq_request; - ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_RTCRST, + ret = mc13783_irq_status(mc13783, MC13783_IRQ_RTCRST, NULL, &rtcrst_pending); if (ret) goto err_reset_irq_status; priv->valid = !rtcrst_pending; - ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_1HZ, + ret = mc13783_irq_request_nounmask(mc13783, MC13783_IRQ_1HZ, mc13783_rtc_update_handler, DRIVER_NAME, priv); if (ret) goto err_update_irq_request; - ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_TODA, + ret = mc13783_irq_request_nounmask(mc13783, MC13783_IRQ_TODA, mc13783_rtc_alarm_handler, DRIVER_NAME, priv); if (ret) goto err_alarm_irq_request; @@ -357,22 +360,22 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) if (IS_ERR(priv->rtc)) { ret = PTR_ERR(priv->rtc); - mc13783_irq_free(priv->mc13783, MC13783_IRQ_TODA, priv); + mc13783_irq_free(mc13783, MC13783_IRQ_TODA, priv); err_alarm_irq_request: - mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); + mc13783_irq_free(mc13783, MC13783_IRQ_1HZ, priv); err_update_irq_request: err_reset_irq_status: - mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); + mc13783_irq_free(mc13783, MC13783_IRQ_RTCRST, priv); err_reset_irq_request: platform_set_drvdata(pdev, NULL); kfree(priv); } - mc13783_unlock(priv->mc13783); + mc13783_unlock(mc13783); return ret; } From ef5da59f12602815baa8fad98241b77dedea3b31 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 23 Mar 2010 13:35:14 -0700 Subject: [PATCH 272/478] scripts/kernel-doc: handle struct member __aligned scripts/kernel-doc erroneously says: Warning(include/linux/skbuff.h:410): Excess struct/union/enum/typedef member 'cb' description in 'sk_buff' on this line in struct sk_buff: char cb[48] __aligned(8); due to treating the last field as the struct member name, so teach kernel-doc to ignore __aligned(x) in structs. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/kernel-doc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index c7865c362d2..c297eb4785d 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1424,6 +1424,8 @@ sub dump_struct($$) { $nested =~ s/\/\*.*?\*\///gos; # strip kmemcheck_bitfield_{begin,end}.*; $members =~ s/kmemcheck_bitfield_.*?;//gos; + # strip attributes + $members =~ s/__aligned\s*\(\d+\)//gos; create_parameterlist($members, ';', $file); check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested); From 7731d9a5d415414aa6903709453786d4a5ff57e4 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 23 Mar 2010 13:35:15 -0700 Subject: [PATCH 273/478] fs/binfmt_aout.c: fix pointer warnings fs/binfmt_aout.c: In function `aout_core_dump': fs/binfmt_aout.c:125: warning: passing argument 2 of `dump_write' makes pointer from integer without a cast include/linux/coredump.h:12: note: expected `const void *' but argument is of type `long unsigned int' fs/binfmt_aout.c:132: warning: passing argument 2 of `dump_write' makes pointer from integer without a cast include/linux/coredump.h:12: note: expected `const void *' but argument is of type `long unsigned int' due to dump_write() expecting a user void *. Fold casts into the START_DATA/START_STACK macros and shut up the warnings. Signed-off-by: Borislav Petkov Cc: Daisuke HATAYAMA Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_aout.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 15d80bb35d6..9b6aef0f75e 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -75,14 +75,16 @@ static int aout_core_dump(struct coredump_params *cprm) struct file *file = cprm->file; mm_segment_t fs; int has_dumped = 0; - unsigned long dump_start, dump_size; + void __user *dump_start; + int dump_size; struct user dump; #ifdef __alpha__ -# define START_DATA(u) (u.start_data) +# define START_DATA(u) ((void __user *)u.start_data) #else -# define START_DATA(u) ((u.u_tsize << PAGE_SHIFT) + u.start_code) +# define START_DATA(u) ((void __user *)((u.u_tsize << PAGE_SHIFT) + \ + u.start_code)) #endif -# define START_STACK(u) (u.start_stack) +# define START_STACK(u) ((void __user *)u.start_stack) fs = get_fs(); set_fs(KERNEL_DS); @@ -104,9 +106,9 @@ static int aout_core_dump(struct coredump_params *cprm) /* make sure we actually have a data and stack area to dump */ set_fs(USER_DS); - if (!access_ok(VERIFY_READ, (void __user *)START_DATA(dump), dump.u_dsize << PAGE_SHIFT)) + if (!access_ok(VERIFY_READ, START_DATA(dump), dump.u_dsize << PAGE_SHIFT)) dump.u_dsize = 0; - if (!access_ok(VERIFY_READ, (void __user *)START_STACK(dump), dump.u_ssize << PAGE_SHIFT)) + if (!access_ok(VERIFY_READ, START_STACK(dump), dump.u_ssize << PAGE_SHIFT)) dump.u_ssize = 0; set_fs(KERNEL_DS); From 091e635e6735fa4496c4a18e7e967b58e961303c Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 23 Mar 2010 13:35:16 -0700 Subject: [PATCH 274/478] Documentation/volatile-considered-harmful.txt: correct cpu_relax() documentation cpu_relax() is documented in volatile-considered-harmful.txt to be a memory barrier. However, everyone with the exception of Blackfin and possibly ia64 defines cpu_relax() to be a compiler barrier. Make the documentation reflect the general concensus. Linus sayeth: : I don't think it was ever the intention that it would be seen as anything : but a compiler barrier, although it is obviously implied that it might : well perform some per-architecture actions that have "memory barrier-like" : semantics. : : After all, the whole and only point of the "cpu_relax()" thing is to tell : the CPU that we're busy-looping on some event. : : And that "event" might be (and often is) about reading the same memory : location over and over until it changes to what we want it to be. So it's : quite possible that on various architectures the "cpu_relax()" could be : about making sure that such a tight loop on loads doesn't starve cache : transactions, for example - and as such look a bit like a memory barrier : from a CPU standpoint. : : But it's not meant to have any kind of architectural memory ordering : semantics as far as the kernel is concerned - those must come from other : sources. Signed-off-by: Russell King Cc: Acked-by: Linus Torvalds Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/volatile-considered-harmful.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/volatile-considered-harmful.txt b/Documentation/volatile-considered-harmful.txt index 991c26a6ef6..db0cb228d64 100644 --- a/Documentation/volatile-considered-harmful.txt +++ b/Documentation/volatile-considered-harmful.txt @@ -63,9 +63,9 @@ way to perform a busy wait is: cpu_relax(); The cpu_relax() call can lower CPU power consumption or yield to a -hyperthreaded twin processor; it also happens to serve as a memory barrier, -so, once again, volatile is unnecessary. Of course, busy-waiting is -generally an anti-social act to begin with. +hyperthreaded twin processor; it also happens to serve as a compiler +barrier, so, once again, volatile is unnecessary. Of course, busy- +waiting is generally an anti-social act to begin with. There are still a few rare situations where volatile makes sense in the kernel: From 1d53661d26aa779dcd74f8a1c5a94e181cc101d8 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 23 Mar 2010 13:35:17 -0700 Subject: [PATCH 275/478] blackfin: enable DEBUG_SECTION_MISMATCH We see only one section mismatch now after thousands of randconfigs, and a bug has been filed about that one. Signed-off-by: Mike Frysinger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/Kconfig.debug | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8e5ec5e1ab9..1fafb4b99c9 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -103,7 +103,8 @@ config HEADERS_CHECK config DEBUG_SECTION_MISMATCH bool "Enable full Section mismatch analysis" - depends on UNDEFINED + depends on UNDEFINED || (BLACKFIN) + default y # This option is on purpose disabled for now. # It will be enabled when we are down to a reasonable number # of section mismatch warnings (< 10 for an allyesconfig build) From 3a4df13d2420ae1998e5c7d26275f8714e84da30 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 23 Mar 2010 13:35:18 -0700 Subject: [PATCH 276/478] get_maintainer: repair STDIN usage Commit 22dd5b0cba50a197aaa3bd2790a29ee2e8e4e372 (fix perlcritic warnings) broke the ability to handle STDIN because the three argument version of open() cannot handle standard IO-streams (which is mentioned in PerlBestPractices, too). Signed-off-by: Wolfram Sang Cc: Stephen Hemminger Acked-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index f76f3d13276..6f97a13bcee 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -284,7 +284,7 @@ foreach my $file (@ARGV) { my $file_cnt = @files; my $lastfile; - open(my $patch, '<', $file) + open(my $patch, "< $file") or die "$P: Can't open $file: $!\n"; while (<$patch>) { my $patch_line = $_; From 5ca9ea9a17a14c68611d3774d1e8a7ab6c7f4763 Mon Sep 17 00:00:00 2001 From: Greg Thelen Date: Tue, 23 Mar 2010 13:35:19 -0700 Subject: [PATCH 277/478] memcg: fix typo in memcg documentation Update memory.txt to be more consistent: s/swapiness/swappiness/ Signed-off-by: Greg Thelen Acked-by: Balbir Singh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cgroups/memory.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index f8bc802d70b..3a6aecd078b 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -340,7 +340,7 @@ Note: 5.3 swappiness Similar to /proc/sys/vm/swappiness, but affecting a hierarchy of groups only. - Following cgroups' swapiness can't be changed. + Following cgroups' swappiness can't be changed. - root cgroup (uses /proc/sys/vm/swappiness). - a cgroup which uses hierarchy and it has child cgroup. - a cgroup which uses hierarchy and not the root of hierarchy. From 06ca02b06fc26b3f940d223f319397a72a591ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20R=C3=B6jfors?= Date: Tue, 23 Mar 2010 13:35:20 -0700 Subject: [PATCH 278/478] drivers/gpio/max730x.c: add license macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the header in max730x it is licensed GPLv2. Add a MODULE_LICENSE to avoid getting the kernel tainted. [w.sang@pengutronix.de: add MODULE_AUTHOR and MODULE_DESCRIPTION also] Signed-off-by: Richard Röjfors Signed-off-by: Wolfram Sang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/max730x.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpio/max730x.c b/drivers/gpio/max730x.c index c9bced55f82..4a7d662ff9b 100644 --- a/drivers/gpio/max730x.c +++ b/drivers/gpio/max730x.c @@ -242,3 +242,7 @@ int __devexit __max730x_remove(struct device *dev) return ret; } EXPORT_SYMBOL_GPL(__max730x_remove); + +MODULE_AUTHOR("Juergen Beisert, Wolfram Sang"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MAX730x GPIO-Expanders, generic parts"); From 28b8e8d4e2e3e27aa911b5aee59d5194a878f53e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 23 Mar 2010 13:35:20 -0700 Subject: [PATCH 279/478] MAINTAINERS: use tab not spaces for delimiter Keeps MAINTAINERS a bit more consistent. done via sed -r -i -e 's/^([A-Z]):[ \t]+/\1:\t/g' MAINTAINERS Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 449d4440208..fbc3d653d52 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -797,12 +797,12 @@ M: Michael Petchkovsky S: Maintained ARM/NOMADIK ARCHITECTURE -M: Alessandro Rubini -M: STEricsson -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained -F: arch/arm/mach-nomadik/ -F: arch/arm/plat-nomadik/ +M: Alessandro Rubini +M: STEricsson +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: arch/arm/mach-nomadik/ +F: arch/arm/plat-nomadik/ ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT M: Nelson Castillo @@ -1926,17 +1926,17 @@ F: drivers/scsi/dpt* F: drivers/scsi/dpt/ DRBD DRIVER -P: Philipp Reisner -P: Lars Ellenberg -M: drbd-dev@lists.linbit.com -L: drbd-user@lists.linbit.com -W: http://www.drbd.org -T: git git://git.drbd.org/linux-2.6-drbd.git drbd -T: git git://git.drbd.org/drbd-8.3.git -S: Supported -F: drivers/block/drbd/ -F: lib/lru_cache.c -F: Documentation/blockdev/drbd/ +P: Philipp Reisner +P: Lars Ellenberg +M: drbd-dev@lists.linbit.com +L: drbd-user@lists.linbit.com +W: http://www.drbd.org +T: git git://git.drbd.org/linux-2.6-drbd.git drbd +T: git git://git.drbd.org/drbd-8.3.git +S: Supported +F: drivers/block/drbd/ +F: lib/lru_cache.c +F: Documentation/blockdev/drbd/ DRIVER CORE, KOBJECTS, AND SYSFS M: Greg Kroah-Hartman @@ -3518,8 +3518,8 @@ F: drivers/scsi/sym53c8xx_2/ LTP (Linux Test Project) M: Rishikesh K Rajak M: Garrett Cooper -M: Mike Frysinger -M: Subrata Modak +M: Mike Frysinger +M: Subrata Modak L: ltp-list@lists.sourceforge.net (subscribers-only) W: http://ltp.sourceforge.net/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/galak/ltp.git @@ -6201,7 +6201,7 @@ F: arch/x86/ X86 PLATFORM DRIVERS M: Matthew Garrett L: platform-driver-x86@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.git S: Maintained F: drivers/platform/x86 From 3fa30460ea502133a18a07b14452cd660906f16f Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 23 Mar 2010 13:35:21 -0700 Subject: [PATCH 280/478] nommu: fix an incorrect comment in the do_mmap_shared_file() Fix an incorrect comment in the do_mmap_shared_file(). If a mapping is requested MAP_SHARED, then a private copy cannot be made and still provide correct semantics. Signed-off-by: David Howells Reported-by: Dave Hudson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/nommu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mm/nommu.c b/mm/nommu.c index 605ace8982a..e4b8f4d28a3 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1040,10 +1040,9 @@ static int do_mmap_shared_file(struct vm_area_struct *vma) if (ret != -ENOSYS) return ret; - /* getting an ENOSYS error indicates that direct mmap isn't - * possible (as opposed to tried but failed) so we'll fall - * through to making a private copy of the data and mapping - * that if we can */ + /* getting -ENOSYS indicates that direct mmap isn't possible (as + * opposed to tried but failed) so we can only give a suitable error as + * it's not possible to make a private copy if MAP_SHARED was given */ return -ENODEV; } From 4c87684d32e8f95715d53039dcd2d998dc63d1eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Tue, 23 Mar 2010 13:35:22 -0700 Subject: [PATCH 281/478] kfifo: fix KFIFO_INIT in include/linux/kfifo.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit include/linux/kfifo.h first defines and then undefines __kfifo_initializer which is used by INIT_KFIFO (which is also a macro, so building a module which uses INIT_KFIFO will fail). Signed-off-by: David Härdeman Acked-by: Stefani Seibold Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kfifo.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index bc0fc795bd3..ece0b1c3381 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -102,8 +102,6 @@ union { \ unsigned char name##kfifo_buffer[size]; \ struct kfifo name = __kfifo_initializer(size, name##kfifo_buffer) -#undef __kfifo_initializer - extern void kfifo_init(struct kfifo *fifo, void *buffer, unsigned int size); extern __must_check int kfifo_alloc(struct kfifo *fifo, unsigned int size, From 5e07c2c7301bd2c82e55cf5cbb36f7b5bddeb8e9 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 23 Mar 2010 13:35:23 -0700 Subject: [PATCH 282/478] Documentation: rename PCI/PCI-DMA-mapping.txt to DMA-API-HOWTO.txt This patch renames PCI/PCI-DMA-mapping.txt to DMA-API-HOWTO.txt. The commit 51e7364ef281e540371f084008732b13292622f0 "Documentation: rename PCI-DMA-mapping.txt to DMA-API-HOWTO.txt" was supposed to do this but it didn't. Signed-off-by: FUJITA Tomonori Acked-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/{PCI/PCI-DMA-mapping.txt => DMA-API-HOWTO.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/{PCI/PCI-DMA-mapping.txt => DMA-API-HOWTO.txt} (100%) diff --git a/Documentation/PCI/PCI-DMA-mapping.txt b/Documentation/DMA-API-HOWTO.txt similarity index 100% rename from Documentation/PCI/PCI-DMA-mapping.txt rename to Documentation/DMA-API-HOWTO.txt From 20072205fcdf7d85cd3101f1f11dfab333c5fd0c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 23 Mar 2010 13:35:24 -0700 Subject: [PATCH 283/478] scripts/kernel-doc: fix fatal error on function prototype Fix a fatal error in scripts/kernel-doc when a function signature uses __init_or_module (just ignore that string): Error(drivers/base/platform.c:568): cannot understand prototype: 'struct platform_device * __init_or_module platform_create_bundle(struct platform_driver *driver, int (*probe)(struct platform_device *), struct resource *res, unsigned int n_res, const void *data, size_t size) ' Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/kernel-doc | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index c297eb4785d..fcdfb245a57 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1730,6 +1730,7 @@ sub dump_function($$) { $prototype =~ s/^noinline +//; $prototype =~ s/__devinit +//; $prototype =~ s/__init +//; + $prototype =~ s/__init_or_module +//; $prototype =~ s/^#\s*define\s+//; #ak added $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; From cb53237513bd1e090cce120efe12ede72c932b5f Mon Sep 17 00:00:00 2001 From: Robin Holt Date: Tue, 23 Mar 2010 13:35:26 -0700 Subject: [PATCH 284/478] mm/ksm.c is doing an unneeded _notify in write_protect_page. ksm.c's write_protect_page implements a lockless means of verifying a page does not have any users of the page which are not accounted for via other kernel tracking means. It does this by removing the writable pte with TLB flushes, checking the page_count against the total known users, and then using set_pte_at_notify to make it a read-only entry. An unneeded mmu_notifier callout is made in the case where the known users does not match the page_count. In that event, we are inserting the identical pte and there is no need for the set_pte_at_notify, but rather the simpler set_pte_at suffices. Signed-off-by: Robin Holt Acked-by: Izik Eidus Acked-by: Andrea Arcangeli Acked-by: Hugh Dickins Cc: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/ksm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/ksm.c b/mm/ksm.c index a93f1b7f508..8cdfc2a1e8b 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -751,7 +751,7 @@ static int write_protect_page(struct vm_area_struct *vma, struct page *page, * page */ if (page_mapcount(page) + 1 + swapped != page_count(page)) { - set_pte_at_notify(mm, addr, ptep, entry); + set_pte_at(mm, addr, ptep, entry); goto out_unlock; } entry = pte_wrprotect(entry); From 8c363afe94b885d39ae2e93e41680282a470ad84 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 23 Mar 2010 13:35:27 -0700 Subject: [PATCH 285/478] c2port: fix device_create() return value check Use IS_ERR() instead of comparing to NULL. [akpm@linux-foundation.org: preserve the error code] Signed-off-by: Jani Nikula Cc: Vegard Nossum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/c2port/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c index b5346b4db91..b7a85f46a6c 100644 --- a/drivers/misc/c2port/core.c +++ b/drivers/misc/c2port/core.c @@ -912,8 +912,8 @@ struct c2port_device *c2port_device_register(char *name, c2dev->dev = device_create(c2port_class, NULL, 0, c2dev, "c2port%d", id); - if (unlikely(!c2dev->dev)) { - ret = -ENOMEM; + if (unlikely(IS_ERR(c2dev->dev))) { + ret = PTR_ERR(c2dev->dev); goto error_device_create; } dev_set_drvdata(c2dev->dev, c2dev); From 413b43deab8377819aba1dbad2abf0c15d59b491 Mon Sep 17 00:00:00 2001 From: Ravikiran G Thirumalai Date: Tue, 23 Mar 2010 13:35:28 -0700 Subject: [PATCH 286/478] tmpfs: fix oops on mounts with mpol=default Fix an 'oops' when a tmpfs mount point is mounted with the mpol=default mempolicy. Upon remounting a tmpfs mount point with 'mpol=default' option, the mount code crashed with a null pointer dereference. The initial problem report was on 2.6.27, but the problem exists in mainline 2.6.34-rc as well. On examining the code, we see that mpol_new returns NULL if default mempolicy was requested. This 'NULL' mempolicy is accessed to store the node mask resulting in oops. The following patch fixes it. Signed-off-by: Ravikiran Thirumalai Signed-off-by: KOSAKI Motohiro Cc: Christoph Lameter Cc: Mel Gorman Acked-by: Lee Schermerhorn Cc: Hugh Dickins Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempolicy.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 643f66e1018..745ce90308a 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2215,10 +2215,15 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) goto out; mode = MPOL_PREFERRED; break; - + case MPOL_DEFAULT: + /* + * Insist on a empty nodelist + */ + if (!nodelist) + err = 0; + goto out; /* * case MPOL_BIND: mpol_new() enforces non-empty nodemask. - * case MPOL_DEFAULT: mpol_new() enforces empty nodemask, ignores flags. */ } From d69b2e63e9172afb4d07c305601b79a55509ac4c Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Tue, 23 Mar 2010 13:35:30 -0700 Subject: [PATCH 287/478] tmpfs: mpol=bind:0 don't cause mount error. Currently, following mount operation cause mount error. % mount -t tmpfs -ompol=bind:0 none /tmp Because commit 71fe804b6d5 (mempolicy: use struct mempolicy pointer in shmem_sb_info) corrupted MPOL_BIND parse code. This patch restore the needed one. Signed-off-by: KOSAKI Motohiro Cc: Ravikiran Thirumalai Cc: Christoph Lameter Cc: Mel Gorman Acked-by: Lee Schermerhorn Cc: Hugh Dickins Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempolicy.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 745ce90308a..10db44f9574 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2222,9 +2222,13 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) if (!nodelist) err = 0; goto out; - /* - * case MPOL_BIND: mpol_new() enforces non-empty nodemask. - */ + case MPOL_BIND: + /* + * Insist on a nodelist + */ + if (!nodelist) + goto out; + err = 0; } mode_flags = 0; From 12821f5fb942e795f8009ece14bde868893bd811 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Tue, 23 Mar 2010 13:35:31 -0700 Subject: [PATCH 288/478] tmpfs: handle MPOL_LOCAL mount option properly commit 71fe804b6d5 (mempolicy: use struct mempolicy pointer in shmem_sb_info) added mpol=local mount option. but its feature is broken since it was born. because such code always return 1 (i.e. mount failure). This patch fixes it. Signed-off-by: KOSAKI Motohiro Cc: Ravikiran Thirumalai Cc: Christoph Lameter Cc: Mel Gorman Acked-by: Lee Schermerhorn Cc: Hugh Dickins Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempolicy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 10db44f9574..fb71790398f 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2214,6 +2214,7 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) if (nodelist) goto out; mode = MPOL_PREFERRED; + err = 0; break; case MPOL_DEFAULT: /* From 926f2ae04f183098cf9a30521776fb2759c8afeb Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Tue, 23 Mar 2010 13:35:32 -0700 Subject: [PATCH 289/478] tmpfs: cleanup mpol_parse_str() mpol_parse_str() made lots 'err' variable related bug. Because it is ugly and reviewing unfriendly. This patch simplifies it. Signed-off-by: KOSAKI Motohiro Cc: Ravikiran Thirumalai Cc: Christoph Lameter Cc: Mel Gorman Acked-by: Lee Schermerhorn Cc: Hugh Dickins Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempolicy.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index fb71790398f..6cdfa1df57f 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2195,8 +2195,8 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) char *rest = nodelist; while (isdigit(*rest)) rest++; - if (!*rest) - err = 0; + if (*rest) + goto out; } break; case MPOL_INTERLEAVE: @@ -2205,7 +2205,6 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) */ if (!nodelist) nodes = node_states[N_HIGH_MEMORY]; - err = 0; break; case MPOL_LOCAL: /* @@ -2214,7 +2213,6 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) if (nodelist) goto out; mode = MPOL_PREFERRED; - err = 0; break; case MPOL_DEFAULT: /* @@ -2229,7 +2227,6 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) */ if (!nodelist) goto out; - err = 0; } mode_flags = 0; @@ -2243,13 +2240,14 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) else if (!strcmp(flags, "relative")) mode_flags |= MPOL_F_RELATIVE_NODES; else - err = 1; + goto out; } new = mpol_new(mode, mode_flags, &nodes); if (IS_ERR(new)) - err = 1; - else { + goto out; + + { int ret; NODEMASK_SCRATCH(scratch); if (scratch) { @@ -2260,13 +2258,15 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) ret = -ENOMEM; NODEMASK_SCRATCH_FREE(scratch); if (ret) { - err = 1; mpol_put(new); - } else if (no_context) { - /* save for contextualization */ - new->w.user_nodemask = nodes; + goto out; } } + err = 0; + if (no_context) { + /* save for contextualization */ + new->w.user_nodemask = nodes; + } out: /* Restore string for error message */ From 5574169613b40b85d6f4c67208fa4846b897a0a1 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Tue, 23 Mar 2010 13:35:33 -0700 Subject: [PATCH 290/478] doc: add the documentation for mpol=local commit 3f226aa1c (mempolicy: support mpol=local tmpfs mount option) added new mpol=local mount option. but it didn't add a documentation. This patch does it. Signed-off-by: KOSAKI Motohiro Cc: Ravikiran Thirumalai Cc: Christoph Lameter Cc: Mel Gorman Acked-by: Lee Schermerhorn Cc: Hugh Dickins Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/tmpfs.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/filesystems/tmpfs.txt b/Documentation/filesystems/tmpfs.txt index 3015da0c6b2..fe09a2cb185 100644 --- a/Documentation/filesystems/tmpfs.txt +++ b/Documentation/filesystems/tmpfs.txt @@ -82,11 +82,13 @@ tmpfs has a mount option to set the NUMA memory allocation policy for all files in that instance (if CONFIG_NUMA is enabled) - which can be adjusted on the fly via 'mount -o remount ...' -mpol=default prefers to allocate memory from the local node +mpol=default use the process allocation policy + (see set_mempolicy(2)) mpol=prefer:Node prefers to allocate memory from the given Node mpol=bind:NodeList allocates memory only from nodes in NodeList mpol=interleave prefers to allocate from each node in turn mpol=interleave:NodeList allocates from each node of NodeList in turn +mpol=local prefers to allocate memory from the local node NodeList format is a comma-separated list of decimal numbers and ranges, a range being two hyphen-separated decimal numbers, the smallest and @@ -134,3 +136,5 @@ Author: Christoph Rohland , 1.12.01 Updated: Hugh Dickins, 4 June 2007 +Updated: + KOSAKI Motohiro, 16 Mar 2010 From 5ab116c9349ef52d6fbd2e2917a53f13194b048e Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Tue, 23 Mar 2010 13:35:34 -0700 Subject: [PATCH 291/478] cpuset: fix the problem that cpuset_mem_spread_node() returns an offline node cpuset_mem_spread_node() returns an offline node, and causes an oops. This patch fixes it by initializing task->mems_allowed to node_states[N_HIGH_MEMORY], and updating task->mems_allowed when doing memory hotplug. Signed-off-by: Miao Xie Acked-by: David Rientjes Reported-by: Nick Piggin Tested-by: Nick Piggin Cc: Paul Menage Cc: Li Zefan Cc: Ingo Molnar Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- init/main.c | 2 +- kernel/cpuset.c | 20 ++++++++++++-------- kernel/kthread.c | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/init/main.c b/init/main.c index a1ab78ceb4b..cbead27caef 100644 --- a/init/main.c +++ b/init/main.c @@ -858,7 +858,7 @@ static int __init kernel_init(void * unused) /* * init can allocate pages on any node */ - set_mems_allowed(node_possible_map); + set_mems_allowed(node_states[N_HIGH_MEMORY]); /* * init can run on any cpu. */ diff --git a/kernel/cpuset.c b/kernel/cpuset.c index ba401fab459..5d38bd74483 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -920,9 +920,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, * call to guarantee_online_mems(), as we know no one is changing * our task's cpuset. * - * Hold callback_mutex around the two modifications of our tasks - * mems_allowed to synchronize with cpuset_mems_allowed(). - * * While the mm_struct we are migrating is typically from some * other task, the task_struct mems_allowed that we are hacking * is for our current task, which must allocate new pages for that @@ -1391,11 +1388,10 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont, if (cs == &top_cpuset) { cpumask_copy(cpus_attach, cpu_possible_mask); - to = node_possible_map; } else { guarantee_online_cpus(cs, cpus_attach); - guarantee_online_mems(cs, &to); } + guarantee_online_mems(cs, &to); /* do per-task migration stuff possibly for each in the threadgroup */ cpuset_attach_task(tsk, &to, cs); @@ -2090,15 +2086,23 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb, static int cpuset_track_online_nodes(struct notifier_block *self, unsigned long action, void *arg) { + nodemask_t oldmems; + cgroup_lock(); switch (action) { case MEM_ONLINE: - case MEM_OFFLINE: + oldmems = top_cpuset.mems_allowed; mutex_lock(&callback_mutex); top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY]; mutex_unlock(&callback_mutex); - if (action == MEM_OFFLINE) - scan_for_empty_cpusets(&top_cpuset); + update_tasks_nodemask(&top_cpuset, &oldmems, NULL); + break; + case MEM_OFFLINE: + /* + * needn't update top_cpuset.mems_allowed explicitly because + * scan_for_empty_cpusets() will update it. + */ + scan_for_empty_cpusets(&top_cpuset); break; default: break; diff --git a/kernel/kthread.c b/kernel/kthread.c index 82ed0ea1519..83911c78017 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -219,7 +219,7 @@ int kthreadd(void *unused) set_task_comm(tsk, "kthreadd"); ignore_signals(tsk); set_cpus_allowed_ptr(tsk, cpu_all_mask); - set_mems_allowed(node_possible_map); + set_mems_allowed(node_states[N_HIGH_MEMORY]); current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG; From 53feb29767c29c877f9d47dcfe14211b5b0f7ebd Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Tue, 23 Mar 2010 13:35:35 -0700 Subject: [PATCH 292/478] cpuset: alloc nodemask_t on the heap rather than the stack Signed-off-by: Miao Xie Acked-by: David Rientjes Cc: Nick Piggin Cc: Paul Menage Cc: Li Zefan Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cpuset.c | 94 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 28 deletions(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 5d38bd74483..d10946748ec 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -970,15 +970,20 @@ static void cpuset_change_nodemask(struct task_struct *p, struct cpuset *cs; int migrate; const nodemask_t *oldmem = scan->data; - nodemask_t newmems; + NODEMASK_ALLOC(nodemask_t, newmems, GFP_KERNEL); + + if (!newmems) + return; cs = cgroup_cs(scan->cg); - guarantee_online_mems(cs, &newmems); + guarantee_online_mems(cs, newmems); task_lock(p); - cpuset_change_task_nodemask(p, &newmems); + cpuset_change_task_nodemask(p, newmems); task_unlock(p); + NODEMASK_FREE(newmems); + mm = get_task_mm(p); if (!mm) return; @@ -1048,16 +1053,21 @@ static void update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem, static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs, const char *buf) { - nodemask_t oldmem; + NODEMASK_ALLOC(nodemask_t, oldmem, GFP_KERNEL); int retval; struct ptr_heap heap; + if (!oldmem) + return -ENOMEM; + /* * top_cpuset.mems_allowed tracks node_stats[N_HIGH_MEMORY]; * it's read-only */ - if (cs == &top_cpuset) - return -EACCES; + if (cs == &top_cpuset) { + retval = -EACCES; + goto done; + } /* * An empty mems_allowed is ok iff there are no tasks in the cpuset. @@ -1073,11 +1083,13 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs, goto done; if (!nodes_subset(trialcs->mems_allowed, - node_states[N_HIGH_MEMORY])) - return -EINVAL; + node_states[N_HIGH_MEMORY])) { + retval = -EINVAL; + goto done; + } } - oldmem = cs->mems_allowed; - if (nodes_equal(oldmem, trialcs->mems_allowed)) { + *oldmem = cs->mems_allowed; + if (nodes_equal(*oldmem, trialcs->mems_allowed)) { retval = 0; /* Too easy - nothing to do */ goto done; } @@ -1093,10 +1105,11 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs, cs->mems_allowed = trialcs->mems_allowed; mutex_unlock(&callback_mutex); - update_tasks_nodemask(cs, &oldmem, &heap); + update_tasks_nodemask(cs, oldmem, &heap); heap_free(&heap); done: + NODEMASK_FREE(oldmem); return retval; } @@ -1381,39 +1394,47 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont, struct cgroup *oldcont, struct task_struct *tsk, bool threadgroup) { - nodemask_t from, to; struct mm_struct *mm; struct cpuset *cs = cgroup_cs(cont); struct cpuset *oldcs = cgroup_cs(oldcont); + NODEMASK_ALLOC(nodemask_t, from, GFP_KERNEL); + NODEMASK_ALLOC(nodemask_t, to, GFP_KERNEL); + + if (from == NULL || to == NULL) + goto alloc_fail; if (cs == &top_cpuset) { cpumask_copy(cpus_attach, cpu_possible_mask); } else { guarantee_online_cpus(cs, cpus_attach); } - guarantee_online_mems(cs, &to); + guarantee_online_mems(cs, to); /* do per-task migration stuff possibly for each in the threadgroup */ - cpuset_attach_task(tsk, &to, cs); + cpuset_attach_task(tsk, to, cs); if (threadgroup) { struct task_struct *c; rcu_read_lock(); list_for_each_entry_rcu(c, &tsk->thread_group, thread_group) { - cpuset_attach_task(c, &to, cs); + cpuset_attach_task(c, to, cs); } rcu_read_unlock(); } /* change mm; only needs to be done once even if threadgroup */ - from = oldcs->mems_allowed; - to = cs->mems_allowed; + *from = oldcs->mems_allowed; + *to = cs->mems_allowed; mm = get_task_mm(tsk); if (mm) { - mpol_rebind_mm(mm, &to); + mpol_rebind_mm(mm, to); if (is_memory_migrate(cs)) - cpuset_migrate_mm(mm, &from, &to); + cpuset_migrate_mm(mm, from, to); mmput(mm); } + +alloc_fail: + NODEMASK_FREE(from); + NODEMASK_FREE(to); } /* The various types of files and directories in a cpuset file system */ @@ -1558,13 +1579,21 @@ static int cpuset_sprintf_cpulist(char *page, struct cpuset *cs) static int cpuset_sprintf_memlist(char *page, struct cpuset *cs) { - nodemask_t mask; + NODEMASK_ALLOC(nodemask_t, mask, GFP_KERNEL); + int retval; + + if (mask == NULL) + return -ENOMEM; mutex_lock(&callback_mutex); - mask = cs->mems_allowed; + *mask = cs->mems_allowed; mutex_unlock(&callback_mutex); - return nodelist_scnprintf(page, PAGE_SIZE, mask); + retval = nodelist_scnprintf(page, PAGE_SIZE, *mask); + + NODEMASK_FREE(mask); + + return retval; } static ssize_t cpuset_common_file_read(struct cgroup *cont, @@ -1993,7 +2022,10 @@ static void scan_for_empty_cpusets(struct cpuset *root) struct cpuset *cp; /* scans cpusets being updated */ struct cpuset *child; /* scans child cpusets of cp */ struct cgroup *cont; - nodemask_t oldmems; + NODEMASK_ALLOC(nodemask_t, oldmems, GFP_KERNEL); + + if (oldmems == NULL) + return; list_add_tail((struct list_head *)&root->stack_list, &queue); @@ -2010,7 +2042,7 @@ static void scan_for_empty_cpusets(struct cpuset *root) nodes_subset(cp->mems_allowed, node_states[N_HIGH_MEMORY])) continue; - oldmems = cp->mems_allowed; + *oldmems = cp->mems_allowed; /* Remove offline cpus and mems from this cpuset. */ mutex_lock(&callback_mutex); @@ -2026,9 +2058,10 @@ static void scan_for_empty_cpusets(struct cpuset *root) remove_tasks_in_empty_cpuset(cp); else { update_tasks_cpumask(cp, NULL); - update_tasks_nodemask(cp, &oldmems, NULL); + update_tasks_nodemask(cp, oldmems, NULL); } } + NODEMASK_FREE(oldmems); } /* @@ -2086,16 +2119,19 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb, static int cpuset_track_online_nodes(struct notifier_block *self, unsigned long action, void *arg) { - nodemask_t oldmems; + NODEMASK_ALLOC(nodemask_t, oldmems, GFP_KERNEL); + + if (oldmems == NULL) + return NOTIFY_DONE; cgroup_lock(); switch (action) { case MEM_ONLINE: - oldmems = top_cpuset.mems_allowed; + *oldmems = top_cpuset.mems_allowed; mutex_lock(&callback_mutex); top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY]; mutex_unlock(&callback_mutex); - update_tasks_nodemask(&top_cpuset, &oldmems, NULL); + update_tasks_nodemask(&top_cpuset, oldmems, NULL); break; case MEM_OFFLINE: /* @@ -2108,6 +2144,8 @@ static int cpuset_track_online_nodes(struct notifier_block *self, break; } cgroup_unlock(); + + NODEMASK_FREE(oldmems); return NOTIFY_OK; } #endif From 298359c5bf06c04258d7cf552426e198c47e83c1 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 23 Mar 2010 13:35:37 -0700 Subject: [PATCH 293/478] exit: fix oops in sync_mm_rss In 2.6.34-rc1, removing vhost_net module causes an oops in sync_mm_rss (called from do_exit) when workqueue is destroyed. This does not happen on net-next, or with vhost on top of to 2.6.33. The issue seems to be introduced by 34e55232e59f7b19050267a05ff1226e5cd122a5 ("mm: avoid false sharing of mm_counter) which added sync_mm_rss() that is passed task->mm, and dereferences it without checking. If task is a kernel thread, mm might be NULL. I think this might also happen e.g. with aio. This patch fixes the oops by calling sync_mm_rss when task->mm is set to NULL. I also added BUG_ON to detect any other cases where counters get incremented while mm is NULL. The oops I observed looks like this: BUG: unable to handle kernel NULL pointer dereference at 00000000000002a8 IP: [] sync_mm_rss+0x33/0x6f PGD 0 Oops: 0002 [#1] SMP last sysfs file: /sys/devices/system/cpu/cpu7/cache/index2/shared_cpu_map CPU 2 Modules linked in: vhost_net(-) tun bridge stp sunrpc ipv6 cpufreq_ondemand acpi_cpufreq freq_table kvm_intel kvm i5000_edac edac_core rtc_cmos bnx2 button i2c_i801 i2c_core rtc_core e1000e sg joydev ide_cd_mod serio_raw pcspkr rtc_lib cdrom virtio_net virtio_blk virtio_pci virtio_ring virtio af_packet e1000 shpchp aacraid uhci_hcd ohci_hcd ehci_hcd [last unloaded: microcode] Pid: 2046, comm: vhost Not tainted 2.6.34-rc1-vhost #25 System Planar/IBM System x3550 -[7978B3G]- RIP: 0010:[] [] sync_mm_rss+0x33/0x6f RSP: 0018:ffff8802379b7e60 EFLAGS: 00010202 RAX: 0000000000000008 RBX: ffff88023f2390c0 RCX: 0000000000000000 RDX: ffff88023f2396b0 RSI: 0000000000000000 RDI: ffff88023f2390c0 RBP: ffff8802379b7e60 R08: 0000000000000000 R09: 0000000000000000 R10: ffff88023aecfbc0 R11: 0000000000013240 R12: 0000000000000000 R13: ffffffff81051a6c R14: ffffe8ffffc0f540 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff880001e80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 00000000000002a8 CR3: 000000023af23000 CR4: 00000000000406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process vhost (pid: 2046, threadinfo ffff8802379b6000, task ffff88023f2390c0) Stack: ffff8802379b7ee0 ffffffff81040687 ffffe8ffffc0f558 ffffffffa00a3e2d <0> 0000000000000000 ffff88023f2390c0 ffffffff81055817 ffff8802379b7e98 <0> ffff8802379b7e98 0000000100000286 ffff8802379b7ee0 ffff88023ad47d78 Call Trace: [] do_exit+0x147/0x6c4 [] ? handle_rx_net+0x0/0x17 [vhost_net] [] ? autoremove_wake_function+0x0/0x39 [] ? worker_thread+0x0/0x229 [] kthreadd+0x0/0xf2 [] kernel_thread_helper+0x4/0x10 [] ? kthread+0x0/0x87 [] ? kernel_thread_helper+0x0/0x10 Code: 00 8b 87 6c 02 00 00 85 c0 74 14 48 98 f0 48 01 86 a0 02 00 00 c7 87 6c 02 00 00 00 00 00 00 8b 87 70 02 00 00 85 c0 74 14 48 98 48 01 86 a8 02 00 00 c7 87 70 02 00 00 00 00 00 00 8b 87 74 RIP [] sync_mm_rss+0x33/0x6f RSP CR2: 00000000000002a8 ---[ end trace 41603ba922beddd2 ]--- Fixing recursive fault but reboot is needed! (note: handle_rx_net is a work item using workqueue in question). sync_mm_rss+0x33/0x6f gave me a hint. I also tried reverting 34e55232e59f7b19050267a05ff1226e5cd122a5 and the oops goes away. The module in question calls use_mm and later unuse_mm from a kernel thread. It is when this kernel thread is destroyed that the crash happens. Signed-off-by: Michael S. Tsirkin Andrea Arcangeli Reviewed-by: Rik van Riel Reviewed-by: KAMEZAWA Hiroyuki Reviewed-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory.c | 1 + mm/mmu_context.c | 1 + 2 files changed, 2 insertions(+) diff --git a/mm/memory.c b/mm/memory.c index 5b7f2002e54..bc9ba5a1f5b 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -130,6 +130,7 @@ void __sync_task_rss_stat(struct task_struct *task, struct mm_struct *mm) for (i = 0; i < NR_MM_COUNTERS; i++) { if (task->rss_stat.count[i]) { + BUG_ON(!mm); add_mm_counter(mm, i, task->rss_stat.count[i]); task->rss_stat.count[i] = 0; } diff --git a/mm/mmu_context.c b/mm/mmu_context.c index 0777654147c..9e82e937000 100644 --- a/mm/mmu_context.c +++ b/mm/mmu_context.c @@ -53,6 +53,7 @@ void unuse_mm(struct mm_struct *mm) struct task_struct *tsk = current; task_lock(tsk); + sync_mm_rss(tsk, mm); tsk->mm = NULL; /* active_mm is still 'mm' */ enter_lazy_tlb(mm, tsk); From 6cb4aff0a77cc0e6bae9475d62205319e3ebbf3f Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 23 Mar 2010 13:35:38 -0700 Subject: [PATCH 294/478] reiserfs: fix oops while creating privroot with selinux enabled Commit 57fe60df ("reiserfs: add atomic addition of selinux attributes during inode creation") contains a bug that will cause it to oops when mounting a file system that didn't previously contain extended attributes on a system using security.* xattrs. The issue is that while creating the privroot during mount reiserfs_security_init calls reiserfs_xattr_jcreate_nblocks which dereferences the xattr root. The xattr root doesn't exist, so we get an oops. Addresses http://bugzilla.kernel.org/show_bug.cgi?id=15309 Signed-off-by: Jeff Mahoney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/xattr_security.c | 2 +- include/linux/reiserfs_xattr.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c index d8b5bfcbdd3..de1fcffd906 100644 --- a/fs/reiserfs/xattr_security.c +++ b/fs/reiserfs/xattr_security.c @@ -76,7 +76,7 @@ int reiserfs_security_init(struct inode *dir, struct inode *inode, return error; } - if (sec->length) { + if (sec->length && reiserfs_xattrs_initialized(inode->i_sb)) { blocks = reiserfs_xattr_jcreate_nblocks(inode) + reiserfs_xattr_nblocks(inode, sec->length); /* We don't want to count the directories twice if we have diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h index 99928dce37e..7fa02b4af83 100644 --- a/include/linux/reiserfs_xattr.h +++ b/include/linux/reiserfs_xattr.h @@ -70,6 +70,11 @@ int reiserfs_security_write(struct reiserfs_transaction_handle *th, void reiserfs_security_free(struct reiserfs_security_handle *sec); #endif +static inline int reiserfs_xattrs_initialized(struct super_block *sb) +{ + return REISERFS_SB(sb)->priv_root != NULL; +} + #define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header)) static inline loff_t reiserfs_xattr_nblocks(struct inode *inode, loff_t size) { From 3f8b5ee33293d43ca360771b535dfae8c57259dc Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 23 Mar 2010 13:35:39 -0700 Subject: [PATCH 295/478] reiserfs: properly honor read-only devices The reiserfs journal behaves inconsistently when determining whether to allow a mount of a read-only device. This is due to the use of the continue_replay variable to short circuit the journal scanning. If it's set, it's assumed that there are transactions to replay, but there may not be. If it's unset, it's assumed that there aren't any, and that may not be the case either. I've observed two failure cases: 1) Where a clean file system on a read-only device refuses to mount 2) Where a clean file system on a read-only device passes the optimization and then tries writing the journal header to update the latest mount id. The former is easily observable by using a freshly created file system on a read-only loopback device. This patch moves the check into journal_read_transaction, where it can bail out before it's about to replay a transaction. That way it can go through and skip transactions where appropriate, yet still refuse to mount a file system with outstanding transactions. Signed-off-by: Jeff Mahoney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/journal.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index ba98546fabb..f3de5e8a2ae 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2217,6 +2217,15 @@ static int journal_read_transaction(struct super_block *sb, brelse(d_bh); return 1; } + + if (bdev_read_only(sb->s_bdev)) { + reiserfs_warning(sb, "clm-2076", + "device is readonly, unable to replay log"); + brelse(c_bh); + brelse(d_bh); + return -EROFS; + } + trans_id = get_desc_trans_id(desc); /* now we know we've got a good transaction, and it was inside the valid time ranges */ log_blocks = kmalloc(get_desc_trans_len(desc) * @@ -2459,12 +2468,6 @@ static int journal_read(struct super_block *sb) goto start_log_replay; } - if (continue_replay && bdev_read_only(sb->s_bdev)) { - reiserfs_warning(sb, "clm-2076", - "device is readonly, unable to replay log"); - return -1; - } - /* ok, there are transactions that need to be replayed. start with the first log block, find ** all the valid transactions, and pick out the oldest. */ From 7198f3c9b13c7aa1e5d9f7ff74c0ea303174feff Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 23 Mar 2010 13:35:40 -0700 Subject: [PATCH 296/478] mmc: fix incorrect interpretation of card type bits In the extended CSD register the CARD_TYPE is an 8-bit value of which the upper 6 bits were reserved in JEDEC specifications prior to version 4.4. In version 4.4 two of the reserved bits were designated for identifying support for the newly added High-Speed Dual Data Rate. Unfortunately the mmc_read_ext_csd() function required that the reserved bits be zero instead of ignoring them as it should. This patch makes mmc_read_ext_csd() ignore the CARD_TYPE bits that are reserved or not yet supported. It also stops the function jumping to the end as though an error occurred, when it is only warns that the CARD_TYPE bits (that it does interpret) are invalid. Signed-off-by: Adrian Hunter Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/core/mmc.c | 3 +-- include/linux/mmc/mmc.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 0eac6c81490..e041c003db2 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -225,7 +225,7 @@ static int mmc_read_ext_csd(struct mmc_card *card) mmc_card_set_blockaddr(card); } - switch (ext_csd[EXT_CSD_CARD_TYPE]) { + switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: card->ext_csd.hs_max_dtr = 52000000; break; @@ -237,7 +237,6 @@ static int mmc_read_ext_csd(struct mmc_card *card) printk(KERN_WARNING "%s: card is mmc v4 but doesn't " "support any high-speed modes.\n", mmc_hostname(card->host)); - goto out; } if (card->ext_csd.rev >= 3) { diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index c02c8db7370..8a49cbf0376 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -268,6 +268,7 @@ struct _mmc_csd { #define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ #define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ +#define EXT_CSD_CARD_TYPE_MASK 0x3 /* Mask out reserved and DDR bits */ #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ From c6b6ef8bb05af632889c5536513b9f4004961f73 Mon Sep 17 00:00:00 2001 From: Lee Schermerhorn Date: Tue, 23 Mar 2010 13:35:41 -0700 Subject: [PATCH 297/478] mempolicy: fix get_mempolicy() for relative and static nodes Discovered while testing other mempolicy changes: get_mempolicy() does not handle static/relative mode flags correctly. Return the value that the user specified so that it can be restored via set_mempolicy() if desired. Signed-off-by: Lee Schermerhorn Cc: Hugh Dickins Cc: Ravikiran Thirumalai Cc: KOSAKI Motohiro Cc: Christoph Lameter Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempolicy.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 6cdfa1df57f..8034abd3a13 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -806,9 +806,13 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask, err = 0; if (nmask) { - task_lock(current); - get_policy_nodemask(pol, nmask); - task_unlock(current); + if (mpol_store_user_nodemask(pol)) { + *nmask = pol->w.user_nodemask; + } else { + task_lock(current); + get_policy_nodemask(pol, nmask); + task_unlock(current); + } } out: From 4fd2c20d964a8fb9861045f1022475c9d200d684 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 23 Mar 2010 13:35:42 -0700 Subject: [PATCH 298/478] kcore: fix test for end of list "m" is never NULL here. We need a different test for the end of list condition. Signed-off-by: Dan Carpenter Acked-by: KAMEZAWA Hiroyuki Acked-by: WANG Cong Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/kcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index a44a7897fd4..b442dac8f5f 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -490,7 +490,7 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos) } read_unlock(&kclist_lock); - if (m == NULL) { + if (&m->list == &kclist_head) { if (clear_user(buffer, tsz)) return -EFAULT; } else if (is_vmalloc_or_module_addr((void *)start)) { From b5c26f97ec4a17c650055c83cfc1f2ee6d8818eb Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Tue, 23 Mar 2010 13:35:49 -0700 Subject: [PATCH 299/478] lxfb: set the H- and V-SYNC polarity of the flatpanel output Fixup for the flatpanel output. The geode_modedb attribute flags are used to set the SYNC polarity of the flatpanel. Without this patch our flatpanel registers stayed unconfigured, so we just saw garbage output. Signed-off-by: Michael Grzeschik Cc: Andres Salomon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/geode/lxfb.h | 2 ++ drivers/video/geode/lxfb_ops.c | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h index cc781c00f75..e4c4d89b786 100644 --- a/drivers/video/geode/lxfb.h +++ b/drivers/video/geode/lxfb.h @@ -365,6 +365,8 @@ enum fp_registers { FP_CRC, /* 0x458 */ }; +#define FP_PT2_HSP (1 << 22) +#define FP_PT2_VSP (1 << 23) #define FP_PT2_SCRC (1 << 27) /* shfclk free */ #define FP_PM_P (1 << 24) /* panel power ctl */ diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c index 0e5d8c7c3eb..bc35a95e59d 100644 --- a/drivers/video/geode/lxfb_ops.c +++ b/drivers/video/geode/lxfb_ops.c @@ -274,7 +274,15 @@ static void lx_graphics_enable(struct fb_info *info) u32 msrlo, msrhi; write_fp(par, FP_PT1, 0); - write_fp(par, FP_PT2, FP_PT2_SCRC); + temp = FP_PT2_SCRC; + + if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) + temp |= FP_PT2_HSP; + + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) + temp |= FP_PT2_VSP; + + write_fp(par, FP_PT2, temp); write_fp(par, FP_DFC, FP_DFC_BC); msrlo = MSR_LX_MSR_PADSEL_TFT_SEL_LOW; From 3fbf586cf7f245392142e5407c2a56f1cff979b6 Mon Sep 17 00:00:00 2001 From: Daniel Taylor Date: Tue, 23 Mar 2010 13:35:50 -0700 Subject: [PATCH 300/478] fs/partitions/msdos: add support for large disks In order to use disks larger than 2TiB on Windows XP, it is necessary to use 4096-byte logical sectors in an MBR. Although the kernel storage and functions called from msdos.c used "sector_t" internally, msdos.c still used u32 variables, which results in the ability to handle XP-compatible large disks. This patch changes the internal variables to "sector_t". Daniel said: "In the near future, WD will be releasing products that need this patch". [hirofumi@mail.parknet.co.jp: tweaks and fix] Signed-off-by: Daniel Taylor Signed-off-by: OGAWA Hirofumi Cc: "H. Peter Anvin" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/partitions/msdos.c | 72 +++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 0028d2ef066..b78385840a5 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -31,14 +31,17 @@ */ #include -#define SYS_IND(p) (get_unaligned(&p->sys_ind)) -#define NR_SECTS(p) ({ __le32 __a = get_unaligned(&p->nr_sects); \ - le32_to_cpu(__a); \ - }) +#define SYS_IND(p) get_unaligned(&p->sys_ind) -#define START_SECT(p) ({ __le32 __a = get_unaligned(&p->start_sect); \ - le32_to_cpu(__a); \ - }) +static inline sector_t nr_sects(struct partition *p) +{ + return (sector_t)get_unaligned_le32(&p->nr_sects); +} + +static inline sector_t start_sect(struct partition *p) +{ + return (sector_t)get_unaligned_le32(&p->start_sect); +} static inline int is_extended_partition(struct partition *p) { @@ -104,13 +107,13 @@ static int aix_magic_present(unsigned char *p, struct block_device *bdev) static void parse_extended(struct parsed_partitions *state, struct block_device *bdev, - u32 first_sector, u32 first_size) + sector_t first_sector, sector_t first_size) { struct partition *p; Sector sect; unsigned char *data; - u32 this_sector, this_size; - int sector_size = bdev_logical_block_size(bdev) / 512; + sector_t this_sector, this_size; + sector_t sector_size = bdev_logical_block_size(bdev) / 512; int loopct = 0; /* number of links followed without finding a data partition */ int i; @@ -145,14 +148,14 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev, * First process the data partition(s) */ for (i=0; i<4; i++, p++) { - u32 offs, size, next; - if (!NR_SECTS(p) || is_extended_partition(p)) + sector_t offs, size, next; + if (!nr_sects(p) || is_extended_partition(p)) continue; /* Check the 3rd and 4th entries - these sometimes contain random garbage */ - offs = START_SECT(p)*sector_size; - size = NR_SECTS(p)*sector_size; + offs = start_sect(p)*sector_size; + size = nr_sects(p)*sector_size; next = this_sector + offs; if (i >= 2) { if (offs + size > this_size) @@ -179,13 +182,13 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev, */ p -= 4; for (i=0; i<4; i++, p++) - if (NR_SECTS(p) && is_extended_partition(p)) + if (nr_sects(p) && is_extended_partition(p)) break; if (i == 4) goto done; /* nothing left to do */ - this_sector = first_sector + START_SECT(p) * sector_size; - this_size = NR_SECTS(p) * sector_size; + this_sector = first_sector + start_sect(p) * sector_size; + this_size = nr_sects(p) * sector_size; put_dev_sector(sect); } done: @@ -197,7 +200,7 @@ done: static void parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_SOLARIS_X86_PARTITION Sector sect; @@ -244,7 +247,7 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, */ static void parse_bsd(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin, char *flavour, + sector_t offset, sector_t size, int origin, char *flavour, int max_partitions) { Sector sect; @@ -263,7 +266,7 @@ parse_bsd(struct parsed_partitions *state, struct block_device *bdev, if (le16_to_cpu(l->d_npartitions) < max_partitions) max_partitions = le16_to_cpu(l->d_npartitions); for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { - u32 bsd_start, bsd_size; + sector_t bsd_start, bsd_size; if (state->next == state->limit) break; @@ -290,7 +293,7 @@ parse_bsd(struct parsed_partitions *state, struct block_device *bdev, static void parse_freebsd(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_BSD_DISKLABEL parse_bsd(state, bdev, offset, size, origin, @@ -300,7 +303,7 @@ parse_freebsd(struct parsed_partitions *state, struct block_device *bdev, static void parse_netbsd(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_BSD_DISKLABEL parse_bsd(state, bdev, offset, size, origin, @@ -310,7 +313,7 @@ parse_netbsd(struct parsed_partitions *state, struct block_device *bdev, static void parse_openbsd(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_BSD_DISKLABEL parse_bsd(state, bdev, offset, size, origin, @@ -324,7 +327,7 @@ parse_openbsd(struct parsed_partitions *state, struct block_device *bdev, */ static void parse_unixware(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_UNIXWARE_DISKLABEL Sector sect; @@ -348,7 +351,8 @@ parse_unixware(struct parsed_partitions *state, struct block_device *bdev, if (p->s_label != UNIXWARE_FS_UNUSED) put_partition(state, state->next++, - START_SECT(p), NR_SECTS(p)); + le32_to_cpu(p->start_sect), + le32_to_cpu(p->nr_sects)); p++; } put_dev_sector(sect); @@ -363,7 +367,7 @@ parse_unixware(struct parsed_partitions *state, struct block_device *bdev, */ static void parse_minix(struct parsed_partitions *state, struct block_device *bdev, - u32 offset, u32 size, int origin) + sector_t offset, sector_t size, int origin) { #ifdef CONFIG_MINIX_SUBPARTITION Sector sect; @@ -390,7 +394,7 @@ parse_minix(struct parsed_partitions *state, struct block_device *bdev, /* add each partition in use */ if (SYS_IND(p) == MINIX_PARTITION) put_partition(state, state->next++, - START_SECT(p), NR_SECTS(p)); + start_sect(p), nr_sects(p)); } printk(" >\n"); } @@ -401,7 +405,7 @@ parse_minix(struct parsed_partitions *state, struct block_device *bdev, static struct { unsigned char id; void (*parse)(struct parsed_partitions *, struct block_device *, - u32, u32, int); + sector_t, sector_t, int); } subtypes[] = { {FREEBSD_PARTITION, parse_freebsd}, {NETBSD_PARTITION, parse_netbsd}, @@ -415,7 +419,7 @@ static struct { int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) { - int sector_size = bdev_logical_block_size(bdev) / 512; + sector_t sector_size = bdev_logical_block_size(bdev) / 512; Sector sect; unsigned char *data; struct partition *p; @@ -483,8 +487,8 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) state->next = 5; for (slot = 1 ; slot <= 4 ; slot++, p++) { - u32 start = START_SECT(p)*sector_size; - u32 size = NR_SECTS(p)*sector_size; + sector_t start = start_sect(p)*sector_size; + sector_t size = nr_sects(p)*sector_size; if (!size) continue; if (is_extended_partition(p)) { @@ -513,7 +517,7 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) unsigned char id = SYS_IND(p); int n; - if (!NR_SECTS(p)) + if (!nr_sects(p)) continue; for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++) @@ -521,8 +525,8 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) if (!subtypes[n].parse) continue; - subtypes[n].parse(state, bdev, START_SECT(p)*sector_size, - NR_SECTS(p)*sector_size, slot); + subtypes[n].parse(state, bdev, start_sect(p)*sector_size, + nr_sects(p)*sector_size, slot); } put_dev_sector(sect); return 1; From 8e0cc811e0f8029a7225372fb0951fab102c012f Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Tue, 23 Mar 2010 13:35:50 -0700 Subject: [PATCH 301/478] fs/partition/msdos: fix unusable extended partition for > 512B sector Smaller size than a minimum blocksize can't be used, after all it's handled like 0 size. For extended partition itself, this makes sure to use bigger size than one logical sector size at least. Signed-off-by: OGAWA Hirofumi Cc: Daniel Taylor Cc: "H. Peter Anvin" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/partitions/msdos.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index b78385840a5..90be97f1f5a 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -492,9 +492,16 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) if (!size) continue; if (is_extended_partition(p)) { - /* prevent someone doing mkfs or mkswap on an - extended partition, but leave room for LILO */ - put_partition(state, slot, start, size == 1 ? 1 : 2); + /* + * prevent someone doing mkfs or mkswap on an + * extended partition, but leave room for LILO + * FIXME: this uses one logical sector for > 512b + * sector, although it may not be enough/proper. + */ + sector_t n = 2; + n = min(size, max(sector_size, n)); + put_partition(state, slot, start, n); + printk(" <"); parse_extended(state, bdev, start, size); printk(" >"); From 90fddabf5818367c6bd1fe1b256a10e01827862f Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 24 Mar 2010 09:43:00 +0000 Subject: [PATCH 302/478] Document Linux's circular buffering capabilities Document the circular buffering capabilities available in Linux. Signed-off-by: David Howells Signed-off-by: Paul E. McKenney Reviewed-by: Randy Dunlap Reviewed-by: Stefan Richter Signed-off-by: Linus Torvalds --- Documentation/circular-buffers.txt | 234 +++++++++++++++++++++++++++++ Documentation/memory-barriers.txt | 20 +++ include/linux/circ_buf.h | 4 + 3 files changed, 258 insertions(+) create mode 100644 Documentation/circular-buffers.txt diff --git a/Documentation/circular-buffers.txt b/Documentation/circular-buffers.txt new file mode 100644 index 00000000000..8117e5bf606 --- /dev/null +++ b/Documentation/circular-buffers.txt @@ -0,0 +1,234 @@ + ================ + CIRCULAR BUFFERS + ================ + +By: David Howells + Paul E. McKenney + + +Linux provides a number of features that can be used to implement circular +buffering. There are two sets of such features: + + (1) Convenience functions for determining information about power-of-2 sized + buffers. + + (2) Memory barriers for when the producer and the consumer of objects in the + buffer don't want to share a lock. + +To use these facilities, as discussed below, there needs to be just one +producer and just one consumer. It is possible to handle multiple producers by +serialising them, and to handle multiple consumers by serialising them. + + +Contents: + + (*) What is a circular buffer? + + (*) Measuring power-of-2 buffers. + + (*) Using memory barriers with circular buffers. + - The producer. + - The consumer. + + +========================== +WHAT IS A CIRCULAR BUFFER? +========================== + +First of all, what is a circular buffer? A circular buffer is a buffer of +fixed, finite size into which there are two indices: + + (1) A 'head' index - the point at which the producer inserts items into the + buffer. + + (2) A 'tail' index - the point at which the consumer finds the next item in + the buffer. + +Typically when the tail pointer is equal to the head pointer, the buffer is +empty; and the buffer is full when the head pointer is one less than the tail +pointer. + +The head index is incremented when items are added, and the tail index when +items are removed. The tail index should never jump the head index, and both +indices should be wrapped to 0 when they reach the end of the buffer, thus +allowing an infinite amount of data to flow through the buffer. + +Typically, items will all be of the same unit size, but this isn't strictly +required to use the techniques below. The indices can be increased by more +than 1 if multiple items or variable-sized items are to be included in the +buffer, provided that neither index overtakes the other. The implementer must +be careful, however, as a region more than one unit in size may wrap the end of +the buffer and be broken into two segments. + + +============================ +MEASURING POWER-OF-2 BUFFERS +============================ + +Calculation of the occupancy or the remaining capacity of an arbitrarily sized +circular buffer would normally be a slow operation, requiring the use of a +modulus (divide) instruction. However, if the buffer is of a power-of-2 size, +then a much quicker bitwise-AND instruction can be used instead. + +Linux provides a set of macros for handling power-of-2 circular buffers. These +can be made use of by: + + #include + +The macros are: + + (*) Measure the remaining capacity of a buffer: + + CIRC_SPACE(head_index, tail_index, buffer_size); + + This returns the amount of space left in the buffer[1] into which items + can be inserted. + + + (*) Measure the maximum consecutive immediate space in a buffer: + + CIRC_SPACE_TO_END(head_index, tail_index, buffer_size); + + This returns the amount of consecutive space left in the buffer[1] into + which items can be immediately inserted without having to wrap back to the + beginning of the buffer. + + + (*) Measure the occupancy of a buffer: + + CIRC_CNT(head_index, tail_index, buffer_size); + + This returns the number of items currently occupying a buffer[2]. + + + (*) Measure the non-wrapping occupancy of a buffer: + + CIRC_CNT_TO_END(head_index, tail_index, buffer_size); + + This returns the number of consecutive items[2] that can be extracted from + the buffer without having to wrap back to the beginning of the buffer. + + +Each of these macros will nominally return a value between 0 and buffer_size-1, +however: + + [1] CIRC_SPACE*() are intended to be used in the producer. To the producer + they will return a lower bound as the producer controls the head index, + but the consumer may still be depleting the buffer on another CPU and + moving the tail index. + + To the consumer it will show an upper bound as the producer may be busy + depleting the space. + + [2] CIRC_CNT*() are intended to be used in the consumer. To the consumer they + will return a lower bound as the consumer controls the tail index, but the + producer may still be filling the buffer on another CPU and moving the + head index. + + To the producer it will show an upper bound as the consumer may be busy + emptying the buffer. + + [3] To a third party, the order in which the writes to the indices by the + producer and consumer become visible cannot be guaranteed as they are + independent and may be made on different CPUs - so the result in such a + situation will merely be a guess, and may even be negative. + + +=========================================== +USING MEMORY BARRIERS WITH CIRCULAR BUFFERS +=========================================== + +By using memory barriers in conjunction with circular buffers, you can avoid +the need to: + + (1) use a single lock to govern access to both ends of the buffer, thus + allowing the buffer to be filled and emptied at the same time; and + + (2) use atomic counter operations. + +There are two sides to this: the producer that fills the buffer, and the +consumer that empties it. Only one thing should be filling a buffer at any one +time, and only one thing should be emptying a buffer at any one time, but the +two sides can operate simultaneously. + + +THE PRODUCER +------------ + +The producer will look something like this: + + spin_lock(&producer_lock); + + unsigned long head = buffer->head; + unsigned long tail = ACCESS_ONCE(buffer->tail); + + if (CIRC_SPACE(head, tail, buffer->size) >= 1) { + /* insert one item into the buffer */ + struct item *item = buffer[head]; + + produce_item(item); + + smp_wmb(); /* commit the item before incrementing the head */ + + buffer->head = (head + 1) & (buffer->size - 1); + + /* wake_up() will make sure that the head is committed before + * waking anyone up */ + wake_up(consumer); + } + + spin_unlock(&producer_lock); + +This will instruct the CPU that the contents of the new item must be written +before the head index makes it available to the consumer and then instructs the +CPU that the revised head index must be written before the consumer is woken. + +Note that wake_up() doesn't have to be the exact mechanism used, but whatever +is used must guarantee a (write) memory barrier between the update of the head +index and the change of state of the consumer, if a change of state occurs. + + +THE CONSUMER +------------ + +The consumer will look something like this: + + spin_lock(&consumer_lock); + + unsigned long head = ACCESS_ONCE(buffer->head); + unsigned long tail = buffer->tail; + + if (CIRC_CNT(head, tail, buffer->size) >= 1) { + /* read index before reading contents at that index */ + smp_read_barrier_depends(); + + /* extract one item from the buffer */ + struct item *item = buffer[tail]; + + consume_item(item); + + smp_mb(); /* finish reading descriptor before incrementing tail */ + + buffer->tail = (tail + 1) & (buffer->size - 1); + } + + spin_unlock(&consumer_lock); + +This will instruct the CPU to make sure the index is up to date before reading +the new item, and then it shall make sure the CPU has finished reading the item +before it writes the new tail pointer, which will erase the item. + + +Note the use of ACCESS_ONCE() in both algorithms to read the opposition index. +This prevents the compiler from discarding and reloading its cached value - +which some compilers will do across smp_read_barrier_depends(). This isn't +strictly needed if you can be sure that the opposition index will _only_ be +used the once. + + +=============== +FURTHER READING +=============== + +See also Documentation/memory-barriers.txt for a description of Linux's memory +barrier facilities. diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 7f5809eddee..631ad2f1b22 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -3,6 +3,7 @@ ============================ By: David Howells + Paul E. McKenney Contents: @@ -60,6 +61,10 @@ Contents: - And then there's the Alpha. + (*) Example uses. + + - Circular buffers. + (*) References. @@ -2226,6 +2231,21 @@ The Alpha defines the Linux kernel's memory barrier model. See the subsection on "Cache Coherency" above. +============ +EXAMPLE USES +============ + +CIRCULAR BUFFERS +---------------- + +Memory barriers can be used to implement circular buffering without the need +of a lock to serialise the producer with the consumer. See: + + Documentation/circular-buffers.txt + +for details. + + ========== REFERENCES ========== diff --git a/include/linux/circ_buf.h b/include/linux/circ_buf.h index a2ed0591fb1..90f2471dc6f 100644 --- a/include/linux/circ_buf.h +++ b/include/linux/circ_buf.h @@ -1,3 +1,7 @@ +/* + * See Documentation/circular-buffers.txt for more information. + */ + #ifndef _LINUX_CIRC_BUF_H #define _LINUX_CIRC_BUF_H 1 From 47568d4c56677ede6e7ff7c8e4e0fd860a9c4372 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 24 Mar 2010 17:02:28 +0000 Subject: [PATCH 303/478] FDPIC: For-loop in elf_core_vma_data_size() is incorrect Fix an incorrect for-loop in elf_core_vma_data_size(). The advance-pointer statement lacks an assignment: CC fs/binfmt_elf_fdpic.o fs/binfmt_elf_fdpic.c: In function 'elf_core_vma_data_size': fs/binfmt_elf_fdpic.c:1593: warning: statement with no effect Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- fs/binfmt_elf_fdpic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 2c32d00a669..7ab23e006e4 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1590,7 +1590,7 @@ static size_t elf_core_vma_data_size(unsigned long mm_flags) struct vm_area_struct *vma; size_t size = 0; - for (vma = current->mm->mmap; vma; vma->vm_next) + for (vma = current->mm->mmap; vma; vma = vma->vm_next) if (maydump(vma, mm_flags)) size += vma->vm_end - vma->vm_start; return size; From 61964eba5c419ff710ac996c5ed3a84d5af7490f Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 24 Mar 2010 17:09:19 +0000 Subject: [PATCH 304/478] do_sync_read/write() should set kiocb.ki_nbytes to be consistent do_sync_read/write() should set kiocb.ki_nbytes to be consistent with do_sync_readv_writev(). Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- fs/read_write.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/read_write.c b/fs/read_write.c index b7f4a1f94d4..113386d6fd2 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -258,6 +258,7 @@ ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *pp init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; kiocb.ki_left = len; + kiocb.ki_nbytes = len; for (;;) { ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos); @@ -313,6 +314,7 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; kiocb.ki_left = len; + kiocb.ki_nbytes = len; for (;;) { ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos); From 1147d0f915e3b4c5c4fa279dae2c40016b8f441d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 23 Mar 2010 14:48:37 +0000 Subject: [PATCH 305/478] fscache: add missing unlock Sparse complained about this missing spin_unlock() Signed-off-by: Dan Carpenter Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- fs/fscache/page.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/fscache/page.c b/fs/fscache/page.c index c598ea4c4e7..69809024d71 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -881,6 +881,7 @@ submit_failed: goto nobufs; nobufs_unlock_obj: + spin_unlock(&cookie->stores_lock); spin_unlock(&object->lock); nobufs: spin_unlock(&cookie->lock); From 55e0d7cf279177dfe320f54816320558bc370f24 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 25 Mar 2010 11:00:22 +0100 Subject: [PATCH 306/478] netfilter: xt_hashlimit: dl_seq_stop() fix If dl_seq_start() memory allocation fails, we crash later in dl_seq_stop(), trying to kfree(ERR_PTR(-ENOMEM)) Signed-off-by: Eric Dumazet Signed-off-by: Patrick McHardy --- net/netfilter/xt_hashlimit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 9e9c4896394..70d561a2d9e 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -879,7 +879,8 @@ static void dl_seq_stop(struct seq_file *s, void *v) struct xt_hashlimit_htable *htable = s->private; unsigned int *bucket = (unsigned int *)v; - kfree(bucket); + if (!IS_ERR(bucket)) + kfree(bucket); spin_unlock_bh(&htable->lock); } From 9c13886665c43600bd0af4b38e33c654e648e078 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Thu, 25 Mar 2010 11:17:26 +0100 Subject: [PATCH 307/478] netfilter: ip6table_raw: fix table priority The order of the IPv6 raw table is currently reversed, that makes impossible to use the NOTRACK target in IPv6: for example if someone enters ip6tables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK and if we receive fragmented packets then the first fragment will be untracked and thus skip nf_ct_frag6_gather (and conntrack), while all subsequent fragments enter nf_ct_frag6_gather and reassembly will never successfully be finished. Singed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv6.h | 1 + net/ipv6/netfilter/ip6table_raw.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index d654873aa25..1f7e300094c 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h @@ -59,6 +59,7 @@ enum nf_ip6_hook_priorities { NF_IP6_PRI_FIRST = INT_MIN, NF_IP6_PRI_CONNTRACK_DEFRAG = -400, + NF_IP6_PRI_RAW = -300, NF_IP6_PRI_SELINUX_FIRST = -225, NF_IP6_PRI_CONNTRACK = -200, NF_IP6_PRI_MANGLE = -150, diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index aef31a29de9..b9cf7cd6192 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -13,7 +13,7 @@ static const struct xt_table packet_raw = { .valid_hooks = RAW_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_IPV6, - .priority = NF_IP6_PRI_FIRST, + .priority = NF_IP6_PRI_RAW, }; /* The work comes in here from netfilter.c. */ From 6a4f2ccb467e00281470cde2dee08fe5ecde62d1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 25 Mar 2010 15:00:15 +0100 Subject: [PATCH 308/478] ALSA: hda - Don't set invalid connection index in Realtek initialiaiton Skip initialization of connections of DAC widgets that aren't used, which resulted in invalid verb parameters. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 053d53d8c8b..9a23444e9e7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10043,8 +10043,11 @@ static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, alc_set_pin_output(codec, nid, pin_type); if (spec->multiout.dac_nids[dac_idx] == 0x25) idx = 4; - else + else { + if (spec->multiout.num_dacs >= dac_idx) + return; idx = spec->multiout.dac_nids[dac_idx] - 2; + } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); } From 134b345081534235dbf228b1005c14590e0570ba Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 24 Mar 2010 07:11:01 -0600 Subject: [PATCH 309/478] PCI quirk: Disable MSI on VIA K8T890 systems Bugzilla 15287 indicates that there's a problem with Message Signalled Interrupts on VIA K8T890 systems. Add a quirk to disable MSI on these systems. Signed-off-by: Matthew Wilcox Tested-by: Jan Kreuzer Tested-by: lh Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index bb5b46abc99..f6bbb9c89e3 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2122,6 +2122,7 @@ static void __devinit quirk_disable_msi(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0xa238, quirk_disable_msi); /* Go through the list of Hypertransport capabilities and * return 1 if a HT MSI capability is found and enabled */ From f967a44343e407811898ddac97abc69b293e9810 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Mar 2010 16:34:05 -0600 Subject: [PATCH 310/478] PCI: don't say we claimed a resource if we failed pci_claim_resource() can fail, so pay attention and only claim success when it actually succeeded. If pci_claim_resource() fails, it prints a useful diagnostic. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f6bbb9c89e3..3ea0b29c010 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -368,8 +368,9 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, bus_region.end = res->end; pcibios_bus_to_resource(dev, res, &bus_region); - pci_claim_resource(dev, nr); - dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name); + if (pci_claim_resource(dev, nr) == 0) + dev_info(&dev->dev, "quirk: %pR claimed by %s\n", + res, name); } } From c9c9b564717e5b6b2ae8b770da1c73a348c84cce Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Mar 2010 16:34:10 -0600 Subject: [PATCH 311/478] x86/PCI: remove redundant warnings pci_claim_resource() already prints more detailed error messages, so these are really redundant. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- arch/x86/pci/i386.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index dece3eb9c90..46fd43f7910 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -127,9 +127,6 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) continue; if (!r->start || pci_claim_resource(dev, idx) < 0) { - dev_info(&dev->dev, - "can't reserve window %pR\n", - r); /* * Something is wrong with the region. * Invalidate the resource to prevent @@ -181,8 +178,6 @@ static void __init pcibios_allocate_resources(int pass) "BAR %d: reserving %pr (d=%d, p=%d)\n", idx, r, disabled, pass); if (pci_claim_resource(dev, idx) < 0) { - dev_info(&dev->dev, - "can't reserve %pR\n", r); /* We'll assign a new address later */ r->end -= r->start; r->start = 0; From 99f4692e13ba22b228bdd155473f24ae9bdec1dc Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Mar 2010 16:34:15 -0600 Subject: [PATCH 312/478] frv/PCI: remove redundant warnings pci_claim_resource() already prints more detailed error messages, so these are really redundant. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- arch/frv/mb93090-mb00/pci-frv.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c index 1ed15d7fea2..16bc2cb5649 100644 --- a/arch/frv/mb93090-mb00/pci-frv.c +++ b/arch/frv/mb93090-mb00/pci-frv.c @@ -94,8 +94,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) r = &dev->resource[idx]; if (!r->start) continue; - if (pci_claim_resource(dev, idx) < 0) - printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev)); + pci_claim_resource(dev, idx); } } pcibios_allocate_bus_resources(&bus->children); @@ -125,7 +124,6 @@ static void __init pcibios_allocate_resources(int pass) DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n", r->start, r->end, r->flags, disabled, pass); if (pci_claim_resource(dev, idx) < 0) { - printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, pci_name(dev)); /* We'll assign a new address later */ r->end -= r->start; r->start = 0; From 8f5992291457c8e6de2f5fe39849de6756be1a96 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 25 Mar 2010 17:25:11 +0100 Subject: [PATCH 313/478] netfilter: xt_hashlimit: IPV6 bugfix A missing break statement in hashlimit_ipv6_mask(), and masks between /64 and /95 are not working at all... Signed-off-by: Eric Dumazet Signed-off-by: Patrick McHardy --- net/netfilter/xt_hashlimit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 70d561a2d9e..215a64835de 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -493,6 +493,7 @@ static void hashlimit_ipv6_mask(__be32 *i, unsigned int p) case 64 ... 95: i[2] = maskl(i[2], p - 64); i[3] = 0; + break; case 96 ... 127: i[3] = maskl(i[3], p - 96); break; From eb9fc8ef7cb1362374e55d9503e3e7458f319991 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 25 Mar 2010 09:28:24 -0600 Subject: [PATCH 314/478] x86/PCI: for host bridge address space collisions, show conflicting resource With insert_resource_conflict(), we can learn what the actual conflict is, so print that info for debugging purposes. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- arch/x86/pci/acpi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 6e22454bfaa..75ac3f856ea 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -122,7 +122,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data) struct acpi_resource_address64 addr; acpi_status status; unsigned long flags; - struct resource *root; + struct resource *root, *conflict; u64 start, end; status = resource_to_addr(acpi_res, &addr); @@ -157,9 +157,12 @@ setup_resource(struct acpi_resource *acpi_res, void *data) return AE_OK; } - if (insert_resource(root, res)) { + conflict = insert_resource_conflict(root, res); + if (conflict) { dev_err(&info->bridge->dev, - "can't allocate host bridge window %pR\n", res); + "address space collision: host bridge window %pR " + "conflicts with %s %pR\n", + res, conflict->name, conflict); } else { pci_bus_add_resource(info->bus, res, 0); info->res_num++; From d558b483d5a73f5718705b270cb2090f66ea48c8 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 25 Mar 2010 09:28:30 -0600 Subject: [PATCH 315/478] x86/PCI: truncate _CRS windows with _LEN > _MAX - _MIN + 1 Yanko's GA-MA78GM-S2H (BIOS F11) reports the following resource in a PCI host bridge _CRS: [07] 32-Bit DWORD Address Space Resource Min Relocatability : MinFixed Max Relocatability : MaxFixed Address Minimum : CFF00000 (_MIN) Address Maximum : FEBFFFFF (_MAX) Address Length : 3EE10000 (_LEN) This is invalid per spec (ACPI 4.0, 6.4.3.5) because it's a fixed size, fixed location descriptor, but _LEN != _MAX - _MIN + 1. Based on https://bugzilla.kernel.org/show_bug.cgi?id=15480#c15, I think Windows handles this by truncating the window so it fits between _MIN and _MAX. I also verified this by modifying the SeaBIOS DSDT and booting Windows 2008 R2 with qemu. This patch makes Linux truncate the window, too, which fixes: http://bugzilla.kernel.org/show_bug.cgi?id=15480 Signed-off-by: Bjorn Helgaas Tested-by: Yanko Kaneti Signed-off-by: Jesse Barnes --- arch/x86/pci/acpi.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 75ac3f856ea..e31160216ef 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -123,7 +123,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data) acpi_status status; unsigned long flags; struct resource *root, *conflict; - u64 start, end; + u64 start, end, max_len; status = resource_to_addr(acpi_res, &addr); if (!ACPI_SUCCESS(status)) @@ -140,6 +140,17 @@ setup_resource(struct acpi_resource *acpi_res, void *data) } else return AE_OK; + max_len = addr.maximum - addr.minimum + 1; + if (addr.address_length > max_len) { + dev_printk(KERN_DEBUG, &info->bridge->dev, + "host bridge window length %#llx doesn't fit in " + "%#llx-%#llx, trimming\n", + (unsigned long long) addr.address_length, + (unsigned long long) addr.minimum, + (unsigned long long) addr.maximum); + addr.address_length = max_len; + } + start = addr.minimum + addr.translation_offset; end = start + addr.address_length - 1; From bcbe53682f65330bdd9ad7eed9575d2ff536353a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 22 Mar 2010 19:59:47 -0700 Subject: [PATCH 316/478] via-velocity: Fix FLOW_CNTL_TX_RX handling in set_mii_flow_control() Clear, don't set, ANAR_ASMDIR in this case. Noticed by Roel Kluin. Signed-off-by: David S. Miller --- drivers/net/via-velocity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 3a486f3bad3..bc278d4ee89 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -812,7 +812,7 @@ static void set_mii_flow_control(struct velocity_info *vptr) case FLOW_CNTL_TX_RX: MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); break; case FLOW_CNTL_DISABLE: From 93b39a0dba6a15c35a582b9e8b171b8a6ec971aa Mon Sep 17 00:00:00 2001 From: Henne Date: Thu, 25 Mar 2010 12:05:29 +0000 Subject: [PATCH 317/478] isdn: Cleanup Sections in PCMCIA driver sedlbauer Compiling this driver gave a section mismatch, so I reviewed the init/exit paths of the driver and made the correct changes. WARNING: drivers/isdn/hisax/built-in.o(.text+0x558d6): Section mismatch in reference from the function sedlbauer_config() to the function .devinit.text:hisax_init_pcmcia() The function sedlbauer_config() references the function __devinit hisax_init_pcmcia(). This is often because sedlbauer_config lacks a __devinit annotation or the annotation of hisax_init_pcmcia is wrong. Signed-off-by: Henrik Kretzschmar Acked-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hisax/sedlbauer_cs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 7836ec3c7f8..71b3ddef03b 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -76,7 +76,7 @@ module_param(protocol, int, 0); event handler. */ -static int sedlbauer_config(struct pcmcia_device *link); +static int sedlbauer_config(struct pcmcia_device *link) __devinit ; static void sedlbauer_release(struct pcmcia_device *link); /* @@ -85,7 +85,7 @@ static void sedlbauer_release(struct pcmcia_device *link); needed to manage one actual PCMCIA card. */ -static void sedlbauer_detach(struct pcmcia_device *p_dev); +static void sedlbauer_detach(struct pcmcia_device *p_dev) __devexit; /* You'll also need to prototype all the functions that will actually @@ -129,7 +129,7 @@ typedef struct local_info_t { ======================================================================*/ -static int sedlbauer_probe(struct pcmcia_device *link) +static int __devinit sedlbauer_probe(struct pcmcia_device *link) { local_info_t *local; @@ -177,7 +177,7 @@ static int sedlbauer_probe(struct pcmcia_device *link) ======================================================================*/ -static void sedlbauer_detach(struct pcmcia_device *link) +static void __devexit sedlbauer_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "sedlbauer_detach(0x%p)\n", link); @@ -283,7 +283,7 @@ static int sedlbauer_config_check(struct pcmcia_device *p_dev, -static int sedlbauer_config(struct pcmcia_device *link) +static int __devinit sedlbauer_config(struct pcmcia_device *link) { local_info_t *dev = link->priv; win_req_t *req; @@ -441,7 +441,7 @@ static struct pcmcia_driver sedlbauer_driver = { .name = "sedlbauer_cs", }, .probe = sedlbauer_probe, - .remove = sedlbauer_detach, + .remove = __devexit_p(sedlbauer_detach), .id_table = sedlbauer_ids, .suspend = sedlbauer_suspend, .resume = sedlbauer_resume, From 158e33d1c6d0c6bacf577bcb47591aa4293dfcb1 Mon Sep 17 00:00:00 2001 From: Henne Date: Thu, 25 Mar 2010 12:05:30 +0000 Subject: [PATCH 318/478] isdn: Cleanup Sections in PCMCIA driver teles Compiling this driver gave a section mismatch, so I reviewed the init/exit paths of the driver and made the correct changes. WARNING: drivers/isdn/hisax/built-in.o(.text+0x56bfb): Section mismatch in reference from the function teles_cs_config() to the function .devinit.text:hisax_init_pcmcia() The function teles_cs_config() references the function __devinit hisax_init_pcmcia(). This is often because teles_cs_config lacks a __devinit annotation or the annotation of hisax_init_pcmcia is wrong. Signed-off-by: Henrik Kretzschmar Acked-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hisax/teles_cs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index b0c5976cbdb..d010a0da8e1 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -57,7 +57,7 @@ module_param(protocol, int, 0); handler. */ -static int teles_cs_config(struct pcmcia_device *link); +static int teles_cs_config(struct pcmcia_device *link) __devinit ; static void teles_cs_release(struct pcmcia_device *link); /* @@ -66,7 +66,7 @@ static void teles_cs_release(struct pcmcia_device *link); needed to manage one actual PCMCIA card. */ -static void teles_detach(struct pcmcia_device *p_dev); +static void teles_detach(struct pcmcia_device *p_dev) __devexit ; /* A linked list of "instances" of the teles_cs device. Each actual @@ -112,7 +112,7 @@ typedef struct local_info_t { ======================================================================*/ -static int teles_probe(struct pcmcia_device *link) +static int __devinit teles_probe(struct pcmcia_device *link) { local_info_t *local; @@ -156,7 +156,7 @@ static int teles_probe(struct pcmcia_device *link) ======================================================================*/ -static void teles_detach(struct pcmcia_device *link) +static void __devexit teles_detach(struct pcmcia_device *link) { local_info_t *info = link->priv; @@ -200,7 +200,7 @@ static int teles_cs_configcheck(struct pcmcia_device *p_dev, return -ENODEV; } -static int teles_cs_config(struct pcmcia_device *link) +static int __devinit teles_cs_config(struct pcmcia_device *link) { local_info_t *dev; int i; @@ -319,7 +319,7 @@ static struct pcmcia_driver teles_cs_driver = { .name = "teles_cs", }, .probe = teles_probe, - .remove = teles_detach, + .remove = __devexit_p(teles_detach), .id_table = teles_ids, .suspend = teles_suspend, .resume = teles_resume, From a465870a808bccba63bf6da30a0b56a2a7abfa5c Mon Sep 17 00:00:00 2001 From: Henne Date: Thu, 25 Mar 2010 12:05:31 +0000 Subject: [PATCH 319/478] isdn: Cleanup Sections in PCMCIA driver avma1 Compiling this driver gave a section mismatch, so I reviewed the init/exit paths of the driver and made the correct changes. WARNING: drivers/isdn/hisax/built-in.o(.text+0x56512): Section mismatch in reference from the function avma1cs_config() to the function .devinit.text:hisax_init_pcmcia() The function avma1cs_config() references the function __devinit hisax_init_pcmcia(). This is often because avma1cs_config lacks a __devinit annotation or the annotation of hisax_init_pcmcia is wrong. Signed-off-by: Henrik Kretzschmar Acked-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hisax/avma1_cs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index e5deb15cf40..8d1d63a02b3 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -50,7 +50,7 @@ module_param(isdnprot, int, 0); handler. */ -static int avma1cs_config(struct pcmcia_device *link); +static int avma1cs_config(struct pcmcia_device *link) __devinit ; static void avma1cs_release(struct pcmcia_device *link); /* @@ -59,7 +59,7 @@ static void avma1cs_release(struct pcmcia_device *link); needed to manage one actual PCMCIA card. */ -static void avma1cs_detach(struct pcmcia_device *p_dev); +static void avma1cs_detach(struct pcmcia_device *p_dev) __devexit ; /* @@ -99,7 +99,7 @@ typedef struct local_info_t { ======================================================================*/ -static int avma1cs_probe(struct pcmcia_device *p_dev) +static int __devinit avma1cs_probe(struct pcmcia_device *p_dev) { local_info_t *local; @@ -140,7 +140,7 @@ static int avma1cs_probe(struct pcmcia_device *p_dev) ======================================================================*/ -static void avma1cs_detach(struct pcmcia_device *link) +static void __devexit avma1cs_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link); avma1cs_release(link); @@ -174,7 +174,7 @@ static int avma1cs_configcheck(struct pcmcia_device *p_dev, } -static int avma1cs_config(struct pcmcia_device *link) +static int __devinit avma1cs_config(struct pcmcia_device *link) { local_info_t *dev; int i; @@ -282,7 +282,7 @@ static struct pcmcia_driver avma1cs_driver = { .name = "avma1_cs", }, .probe = avma1cs_probe, - .remove = avma1cs_detach, + .remove = __devexit_p(avma1cs_detach), .id_table = avma1cs_ids, }; From f61bb62e3ed7634fe5b7dfd8c9a52e6b799f4023 Mon Sep 17 00:00:00 2001 From: Henne Date: Thu, 25 Mar 2010 12:05:32 +0000 Subject: [PATCH 320/478] isdn: Cleanup Sections in PCMCIA driver elsa Compiling this driver gave a section mismatch, so I reviewed the init/exit paths of the driver and made the correct changes. WARNING: drivers/isdn/hisax/built-in.o(.text+0x55e37): Section mismatch in reference from the function elsa_cs_config() to the function .devinit.text:hisax_init_pcmcia() The function elsa_cs_config() references the function __devinit hisax_init_pcmcia(). This is often because elsa_cs_config lacks a __devinit annotation or the annotation of hisax_init_pcmcia is wrong. Signed-off-by: Henrik Kretzschmar Acked-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hisax/elsa_cs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index c9a30b1c923..c9f2279e21f 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -76,7 +76,7 @@ module_param(protocol, int, 0); handler. */ -static int elsa_cs_config(struct pcmcia_device *link); +static int elsa_cs_config(struct pcmcia_device *link) __devinit ; static void elsa_cs_release(struct pcmcia_device *link); /* @@ -85,7 +85,7 @@ static void elsa_cs_release(struct pcmcia_device *link); needed to manage one actual PCMCIA card. */ -static void elsa_cs_detach(struct pcmcia_device *p_dev); +static void elsa_cs_detach(struct pcmcia_device *p_dev) __devexit; /* A driver needs to provide a dev_node_t structure for each device @@ -121,7 +121,7 @@ typedef struct local_info_t { ======================================================================*/ -static int elsa_cs_probe(struct pcmcia_device *link) +static int __devinit elsa_cs_probe(struct pcmcia_device *link) { local_info_t *local; @@ -166,7 +166,7 @@ static int elsa_cs_probe(struct pcmcia_device *link) ======================================================================*/ -static void elsa_cs_detach(struct pcmcia_device *link) +static void __devexit elsa_cs_detach(struct pcmcia_device *link) { local_info_t *info = link->priv; @@ -210,7 +210,7 @@ static int elsa_cs_configcheck(struct pcmcia_device *p_dev, return -ENODEV; } -static int elsa_cs_config(struct pcmcia_device *link) +static int __devinit elsa_cs_config(struct pcmcia_device *link) { local_info_t *dev; int i; @@ -327,7 +327,7 @@ static struct pcmcia_driver elsa_cs_driver = { .name = "elsa_cs", }, .probe = elsa_cs_probe, - .remove = elsa_cs_detach, + .remove = __devexit_p(elsa_cs_detach), .id_table = elsa_ids, .suspend = elsa_suspend, .resume = elsa_resume, From 7c9f757319ccf7a47ce167b86eda671c87b5b917 Mon Sep 17 00:00:00 2001 From: Jon Maloy Date: Thu, 25 Mar 2010 12:40:09 -0700 Subject: [PATCH 321/478] TIPC: Removed inactive maintainer Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 449d4440208..5c99bd6cc2c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5423,7 +5423,6 @@ S: Maintained F: sound/soc/codecs/twl4030* TIPC NETWORK LAYER -M: Per Liden M: Jon Maloy M: Allan Stephens L: tipc-discussion@lists.sourceforge.net From 7561e8ca0dfaf6fca3feef982830de3b65300e5b Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 25 Mar 2010 16:48:38 +0000 Subject: [PATCH 322/478] NOMMU: Revert 'nommu: get_user_pages(): pin last page on non-page-aligned start' Revert the following patch: commit c08c6e1f54c85fc299cf9f88cf330d6dd28a9a1d Author: Steven J. Magnani Date: Fri Mar 5 13:42:24 2010 -0800 nommu: get_user_pages(): pin last page on non-page-aligned start As it assumes that the mappings begin at the start of pages - something that isn't necessarily true on NOMMU systems. On NOMMU systems, it is possible for a mapping to only occupy part of the page, and not necessarily touch either end of it; in fact it's also possible for multiple non-overlapping mappings to coexist on one page (consider direct mappings of ROMFS files, for example). Signed-off-by: David Howells Acked-by: Steven J. Magnani Signed-off-by: Linus Torvalds --- mm/nommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/nommu.c b/mm/nommu.c index e4b8f4d28a3..089982f5a4c 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -146,7 +146,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE); for (i = 0; i < nr_pages; i++) { - vma = find_extend_vma(mm, start); + vma = find_vma(mm, start); if (!vma) goto finish_or_fault; @@ -764,7 +764,7 @@ EXPORT_SYMBOL(find_vma); */ struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr) { - return find_vma(mm, addr & PAGE_MASK); + return find_vma(mm, addr); } /* From e1ee65d85904c5dd4b9cea1b15d5e85e20eae8a1 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 25 Mar 2010 16:48:44 +0000 Subject: [PATCH 323/478] NOMMU: Fix __get_user_pages() to pin last page on offset buffers Fix __get_user_pages() to make it pin the last page on a buffer that doesn't begin at the start of a page, but is a multiple of PAGE_SIZE in size. The problem is that __get_user_pages() advances the pointer too much when it iterates to the next page if the page it's currently looking at isn't used from the first byte. This can cause the end of a short VMA to be reached prematurely, resulting in the last page being lost. Signed-off-by: Steven J. Magnani Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- mm/nommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/nommu.c b/mm/nommu.c index 089982f5a4c..63fa17d121f 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -162,7 +162,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, } if (vmas) vmas[i] = vma; - start += PAGE_SIZE; + start = (start + PAGE_SIZE) & PAGE_MASK; } return i; From 3da0ae6298fa10d4f5e2855ae400b2470bc6693d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 25 Mar 2010 20:32:39 -0700 Subject: [PATCH 324/478] isdn: Add netdev to lists in MAINTAINERS entry. Signed-off-by: David S. Miller --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5c99bd6cc2c..9ff6341e43b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3083,6 +3083,7 @@ F: include/scsi/*iscsi* ISDN SUBSYSTEM M: Karsten Keil L: isdn4linux@listserv.isdn4linux.de (subscribers-only) +L: netdev@vger.kernel.org W: http://www.isdn4linux.de T: git git://git.kernel.org/pub/scm/linux/kernel/git/kkeil/isdn-2.6.git S: Maintained From e1f7f02b45cf33a774d56e505ce1718af9392f5e Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Thu, 25 Mar 2010 22:38:15 -0700 Subject: [PATCH 325/478] ALSA: ac97: Add IBM ThinkPad R40e to Headphone/Line Jack Sense blacklist BugLink: https://launchpad.net/bugs/303789 This model needs both 'Headphone Jack Sense' and 'Line Jack Sense' muted for audible audio, so just add its SSID to the blacklist and don't enumerate the controls. Signed-off-by: Daniel T Chen Cc: Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 1caf5e3c1f6..1a59b71c543 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1852,6 +1852,7 @@ static unsigned int ad1981_jacks_blacklist[] = { 0x10140523, /* Thinkpad R40 */ 0x10140534, /* Thinkpad X31 */ 0x10140537, /* Thinkpad T41p */ + 0x1014053e, /* Thinkpad R40e */ 0x10140554, /* Thinkpad T42p/R50p */ 0x10140567, /* Thinkpad T43p 2668-G7U */ 0x10140581, /* Thinkpad X41-2527 */ From 0f17014b340b98465fcf0de4c0d6c84a002ec53b Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 26 Mar 2010 16:07:25 +0200 Subject: [PATCH 326/478] ALSA: pcm_lib - fix xrun functionality The commit 4d96eb255c53ab5e39b37fd4d484ea3dc39ab456 broke the interrupt time xrun functionality (stream stop etc.) if the CONFIG_SND_PCM_XRUN_DEBUG is not set. This is because the xrun() is null defined without it. Fix this by letting the function xrun() to be always defined as it was before. Signed-off-by: Jarkko Nikula Cc: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b546ac2660f..a2ff86189d2 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -148,6 +148,9 @@ static void pcm_debug_name(struct snd_pcm_substream *substream, #define xrun_debug(substream, mask) \ ((substream)->pstr->xrun_debug & (mask)) +#else +#define xrun_debug(substream, mask) 0 +#endif #define dump_stack_on_xrun(substream) do { \ if (xrun_debug(substream, XRUN_DEBUG_STACK)) \ @@ -169,6 +172,7 @@ static void xrun(struct snd_pcm_substream *substream) } } +#ifdef CONFIG_SND_PCM_XRUN_DEBUG #define hw_ptr_error(substream, fmt, args...) \ do { \ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ @@ -255,8 +259,6 @@ static void xrun_log_show(struct snd_pcm_substream *substream) #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ -#define xrun_debug(substream, mask) 0 -#define xrun(substream) do { } while (0) #define hw_ptr_error(substream, fmt, args...) do { } while (0) #define xrun_log(substream, pos) do { } while (0) #define xrun_log_show(substream) do { } while (0) From 3e297b613491f0d4928aa652a2cd266aa06dc409 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 26 Mar 2010 12:40:13 -0400 Subject: [PATCH 327/478] Restore LOOKUP_DIRECTORY hint handling in final lookup on open() Lose want_dir argument, while we are at it - since now nd->flags & LOOKUP_DIRECTORY is equivalent to it. Signed-off-by: Al Viro --- fs/namei.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 1c0fca6e899..a7dce91a7e4 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1610,8 +1610,7 @@ exit: static struct file *do_last(struct nameidata *nd, struct path *path, int open_flag, int acc_mode, - int mode, const char *pathname, - int *want_dir) + int mode, const char *pathname) { struct dentry *dir = nd->path.dentry; struct file *filp; @@ -1642,7 +1641,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, if (nd->last.name[nd->last.len]) { if (open_flag & O_CREAT) goto exit; - *want_dir = 1; + nd->flags |= LOOKUP_DIRECTORY; } /* just plain open? */ @@ -1656,8 +1655,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, if (path->dentry->d_inode->i_op->follow_link) return NULL; error = -ENOTDIR; - if (*want_dir && !path->dentry->d_inode->i_op->lookup) - goto exit_dput; + if (nd->flags & LOOKUP_DIRECTORY) { + if (!path->dentry->d_inode->i_op->lookup) + goto exit_dput; + } path_to_nameidata(path, nd); audit_inode(pathname, nd->path.dentry); goto ok; @@ -1766,7 +1767,6 @@ struct file *do_filp_open(int dfd, const char *pathname, int count = 0; int flag = open_to_namei_flags(open_flag); int force_reval = 0; - int want_dir = open_flag & O_DIRECTORY; if (!(open_flag & O_CREAT)) mode = 0; @@ -1828,7 +1828,9 @@ reval: if (open_flag & O_EXCL) nd.flags |= LOOKUP_EXCL; } - filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname, &want_dir); + if (open_flag & O_DIRECTORY) + nd.flags |= LOOKUP_DIRECTORY; + filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); while (unlikely(!filp)) { /* trailing symlink */ struct path holder; struct inode *inode = path.dentry->d_inode; @@ -1866,7 +1868,7 @@ reval: } holder = path; nd.flags &= ~LOOKUP_PARENT; - filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname, &want_dir); + filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); if (inode->i_op->put_link) inode->i_op->put_link(holder.dentry, &nd, cookie); path_put(&holder); From 4300e8c7f64d95a80ffa7d98d98738f41546bc30 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 26 Mar 2010 10:23:30 -0700 Subject: [PATCH 328/478] Revert "r8169: enable 64-bit DMA by default for PCI Express devices (v2)" This reverts commit 353176888386d9025062a12dcec08d49af10cf2c. People are reporting problems due to this change and there is no anticipation that the cause will be tracked down any time soon. We can try next time to selectively re-enable this based upon chip type, or have a black list of some sort. Signed-off-by: David S. Miller --- drivers/net/r8169.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 9d3ebf3e975..b93fd23b9f0 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -187,7 +187,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = { MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); static int rx_copybreak = 200; -static int use_dac = -1; +static int use_dac; static struct { u32 msg_enable; } debug = { -1 }; @@ -511,8 +511,7 @@ MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); module_param(rx_copybreak, int, 0); MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); module_param(use_dac, int, 0); -MODULE_PARM_DESC(use_dac, "Enable PCI DAC. -1 defaults on for PCI Express only." -" Unsafe on 32 bit PCI slot."); +MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); module_param_named(debug, debug.msg_enable, int, 0); MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); MODULE_LICENSE("GPL"); @@ -2974,7 +2973,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *ioaddr; unsigned int i; int rc; - int this_use_dac = use_dac; if (netif_msg_drv(&debug)) { printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n", @@ -3040,17 +3038,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->cp_cmd = PCIMulRW | RxChkSum; - tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); - if (!tp->pcie_cap) - netif_info(tp, probe, dev, "no PCI Express capability\n"); - - if (this_use_dac < 0) - this_use_dac = tp->pcie_cap != 0; - if ((sizeof(dma_addr_t) > 4) && - this_use_dac && - !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - netif_info(tp, probe, dev, "using 64-bit DMA\n"); + !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) { tp->cp_cmd |= PCIDAC; dev->features |= NETIF_F_HIGHDMA; } else { @@ -3069,6 +3058,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_res_4; } + tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (!tp->pcie_cap) + netif_info(tp, probe, dev, "no PCI Express capability\n"); + RTL_W16(IntrMask, 0x0000); /* Soft reset the chip. */ From bb2792e0383793d5135ba777e93f0a918371394b Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Fri, 26 Mar 2010 00:30:07 +0000 Subject: [PATCH 329/478] netxen: fix bios version calculation Bios sub version from unified fw image is calculated incorrect. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 1c63610ead4..7eb925a9f36 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -761,7 +761,7 @@ nx_get_bios_version(struct netxen_adapter *adapter) if (adapter->fw_type == NX_UNIFIED_ROMIMAGE) { bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off]) + NX_UNI_BIOS_VERSION_OFF)); - return (bios_ver << 24) + ((bios_ver >> 8) & 0xff00) + + return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24); } else return cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]); From 77c553900c58c3e4f475e233ad4ff6aeb282deb4 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Fri, 26 Mar 2010 00:30:08 +0000 Subject: [PATCH 330/478] netxen: fix warning in ioaddr for NX3031 chip Signed-off-by: Amit Kumar Salecha crb_intr_mask/crb_sts_consumer is predefined for NX2031 not for NX3031. For NX3031, these values get defined in rx context creation. Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_ctx.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 2a8ef5fc966..f26e54716c8 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -669,13 +669,15 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) } sds_ring->desc_head = (struct status_desc *)addr; - sds_ring->crb_sts_consumer = - netxen_get_ioaddr(adapter, - recv_crb_registers[port].crb_sts_consumer[ring]); + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + sds_ring->crb_sts_consumer = + netxen_get_ioaddr(adapter, + recv_crb_registers[port].crb_sts_consumer[ring]); - sds_ring->crb_intr_mask = - netxen_get_ioaddr(adapter, - recv_crb_registers[port].sw_int_mask[ring]); + sds_ring->crb_intr_mask = + netxen_get_ioaddr(adapter, + recv_crb_registers[port].sw_int_mask[ring]); + } } From afbe5cd6c40e0f20fa8832d17fa44ae605591ce1 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Fri, 26 Mar 2010 00:30:09 +0000 Subject: [PATCH 331/478] netxen: added sanity check for pci map Signed-off-by: Amit Kumar Salecha Return value of ioremap is not checked, NULL check added. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 45 +++++++++++++++++----------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 9a7a0f3c36c..01808b28d1b 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -604,16 +604,14 @@ netxen_cleanup_pci_map(struct netxen_adapter *adapter) static int netxen_setup_pci_map(struct netxen_adapter *adapter) { - void __iomem *mem_ptr0 = NULL; - void __iomem *mem_ptr1 = NULL; - void __iomem *mem_ptr2 = NULL; void __iomem *db_ptr = NULL; resource_size_t mem_base, db_base; - unsigned long mem_len, db_len = 0, pci_len0 = 0; + unsigned long mem_len, db_len = 0; struct pci_dev *pdev = adapter->pdev; int pci_func = adapter->ahw.pci_func; + struct netxen_hardware_context *ahw = &adapter->ahw; int err = 0; @@ -630,24 +628,40 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) /* 128 Meg of memory */ if (mem_len == NETXEN_PCI_128MB_SIZE) { - mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); - mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START, + + ahw->pci_base0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); + ahw->pci_base1 = ioremap(mem_base + SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_SIZE); - mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START, + ahw->pci_base2 = ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); - pci_len0 = FIRST_PAGE_GROUP_SIZE; + if (ahw->pci_base0 == NULL || ahw->pci_base1 == NULL || + ahw->pci_base2 == NULL) { + dev_err(&pdev->dev, "failed to map PCI bar 0\n"); + err = -EIO; + goto err_out; + } + + ahw->pci_len0 = FIRST_PAGE_GROUP_SIZE; + } else if (mem_len == NETXEN_PCI_32MB_SIZE) { - mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE); - mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - + + ahw->pci_base1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE); + ahw->pci_base2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); + if (ahw->pci_base1 == NULL || ahw->pci_base2 == NULL) { + dev_err(&pdev->dev, "failed to map PCI bar 0\n"); + err = -EIO; + goto err_out; + } + } else if (mem_len == NETXEN_PCI_2MB_SIZE) { - mem_ptr0 = pci_ioremap_bar(pdev, 0); - if (mem_ptr0 == NULL) { + ahw->pci_base0 = pci_ioremap_bar(pdev, 0); + if (ahw->pci_base0 == NULL) { dev_err(&pdev->dev, "failed to map PCI bar 0\n"); return -EIO; } - pci_len0 = mem_len; + ahw->pci_len0 = mem_len; } else { return -EIO; } @@ -656,11 +670,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); - adapter->ahw.pci_base0 = mem_ptr0; - adapter->ahw.pci_len0 = pci_len0; - adapter->ahw.pci_base1 = mem_ptr1; - adapter->ahw.pci_base2 = mem_ptr2; - if (NX_IS_REVISION_P3P(adapter->ahw.revision_id)) { adapter->ahw.ocm_win_crb = netxen_get_ioaddr(adapter, NETXEN_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func))); From 48c11a59c4c1d9926be34920d45da037516eb7b8 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Fri, 26 Mar 2010 00:30:10 +0000 Subject: [PATCH 332/478] netxen: update version to 4.0.73 Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 144d2e88042..0f703838e21 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -53,8 +53,8 @@ #define _NETXEN_NIC_LINUX_MAJOR 4 #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 72 -#define NETXEN_NIC_LINUX_VERSIONID "4.0.72" +#define _NETXEN_NIC_LINUX_SUBVERSION 73 +#define NETXEN_NIC_LINUX_VERSIONID "4.0.73" #define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define _major(v) (((v) >> 24) & 0xff) From 65deeed7b34bc5b8d3cbff495e8fa2ae7b563480 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Wed, 24 Mar 2010 09:35:42 +0000 Subject: [PATCH 333/478] ixgbevf: Fix signed/unsigned int error In the Tx mapping function if a DMA error occurred then the unwind of previously mapped sections would improperly check an unsigned int if it was less than zero. Changed the index variable to signed to avoid the error. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/ixgbevf_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index d6cbd943a6f..1bbbef3ee3f 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -2943,9 +2943,10 @@ static int ixgbevf_tx_map(struct ixgbevf_adapter *adapter, struct ixgbevf_tx_buffer *tx_buffer_info; unsigned int len; unsigned int total = skb->len; - unsigned int offset = 0, size, count = 0, i; + unsigned int offset = 0, size, count = 0; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; unsigned int f; + int i; i = tx_ring->next_to_use; From 5809a1ae77721931ca7bd7aeacb37fdabe6f07c0 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Wed, 24 Mar 2010 09:36:08 +0000 Subject: [PATCH 334/478] ixgbe: In SR-IOV mode insert delay before bring the adapter up VFs running in guest VMs do not respond in as timely a manner to PF indication it is going down as they do when running in the host domain. If the adapter is in SR-IOV mode insert a two second delay to guarantee that all VFs have had time to respond to the PF reset. In any case resetting the PF while VFs are active should be discouraged but if it must be done then there will be a two second delay to help synchronize resets among the PF and all the VFs. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d75c46ff31f..d2cda9e5963 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3056,6 +3056,14 @@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter) while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) msleep(1); ixgbe_down(adapter); + /* + * If SR-IOV enabled then wait a bit before bringing the adapter + * back up to give the VFs time to respond to the reset. The + * two second wait is based upon the watchdog timer cycle in + * the VF driver. + */ + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) + msleep(2000); ixgbe_up(adapter); clear_bit(__IXGBE_RESETTING, &adapter->state); } From 581d1aa777580c1c22169538ffb46676b13c408e Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Wed, 24 Mar 2010 09:36:27 +0000 Subject: [PATCH 335/478] ixgbe: Change where clear_to_send_flag is reset to zero. The clear_to_send flag is being cleared before the call to ping all the VFs. It should be called after pinging all the VFs. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d2cda9e5963..1066d53e102 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3244,13 +3244,15 @@ void ixgbe_down(struct ixgbe_adapter *adapter) /* disable receive for all VFs and wait one second */ if (adapter->num_vfs) { - for (i = 0 ; i < adapter->num_vfs; i++) - adapter->vfinfo[i].clear_to_send = 0; - /* ping all the active vfs to let them know we are going down */ ixgbe_ping_all_vfs(adapter); + /* Disable all VFTE/VFRE TX/RX */ ixgbe_disable_tx_rx(adapter); + + /* Mark all the VFs as inactive */ + for (i = 0 ; i < adapter->num_vfs; i++) + adapter->vfinfo[i].clear_to_send = 0; } /* disable receives */ From e0fce6950b822aba7840d82c2d2018f1e1b8276b Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Wed, 24 Mar 2010 10:01:45 +0000 Subject: [PATCH 336/478] ixgbe: cleanup maximum number of tx queues In the last patch I missed an unecessary min_t comparison. This patch removes it, the path allocates at most 72 tx queues for 82599 and 24 for 82598 there is no need for this check. Additionally this sets MAX_[TX|RX]_QUEUES to 72. Which is used as the size for the tx/rx_ring arrays. There is no reason to have more tx_rings/rx_rings then num_tx_queues. Signed-off-by: John Fastabend Signed-off-by: Jeff Kirsher Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 7 +++++-- drivers/net/ixgbe/ixgbe_main.c | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 19e94ee155a..79c35ae3718 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -204,14 +204,17 @@ enum ixgbe_ring_f_enum { #define IXGBE_MAX_FDIR_INDICES 64 #ifdef IXGBE_FCOE #define IXGBE_MAX_FCOE_INDICES 8 +#define MAX_RX_QUEUES (IXGBE_MAX_FDIR_INDICES + IXGBE_MAX_FCOE_INDICES) +#define MAX_TX_QUEUES (IXGBE_MAX_FDIR_INDICES + IXGBE_MAX_FCOE_INDICES) +#else +#define MAX_RX_QUEUES IXGBE_MAX_FDIR_INDICES +#define MAX_TX_QUEUES IXGBE_MAX_FDIR_INDICES #endif /* IXGBE_FCOE */ struct ixgbe_ring_feature { int indices; int mask; } ____cacheline_internodealigned_in_smp; -#define MAX_RX_QUEUES 128 -#define MAX_TX_QUEUES 128 #define MAX_RX_PACKET_BUFFERS ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) \ ? 8 : 1) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 1066d53e102..208fb4a9721 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -6061,7 +6061,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, indices += min_t(unsigned int, num_possible_cpus(), IXGBE_MAX_FCOE_INDICES); #endif - indices = min_t(unsigned int, indices, MAX_TX_QUEUES); netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), indices); if (!netdev) { err = -ENOMEM; From a7551b75fe47fb6fb70f679935845e741c5e0855 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Wed, 24 Mar 2010 10:02:04 +0000 Subject: [PATCH 337/478] ixgbe: Don't allow user buffer count to exceed 256 If the user buffer count was 256 the shift would place a 1 in the offset region leading to errors. It also overwrites the uers buffer list. This patch makes sure that at most 256 user buffers are allowed for DDP and the buffer count is masked properly such that it doesn't overwrite the offset when shifting the bits. Signed-off-by: Robert Love Signed-off-by: Yi Zou Signed-off-by: Frank Zhang Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_fcoe.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 700cfc0aa1b..e1978da49e5 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -202,6 +202,15 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, addr = sg_dma_address(sg); len = sg_dma_len(sg); while (len) { + /* max number of buffers allowed in one DDP context */ + if (j >= IXGBE_BUFFCNT_MAX) { + netif_err(adapter, drv, adapter->netdev, + "xid=%x:%d,%d,%d:addr=%llx " + "not enough descriptors\n", + xid, i, j, dmacount, (u64)addr); + goto out_noddp_free; + } + /* get the offset of length of current buffer */ thisoff = addr & ((dma_addr_t)bufflen - 1); thislen = min((bufflen - thisoff), len); @@ -227,20 +236,13 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, len -= thislen; addr += thislen; j++; - /* max number of buffers allowed in one DDP context */ - if (j > IXGBE_BUFFCNT_MAX) { - DPRINTK(DRV, ERR, "xid=%x:%d,%d,%d:addr=%llx " - "not enough descriptors\n", - xid, i, j, dmacount, (u64)addr); - goto out_noddp_free; - } } } /* only the last buffer may have non-full bufflen */ lastsize = thisoff + thislen; fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); - fcbuff |= (j << IXGBE_FCBUFF_BUFFCNT_SHIFT); + fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT); fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT); fcbuff |= (IXGBE_FCBUFF_VALID); From ca77cd59d28456b4061afa5254972ec47fa8baf5 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Wed, 24 Mar 2010 12:45:00 +0000 Subject: [PATCH 338/478] ixgbe: Priority tag FIP frames Currently FIP (FCoE Initialization Protocol) frames are going untagged. This causes various problems with FCFs (switches) that have negotiated a priority over dcbx. This patch tags FIP frames with the same priority as the FCoE frames. Signed-off-by: Robert Love Signed-off-by: Chris Leech Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 208fb4a9721..0c553f6cb53 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5648,7 +5648,8 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) #ifdef IXGBE_FCOE if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && - (skb->protocol == htons(ETH_P_FCOE))) { + ((skb->protocol == htons(ETH_P_FCOE)) || + (skb->protocol == htons(ETH_P_FIP)))) { txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1); txq += adapter->ring_feature[RING_F_FCOE].mask; return txq; @@ -5695,18 +5696,25 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, tx_ring = adapter->tx_ring[skb->queue_mapping]; - if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && - (skb->protocol == htons(ETH_P_FCOE))) { - tx_flags |= IXGBE_TX_FLAGS_FCOE; #ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { #ifdef CONFIG_IXGBE_DCB - tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK - << IXGBE_TX_FLAGS_VLAN_SHIFT); - tx_flags |= ((adapter->fcoe.up << 13) - << IXGBE_TX_FLAGS_VLAN_SHIFT); -#endif + /* for FCoE with DCB, we force the priority to what + * was specified by the switch */ + if ((skb->protocol == htons(ETH_P_FCOE)) || + (skb->protocol == htons(ETH_P_FIP))) { + tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK + << IXGBE_TX_FLAGS_VLAN_SHIFT); + tx_flags |= ((adapter->fcoe.up << 13) + << IXGBE_TX_FLAGS_VLAN_SHIFT); + } #endif + /* flag for FCoE offloads */ + if (skb->protocol == htons(ETH_P_FCOE)) + tx_flags |= IXGBE_TX_FLAGS_FCOE; } +#endif + /* four things can cause us to need a context descriptor */ if (skb_is_gso(skb) || (skb->ip_summed == CHECKSUM_PARTIAL) || From af06393bbde6e8d474622a0517cffc662676e3fe Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Wed, 24 Mar 2010 12:45:21 +0000 Subject: [PATCH 339/478] ixgbe: filter FIP frames into the FCoE offload queues During FCF solicitation, the switch is supposed to pad the solicited advertisement out to the endpoints specified maximum FCoE frame size. That means that we need to receive FIP frames that are larger than the standard MTU. To make sure the receive queue is configured correctly, we should be filtering FIP traffic into the FCoE queues. Signed-off-by: Chris Leech Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_fcoe.c | 15 +++++++++++++++ drivers/net/ixgbe/ixgbe_type.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index e1978da49e5..9276d5965b0 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -522,6 +522,9 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) /* Enable L2 eth type filter for FCoE */ IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), (ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN)); + /* Enable L2 eth type filter for FIP */ + IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FIP), + (ETH_P_FIP | IXGBE_ETQF_FILTER_EN)); if (adapter->ring_feature[RING_F_FCOE].indices) { /* Use multiple rx queues for FCoE by redirection table */ for (i = 0; i < IXGBE_FCRETA_SIZE; i++) { @@ -532,6 +535,12 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) } IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA); IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), 0); + fcoe_i = f->mask; + fcoe_i &= IXGBE_FCRETA_ENTRY_MASK; + fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; + IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FIP), + IXGBE_ETQS_QUEUE_EN | + (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); } else { /* Use single rx queue for FCoE */ fcoe_i = f->mask; @@ -541,6 +550,12 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) IXGBE_ETQS_QUEUE_EN | (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); } + /* send FIP frames to the first FCoE queue */ + fcoe_i = f->mask; + fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; + IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FIP), + IXGBE_ETQS_QUEUE_EN | + (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, IXGBE_FCRXCTRL_FCOELLI | diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 0ed5ab37cc5..4ec6dc1a5b7 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1298,6 +1298,7 @@ #define IXGBE_ETQF_FILTER_BCN 1 #define IXGBE_ETQF_FILTER_FCOE 2 #define IXGBE_ETQF_FILTER_1588 3 +#define IXGBE_ETQF_FILTER_FIP 4 /* VLAN Control Bit Masks */ #define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */ #define IXGBE_VLNCTRL_CFI 0x10000000 /* bit 28 */ From a6d36d5689b1806a3365c909192e9f03a43a632b Mon Sep 17 00:00:00 2001 From: Ben Menchaca Date: Wed, 24 Mar 2010 05:05:02 +0000 Subject: [PATCH 340/478] gianfar: fix undo of reserve() Fix undo of reserve() before RX recycle gfar_new_skb reserve()s space in the SKB to align it. If an error occurs, and the skb needs to be returned to the RX recycle queue, the current code attempts to reset head, but did not reset tail. This patch remembers the alignment amount, and reverses the reserve() when needed. Signed-off-by: Ben Menchaca Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 5 +++-- drivers/net/gianfar.h | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index b6715553cf1..669de028d44 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -2393,6 +2393,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev) * as many bytes as needed to align the data properly */ skb_reserve(skb, alignamount); + GFAR_CB(skb)->alignamount = alignamount; return skb; } @@ -2533,13 +2534,13 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) newskb = skb; else if (skb) { /* - * We need to reset ->data to what it + * We need to un-reserve() the skb to what it * was before gfar_new_skb() re-aligned * it to an RXBUF_ALIGNMENT boundary * before we put the skb back on the * recycle list. */ - skb->data = skb->head + NET_SKB_PAD; + skb_reserve(skb, -GFAR_CB(skb)->alignamount); __skb_queue_head(&priv->rx_recycle, skb); } } else { diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 3d72dc43dca..17d25e71423 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -566,6 +566,12 @@ struct rxfcb { u16 vlctl; /* VLAN control word */ }; +struct gianfar_skb_cb { + int alignamount; +}; + +#define GFAR_CB(skb) ((struct gianfar_skb_cb *)((skb)->cb)) + struct rmon_mib { u32 tr64; /* 0x.680 - Transmit and Receive 64-byte Frame Counter */ From ac90a149361a331f697d5aa500bedcff22054669 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 27 Mar 2009 17:23:32 +0000 Subject: [PATCH 341/478] tulip: Fix null dereference in uli526x_rx_packet() Acked-by: Grant Grundler Signed-off-by: David S. Miller --- drivers/net/tulip/uli526x.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 0ab05af237e..90be57bad39 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -851,13 +851,15 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info if ( !(rdes0 & 0x8000) || ((db->cr6_data & CR6_PM) && (rxlen>6)) ) { + struct sk_buff *new_skb = NULL; + skb = rxptr->rx_skb_ptr; /* Good packet, send to upper layer */ /* Shorst packet used new SKB */ - if ( (rxlen < RX_COPY_SIZE) && - ( (skb = dev_alloc_skb(rxlen + 2) ) - != NULL) ) { + if ((rxlen < RX_COPY_SIZE) && + ((new_skb = dev_alloc_skb(rxlen + 2) != NULL))) { + skb = new_skb; /* size less than COPY_SIZE, allocate a rxlen SKB */ skb_reserve(skb, 2); /* 16byte align */ memcpy(skb_put(skb, rxlen), From 4b97efdf392563bf03b4917a0b5add2df65de39a Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 26 Mar 2010 20:27:49 -0700 Subject: [PATCH 342/478] net: fix netlink address dumping in IPv4/IPv6 When a dump is interrupted at the last device in a hash chain and then continued, "idx" won't get incremented past s_idx, so s_ip_idx is not reset when moving on to the next device. This means of all following devices only the last n - s_ip_idx addresses are dumped. Tested-by: Pawel Staszewski Signed-off-by: Patrick McHardy --- net/ipv4/devinet.c | 2 +- net/ipv6/addrconf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 51ca946e339..3feb2b39030 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1194,7 +1194,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) hlist_for_each_entry_rcu(dev, node, head, index_hlist) { if (idx < s_idx) goto cont; - if (idx > s_idx) + if (h > s_h || idx > s_idx) s_ip_idx = 0; in_dev = __in_dev_get_rcu(dev); if (!in_dev) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3381b4317c2..7e567ae5eaa 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3610,7 +3610,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, hlist_for_each_entry_rcu(dev, node, head, index_hlist) { if (idx < s_idx) goto cont; - if (idx > s_idx) + if (h > s_h || idx > s_idx) s_ip_idx = 0; ip_idx = 0; if ((idev = __in6_dev_get(dev)) == NULL) From b35ecb5d404c00f2420221ccbb1bbba1139353a4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 24 Mar 2010 07:43:17 +0000 Subject: [PATCH 343/478] ipv4: Cleanup struct net dereference in rt_intern_hash There's no need in getting it 3 times and gcc isn't smart enough to understand this himself. This is just a cleanup before the fix (next patch). Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/route.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 54fd68c14c8..124af1605d1 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1212,11 +1212,11 @@ restart: slow_chain_length(rt_hash_table[hash].chain) > rt_chain_length_max) { struct net *net = dev_net(rt->u.dst.dev); int num = ++net->ipv4.current_rt_cache_rebuild_count; - if (!rt_caching(dev_net(rt->u.dst.dev))) { + if (!rt_caching(net)) { printk(KERN_WARNING "%s: %d rebuilds is over limit, route caching disabled\n", rt->u.dst.dev->name, num); } - rt_emergency_hash_rebuild(dev_net(rt->u.dst.dev)); + rt_emergency_hash_rebuild(net); } } From 6a2bad70d546cf30a46bc6d9ec0cb9a0891a38eb Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 24 Mar 2010 21:51:22 +0000 Subject: [PATCH 344/478] ipv4: Restart rt_intern_hash after emergency rebuild (v2) The the rebuild changes the genid which in turn is used at the hash calculation. Thus if we don't restart and go on with inserting the rt will happen in wrong chain. (Fixed Neil's comment about the index passed into the rt_intern_hash) Signed-off-by: Pavel Emelyanov Reviewed-by: Neil Horman Signed-off-by: David S. Miller --- net/ipv4/route.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 124af1605d1..d413b57be9b 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1097,7 +1097,7 @@ static int slow_chain_length(const struct rtable *head) } static int rt_intern_hash(unsigned hash, struct rtable *rt, - struct rtable **rp, struct sk_buff *skb) + struct rtable **rp, struct sk_buff *skb, int ifindex) { struct rtable *rth, **rthp; unsigned long now; @@ -1217,6 +1217,11 @@ restart: rt->u.dst.dev->name, num); } rt_emergency_hash_rebuild(net); + spin_unlock_bh(rt_hash_lock_addr(hash)); + + hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src, + ifindex, rt_genid(net)); + goto restart; } } @@ -1477,7 +1482,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, &netevent); rt_del(hash, rth); - if (!rt_intern_hash(hash, rt, &rt, NULL)) + if (!rt_intern_hash(hash, rt, &rt, NULL, rt->fl.oif)) ip_rt_put(rt); goto do_next; } @@ -1931,7 +1936,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, in_dev_put(in_dev); hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); - return rt_intern_hash(hash, rth, NULL, skb); + return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex); e_nobufs: in_dev_put(in_dev); @@ -2098,7 +2103,7 @@ static int ip_mkroute_input(struct sk_buff *skb, /* put it into the cache */ hash = rt_hash(daddr, saddr, fl->iif, rt_genid(dev_net(rth->u.dst.dev))); - return rt_intern_hash(hash, rth, NULL, skb); + return rt_intern_hash(hash, rth, NULL, skb, fl->iif); } /* @@ -2255,7 +2260,7 @@ local_input: } rth->rt_type = res.type; hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); - err = rt_intern_hash(hash, rth, NULL, skb); + err = rt_intern_hash(hash, rth, NULL, skb, fl.iif); goto done; no_route: @@ -2502,7 +2507,7 @@ static int ip_mkroute_output(struct rtable **rp, if (err == 0) { hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, rt_genid(dev_net(dev_out))); - err = rt_intern_hash(hash, rth, rp, NULL); + err = rt_intern_hash(hash, rth, rp, NULL, oldflp->oif); } return err; From a08af745e4c711d22aeadc2adade36958fe03ce8 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 25 Mar 2010 12:11:48 +0000 Subject: [PATCH 345/478] igbvf: do not modify tx_queue_len on link speed change Previously the driver tweaked txqueuelen to avoid false Tx hang reports seen at half duplex. This had the effect of overriding user set values on link change/reset. Testing shows that adjusting only the timeout factor is sufficient to prevent Tx hang reports at half duplex. Based on e1000e patch by Franco Fichtner CC: Franco Fichtner Signed-off-by: Emil Tantilov Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igbvf/igbvf.h | 1 - drivers/net/igbvf/netdev.c | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/net/igbvf/igbvf.h b/drivers/net/igbvf/igbvf.h index a1774b29d22..debeee2dc71 100644 --- a/drivers/net/igbvf/igbvf.h +++ b/drivers/net/igbvf/igbvf.h @@ -198,7 +198,6 @@ struct igbvf_adapter { struct igbvf_ring *tx_ring /* One per active queue */ ____cacheline_aligned_in_smp; - unsigned long tx_queue_len; unsigned int restart_queue; u32 txd_cmd; diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index a77afd8a14b..b41037ed808 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -1304,8 +1304,6 @@ static void igbvf_configure_tx(struct igbvf_adapter *adapter) /* enable Report Status bit */ adapter->txd_cmd |= E1000_ADVTXD_DCMD_RS; - - adapter->tx_queue_len = adapter->netdev->tx_queue_len; } /** @@ -1524,7 +1522,6 @@ void igbvf_down(struct igbvf_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); - netdev->tx_queue_len = adapter->tx_queue_len; netif_carrier_off(netdev); /* record the stats before reset*/ @@ -1857,21 +1854,15 @@ static void igbvf_watchdog_task(struct work_struct *work) &adapter->link_duplex); igbvf_print_link_info(adapter); - /* - * tweak tx_queue_len according to speed/duplex - * and adjust the timeout factor - */ - netdev->tx_queue_len = adapter->tx_queue_len; + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { case SPEED_10: txb2b = 0; - netdev->tx_queue_len = 10; adapter->tx_timeout_factor = 16; break; case SPEED_100: txb2b = 0; - netdev->tx_queue_len = 100; /* maybe add some timeout factor ? */ break; } From f49c57e141c7f53353e4265a31dc2324e6215037 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 24 Mar 2010 12:55:02 +0000 Subject: [PATCH 346/478] e1000e: do not modify tx_queue_len on link speed change Previously the driver tweaked txqueuelen to avoid false Tx hang reports seen at half duplex. This had the effect of overriding user set values on link change/reset. Testing shows that adjusting only the timeout factor is sufficient to prevent Tx hang reports at half duplex. This patch removes all instances of tx_queue_len in the driver. Originally reported and patched by Franco Fichtner CC: Franco Fichtner Signed-off-by: Emil Tantilov Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/e1000.h | 1 - drivers/net/e1000e/netdev.c | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index c2ec095d216..118bdf48359 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -279,7 +279,6 @@ struct e1000_adapter { struct napi_struct napi; - unsigned long tx_queue_len; unsigned int restart_queue; u32 txd_cmd; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 88d54d3efce..e1cceb60657 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2289,8 +2289,6 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) ew32(TCTL, tctl); e1000e_config_collision_dist(hw); - - adapter->tx_queue_len = adapter->netdev->tx_queue_len; } /** @@ -2877,7 +2875,6 @@ void e1000e_down(struct e1000_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); - netdev->tx_queue_len = adapter->tx_queue_len; netif_carrier_off(netdev); adapter->link_speed = 0; adapter->link_duplex = 0; @@ -3588,21 +3585,15 @@ static void e1000_watchdog_task(struct work_struct *work) "link gets many collisions.\n"); } - /* - * tweak tx_queue_len according to speed/duplex - * and adjust the timeout factor - */ - netdev->tx_queue_len = adapter->tx_queue_len; + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { case SPEED_10: txb2b = 0; - netdev->tx_queue_len = 10; adapter->tx_timeout_factor = 16; break; case SPEED_100: txb2b = 0; - netdev->tx_queue_len = 100; adapter->tx_timeout_factor = 10; break; } From 49137f2efb5cf68724bccaba531ab3d59acd71f9 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Tue, 16 Mar 2010 21:46:15 +0100 Subject: [PATCH 347/478] Open segment file before using it logfs_recover_sb() needs it open. Signed-off-by: Joern Engel --- fs/logfs/super.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/logfs/super.c b/fs/logfs/super.c index c66beab78de..018728120bb 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -289,6 +289,10 @@ static int logfs_make_writeable(struct super_block *sb) { int err; + err = logfs_open_segfile(sb); + if (err) + return err; + /* Repair any broken superblock copies */ err = logfs_recover_sb(sb); if (err) @@ -299,10 +303,6 @@ static int logfs_make_writeable(struct super_block *sb) if (err) return err; - err = logfs_open_segfile(sb); - if (err) - return err; - /* Do one GC pass before any data gets dirtied */ logfs_gc_pass(sb); From 59fe27c0a8173a74b105debc803b97582028c90b Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Wed, 17 Mar 2010 13:47:45 +0100 Subject: [PATCH 348/478] Limit max_pages for insane devices Intel SSDs have a limit of 0xffff as queue_max_hw_sectors(q). Such a limit may make sense from a hardware pov, but it causes bio_alloc() to return NULL. Signed-off-by: Joern Engel --- fs/logfs/dev_bdev.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index 9718c22f186..f99f5dcce54 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -97,8 +97,10 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9); int i; + if (max_pages > BIO_MAX_PAGES) + max_pages = BIO_MAX_PAGES; bio = bio_alloc(GFP_NOFS, max_pages); - BUG_ON(!bio); /* FIXME: handle this */ + BUG_ON(!bio); for (i = 0; i < nr_pages; i++) { if (i >= max_pages) { @@ -191,8 +193,10 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9); int i; + if (max_pages > BIO_MAX_PAGES) + max_pages = BIO_MAX_PAGES; bio = bio_alloc(GFP_NOFS, max_pages); - BUG_ON(!bio); /* FIXME: handle this */ + BUG_ON(!bio); for (i = 0; i < nr_pages; i++) { if (i >= max_pages) { From e07bf553f37cd4fa470b499ff34d800956df2d48 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Wed, 17 Mar 2010 15:29:38 +0100 Subject: [PATCH 349/478] Plug memory leak in writeseg_end_io Signed-off-by: Joern Engel --- fs/logfs/dev_bdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index f99f5dcce54..a5d0c56d3eb 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -80,6 +80,7 @@ static void writeseg_end_io(struct bio *bio, int err) prefetchw(&bvec->bv_page->flags); end_page_writeback(page); + page_cache_release(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); if (atomic_dec_and_test(&super->s_pending_writes)) From e326068806ee044cc617b1dc24be1293fca3fbf6 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Wed, 17 Mar 2010 16:00:07 +0100 Subject: [PATCH 350/478] Prevent schedule while atomic in __logfs_readdir Apparently filldir can sleep, which forbids kmap_atomic. Signed-off-by: Joern Engel --- fs/logfs/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c index 56a8bfbb012..c76b4b5c7ff 100644 --- a/fs/logfs/dir.c +++ b/fs/logfs/dir.c @@ -303,12 +303,12 @@ static int __logfs_readdir(struct file *file, void *buf, filldir_t filldir) (filler_t *)logfs_readpage, NULL); if (IS_ERR(page)) return PTR_ERR(page); - dd = kmap_atomic(page, KM_USER0); + dd = kmap(page); BUG_ON(dd->namelen == 0); full = filldir(buf, (char *)dd->name, be16_to_cpu(dd->namelen), pos, be64_to_cpu(dd->ino), dd->type); - kunmap_atomic(dd, KM_USER0); + kunmap(page); page_cache_release(page); if (full) break; From faaa27ab919799929732c356a92a160f8657ecc6 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Fri, 26 Mar 2010 10:18:36 +0100 Subject: [PATCH 351/478] Write out both superblocks on mismatch If the first superblock is wrong and the second gets written, there will still be a mismatch on next mount. Write both to make sure they match. Signed-off-by: Joern Engel --- fs/logfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/logfs/super.c b/fs/logfs/super.c index 018728120bb..006670fe9e8 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -277,7 +277,7 @@ static int logfs_recover_sb(struct super_block *sb) } if (valid0 && valid1 && ds_cmp(ds0, ds1)) { printk(KERN_INFO"Superblocks don't match - fixing.\n"); - return write_one_sb(sb, super->s_devops->find_last_sb); + return logfs_write_sb(sb); } /* If neither is valid now, something's wrong. Didn't we properly * check them before?!? */ From 7db8064c17b92e95aec2e333096c035db9ddd4fe Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Fri, 26 Mar 2010 14:45:55 +0100 Subject: [PATCH 352/478] Fix logfs_get_sb_final error path rootdir was already allocated, so we must iput it again. Found by Al Viro. Signed-off-by: Joern Engel --- fs/logfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/logfs/super.c b/fs/logfs/super.c index 006670fe9e8..2845c41d70d 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -328,7 +328,7 @@ static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt) sb->s_root = d_alloc_root(rootdir); if (!sb->s_root) - goto fail; + goto fail2; super->s_erase_page = alloc_pages(GFP_KERNEL, 0); if (!super->s_erase_page) From 6f2e9e6a950a165a7d2c399ab7557e6745ef2bfd Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Fri, 26 Mar 2010 14:50:08 +0100 Subject: [PATCH 353/478] Use deactivate_locked_super Found by Al Viro. Signed-off-by: Joern Engel --- fs/logfs/super.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/logfs/super.c b/fs/logfs/super.c index 2845c41d70d..9d856c49afc 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -572,8 +572,7 @@ int logfs_get_sb_device(struct file_system_type *type, int flags, return 0; err1: - up_write(&sb->s_umount); - deactivate_super(sb); + deactivate_locked_super(sb); return err; err0: kfree(super); From e4afb29fa3ea759d408fa537ab6a81800708396e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 27 Mar 2010 07:55:58 -0700 Subject: [PATCH 354/478] Revert "via82cxxx: workaround h/w bugs" This reverts commit f931a5d5785d7b7c44871bd7ad2762e29dfddf29. It causes regressions for some users. Signed-off-by: David S. Miller --- drivers/ide/via82cxxx.c | 57 ----------------------------------------- 1 file changed, 57 deletions(-) diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index e65d010b708..48fd4efc90a 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -110,7 +110,6 @@ struct via82cxxx_dev { struct via_isa_bridge *via_config; unsigned int via_80w; - u8 cached_device[2]; }; /** @@ -403,66 +402,10 @@ static const struct ide_port_ops via_port_ops = { .cable_detect = via82cxxx_cable_detect, }; -static void via_write_devctl(ide_hwif_t *hwif, u8 ctl) -{ - struct via82cxxx_dev *vdev = hwif->host->host_priv; - - outb(ctl, hwif->io_ports.ctl_addr); - outb(vdev->cached_device[hwif->channel], hwif->io_ports.device_addr); -} - -static void __via_dev_select(ide_drive_t *drive, u8 select) -{ - ide_hwif_t *hwif = drive->hwif; - struct via82cxxx_dev *vdev = hwif->host->host_priv; - - outb(select, hwif->io_ports.device_addr); - vdev->cached_device[hwif->channel] = select; -} - -static void via_dev_select(ide_drive_t *drive) -{ - __via_dev_select(drive, drive->select | ATA_DEVICE_OBS); -} - -static void via_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - - if (valid & IDE_VALID_FEATURE) - outb(tf->feature, io_ports->feature_addr); - if (valid & IDE_VALID_NSECT) - outb(tf->nsect, io_ports->nsect_addr); - if (valid & IDE_VALID_LBAL) - outb(tf->lbal, io_ports->lbal_addr); - if (valid & IDE_VALID_LBAM) - outb(tf->lbam, io_ports->lbam_addr); - if (valid & IDE_VALID_LBAH) - outb(tf->lbah, io_ports->lbah_addr); - if (valid & IDE_VALID_DEVICE) - __via_dev_select(drive, tf->device); -} - -const struct ide_tp_ops via_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = via_write_devctl, - - .dev_select = via_dev_select, - .tf_load = via_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - static const struct ide_port_info via82cxxx_chipset __devinitdata = { .name = DRV_NAME, .init_chipset = init_chipset_via82cxxx, .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } }, - .tp_ops = &via_tp_ops, .port_ops = &via_port_ops, .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST | IDE_HFLAG_POST_SET_MODE | From 71c5c1595c04852d6fbf3c4882b47b30b61a4d32 Mon Sep 17 00:00:00 2001 From: Brandon L Black Date: Fri, 26 Mar 2010 16:18:03 +0000 Subject: [PATCH 355/478] net: Add MSG_WAITFORONE flag to recvmmsg Add new flag MSG_WAITFORONE for the recvmmsg() syscall. When this flag is specified for a blocking socket, recvmmsg() will only block until at least 1 packet is available. The default behavior is to block until all vlen packets are available. This flag has no effect on non-blocking sockets or when used in combination with MSG_DONTWAIT. Signed-off-by: Brandon L Black Acked-by: Ulrich Drepper Acked-by: Eric Dumazet Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/linux/socket.h | 1 + net/socket.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/linux/socket.h b/include/linux/socket.h index 7b3aae2052a..354cc5617f8 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -255,6 +255,7 @@ struct ucred { #define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */ #define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */ #define MSG_MORE 0x8000 /* Sender will send more */ +#define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */ #define MSG_EOF MSG_FIN diff --git a/net/socket.c b/net/socket.c index 769c386bd42..f55ffe9f8c8 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2135,6 +2135,10 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, break; ++datagrams; + /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ + if (flags & MSG_WAITFORONE) + flags |= MSG_DONTWAIT; + if (timeout) { ktime_get_ts(timeout); *timeout = timespec_sub(end_time, *timeout); From c0e4d4bad4e8cf0aa787a3045392f949d76b5886 Mon Sep 17 00:00:00 2001 From: wzt wzt Date: Thu, 25 Mar 2010 20:12:59 +0000 Subject: [PATCH 356/478] benet: Fix compile warnnings in drivers/net/benet/be_ethtool.c Fix the following warnings: be_ethtool.c:493: warning: integer constant is too large for 'long' type be_ethtool.c:493: warning: integer constant is too large for 'long' type Signed-off-by: Zhitong Wang Acked-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 9560d48944a..51e1065e789 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -490,7 +490,7 @@ be_test_ddr_dma(struct be_adapter *adapter) { int ret, i; struct be_dma_mem ddrdma_cmd; - u64 pattern[2] = {0x5a5a5a5a5a5a5a5a, 0xa5a5a5a5a5a5a5a5}; + u64 pattern[2] = {0x5a5a5a5a5a5a5a5aULL, 0xa5a5a5a5a5a5a5a5ULL}; ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test); ddrdma_cmd.va = pci_alloc_consistent(adapter->pdev, ddrdma_cmd.size, From e017b60316468f21a63bdd4affefaf81a7f988fd Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 25 Mar 2010 17:15:06 +0000 Subject: [PATCH 357/478] igb: use correct bits to identify if managability is enabled igb was previously checking the wrong bits in the MANC register to determine if managability was enabled. As a result it was incorrectly powering down and resetting the phy when it didn't need to. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 2a8a886b37e..be8d010e402 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -1367,7 +1367,8 @@ out: * igb_enable_mng_pass_thru - Enable processing of ARP's * @hw: pointer to the HW structure * - * Verifies the hardware needs to allow ARPs to be processed by the host. + * Verifies the hardware needs to leave interface enabled so that frames can + * be directed to and from the management interface. **/ bool igb_enable_mng_pass_thru(struct e1000_hw *hw) { @@ -1380,8 +1381,7 @@ bool igb_enable_mng_pass_thru(struct e1000_hw *hw) manc = rd32(E1000_MANC); - if (!(manc & E1000_MANC_RCV_TCO_EN) || - !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) + if (!(manc & E1000_MANC_RCV_TCO_EN)) goto out; if (hw->mac.arc_subsystem_valid) { From e7d481a6f3c13041446b7bb8f98ab861460076a3 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Thu, 25 Mar 2010 17:06:48 +0000 Subject: [PATCH 358/478] ixgbe: Do not run all Diagnostic offline tests when VFs are active When running the offline diagnostic tests check to see if any VFs are online. If so then only run the link test. This is necessary because the VFs running in guest VMs aren't aware of when the PF is taken offline for a diagnostic test. Also put a message to the system log telling the system administrator to take the VFs offline manually if (s)he wants to run a full diagnostic. Return 1 on each of the tests not run to alert the user of the condition. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_ethtool.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 7949a446e4c..1959ef76c96 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1853,6 +1853,26 @@ static void ixgbe_diag_test(struct net_device *netdev, if (ixgbe_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { + int i; + for (i = 0; i < adapter->num_vfs; i++) { + if (adapter->vfinfo[i].clear_to_send) { + netdev_warn(netdev, "%s", + "offline diagnostic is not " + "supported when VFs are " + "present\n"); + data[0] = 1; + data[1] = 1; + data[2] = 1; + data[3] = 1; + eth_test->flags |= ETH_TEST_FL_FAILED; + clear_bit(__IXGBE_TESTING, + &adapter->state); + goto skip_ol_tests; + } + } + } + if (if_running) /* indicate we're in test mode */ dev_close(netdev); @@ -1908,6 +1928,7 @@ skip_loopback: clear_bit(__IXGBE_TESTING, &adapter->state); } +skip_ol_tests: msleep_interruptible(4 * 1000); } From 7438189baa0a2fe30084bdc97e3d540ebc5444f3 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 25 Mar 2010 23:45:35 +0000 Subject: [PATCH 359/478] net: ipmr/ip6mr: prevent out-of-bounds vif_table access When cache is unresolved, c->mf[6]c_parent is set to 65535 and minvif, maxvif are not initialized, hence we must avoid to parse IIF and OIF. A second problem can happen when the user dumps a cache entry where a VIF, that was referenced at creation time, has been removed. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/ipv4/ipmr.c | 11 +++++++---- net/ipv6/ip6mr.c | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 0b9d03c54dc..d0a6092a67b 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1616,17 +1616,20 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm) int ct; struct rtnexthop *nhp; struct net *net = mfc_net(c); - struct net_device *dev = net->ipv4.vif_table[c->mfc_parent].dev; u8 *b = skb_tail_pointer(skb); struct rtattr *mp_head; - if (dev) - RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); + /* If cache is unresolved, don't try to parse IIF and OIF */ + if (c->mfc_parent > MAXVIFS) + return -ENOENT; + + if (VIF_EXISTS(net, c->mfc_parent)) + RTA_PUT(skb, RTA_IIF, 4, &net->ipv4.vif_table[c->mfc_parent].dev->ifindex); mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { - if (c->mfc_un.res.ttls[ct] < 255) { + if (VIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) { if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) goto rtattr_failure; nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 23e4ac0cc30..27acfb58650 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1695,17 +1695,20 @@ ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm) int ct; struct rtnexthop *nhp; struct net *net = mfc6_net(c); - struct net_device *dev = net->ipv6.vif6_table[c->mf6c_parent].dev; u8 *b = skb_tail_pointer(skb); struct rtattr *mp_head; - if (dev) - RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); + /* If cache is unresolved, don't try to parse IIF and OIF */ + if (c->mf6c_parent > MAXMIFS) + return -ENOENT; + + if (MIF_EXISTS(net, c->mf6c_parent)) + RTA_PUT(skb, RTA_IIF, 4, &net->ipv6.vif6_table[c->mf6c_parent].dev->ifindex); mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { - if (c->mfc_un.res.ttls[ct] < 255) { + if (MIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) { if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) goto rtattr_failure; nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); From 39ca5f033bb2ea18877632809185268eebbb37a9 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Fri, 26 Mar 2010 11:25:58 +0000 Subject: [PATCH 360/478] e1000: do not modify tx_queue_len on link speed change Previously the driver tweaked txqueuelen to avoid false Tx hang reports seen at half duplex. This had the effect of overriding user set values on link change/reset. Testing shows that adjusting only the timeout factor is sufficient to prevent Tx hang reports at half duplex. This patch removes all instances of tx_queue_len in the driver. Based on e1000e patch by Franco Fichtner CC: Franco Fichtner Signed-off-by: Emil Tantilov Acked-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000/e1000.h | 1 - drivers/net/e1000/e1000_main.c | 9 +-------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 9902b33b716..2f29c213185 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -261,7 +261,6 @@ struct e1000_adapter { /* TX */ struct e1000_tx_ring *tx_ring; /* One per active queue */ unsigned int restart_queue; - unsigned long tx_queue_len; u32 txd_cmd; u32 tx_int_delay; u32 tx_abs_int_delay; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 8be6faee43e..b15ece26ed8 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -383,8 +383,6 @@ static void e1000_configure(struct e1000_adapter *adapter) adapter->alloc_rx_buf(adapter, ring, E1000_DESC_UNUSED(ring)); } - - adapter->tx_queue_len = netdev->tx_queue_len; } int e1000_up(struct e1000_adapter *adapter) @@ -503,7 +501,6 @@ void e1000_down(struct e1000_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); - netdev->tx_queue_len = adapter->tx_queue_len; adapter->link_speed = 0; adapter->link_duplex = 0; netif_carrier_off(netdev); @@ -2316,19 +2313,15 @@ static void e1000_watchdog(unsigned long data) E1000_CTRL_RFCE) ? "RX" : ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" ))); - /* tweak tx_queue_len according to speed/duplex - * and adjust the timeout factor */ - netdev->tx_queue_len = adapter->tx_queue_len; + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { case SPEED_10: txb2b = false; - netdev->tx_queue_len = 10; adapter->tx_timeout_factor = 16; break; case SPEED_100: txb2b = false; - netdev->tx_queue_len = 100; /* maybe add some timeout factor ? */ break; } From 44ebb95290afcc687511ad3f7fd6434e867c270a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 26 Mar 2010 16:27:55 +0000 Subject: [PATCH 361/478] drivers/net: Fix continuation lines Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/atlx/atl1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 9ba547069db..0ebd8208f60 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -84,7 +84,7 @@ #define ATLX_DRIVER_VERSION "2.1.3" MODULE_AUTHOR("Xiong Huang , \ - Chris Snook , Jay Cliburn "); +Chris Snook , Jay Cliburn "); MODULE_LICENSE("GPL"); MODULE_VERSION(ATLX_DRIVER_VERSION); From 7469a9acf919d36836f6c635099d8edc9be4528a Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 27 Mar 2010 08:36:18 -0700 Subject: [PATCH 362/478] sparc: Fix use of uid16_t and gid16_t in asm/stat.h Signed-off-by: Rob Landley Signed-off-by: David S. Miller --- arch/sparc/include/asm/stat.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sparc/include/asm/stat.h b/arch/sparc/include/asm/stat.h index 39327d6a57e..a232e9e1f4e 100644 --- a/arch/sparc/include/asm/stat.h +++ b/arch/sparc/include/asm/stat.h @@ -53,8 +53,8 @@ struct stat { ino_t st_ino; mode_t st_mode; short st_nlink; - uid16_t st_uid; - gid16_t st_gid; + unsigned short st_uid; + unsigned short st_gid; unsigned short st_rdev; off_t st_size; time_t st_atime; From a2fd940f4cff74b932728bd6ca12848da21a0234 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Thu, 25 Mar 2010 14:49:05 +0000 Subject: [PATCH 363/478] bonding: fix broken multicast with round-robin mode Round-robin (mode 0) does nothing to ensure that any multicast traffic originally destined for the host will continue to arrive at the host when the link that sent the IGMP join or membership report goes down. One of the benefits of absolute round-robin transmit. Keeping track of subscribed multicast groups for each slave did not seem like a good use of resources, so I decided to simply send on the curr_active slave of the bond (typically the first enslaved device that is up). This makes failover management simple as IGMP membership reports only need to be sent when the curr_active_slave changes. I tested this patch and it appears to work as expected. Originally reported by Lon Hohberger . Signed-off-by: Andy Gospodarek CC: Lon Hohberger CC: Jay Vosburgh Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 40 ++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 430c02267d7..5b92fbff431 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1235,6 +1235,11 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) write_lock_bh(&bond->curr_slave_lock); } } + + /* resend IGMP joins since all were sent on curr_active_slave */ + if (bond->params.mode == BOND_MODE_ROUNDROBIN) { + bond_resend_igmp_join_requests(bond); + } } /** @@ -4138,22 +4143,41 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *start_at; int i, slave_no, res = 1; + struct iphdr *iph = ip_hdr(skb); read_lock(&bond->lock); if (!BOND_IS_OK(bond)) goto out; - /* - * Concurrent TX may collide on rr_tx_counter; we accept that - * as being rare enough not to justify using an atomic op here + * Start with the curr_active_slave that joined the bond as the + * default for sending IGMP traffic. For failover purposes one + * needs to maintain some consistency for the interface that will + * send the join/membership reports. The curr_active_slave found + * will send all of this type of traffic. */ - slave_no = bond->rr_tx_counter++ % bond->slave_cnt; + if ((iph->protocol == htons(IPPROTO_IGMP)) && + (skb->protocol == htons(ETH_P_IP))) { - bond_for_each_slave(bond, slave, i) { - slave_no--; - if (slave_no < 0) - break; + read_lock(&bond->curr_slave_lock); + slave = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + if (!slave) + goto out; + } else { + /* + * Concurrent TX may collide on rr_tx_counter; we accept + * that as being rare enough not to justify using an + * atomic op here. + */ + slave_no = bond->rr_tx_counter++ % bond->slave_cnt; + + bond_for_each_slave(bond, slave, i) { + slave_no--; + if (slave_no < 0) + break; + } } start_at = slave; From 1546a713ae1f066f83469cdd99ebdf500d6a65e4 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Sat, 27 Mar 2010 10:55:37 +0000 Subject: [PATCH 364/478] pcnet_cs: add new id pcnet_cs: *add new id (Allied Telesis LM33-PCM-T Lan&Modem multifunction card) *use PROD_ID for LA-PCM.(because LA-PCM and LM33-PCM-T use the same MANF_ID). Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller --- drivers/net/pcmcia/pcnet_cs.c | 3 ++- drivers/serial/serial_cs.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 776cad2f571..1028fcb91a2 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1549,6 +1549,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x021b, 0x0101), PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x08a1, 0xc0ab), PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4), + PCMCIA_PFC_DEVICE_PROD_ID12(0, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e), PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff), PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae), PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033), @@ -1740,7 +1741,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "cis/DP83903.cis"), - PCMCIA_DEVICE_CIS_MANF_CARD(0xc00f, 0x0002, "cis/LA-PCM.cis"), + PCMCIA_DEVICE_CIS_PROD_ID12("Allied Telesis,K.K", "Ethernet LAN Card", 0x2ad62f3c, 0x9fd2f0a2, "cis/LA-PCM.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "cis/PE520.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "cis/NE2K.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("PMX ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "cis/PE-200.cis"), diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index e91db4b3801..175d202ab37 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -745,6 +745,7 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29), PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719), PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e), PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff), PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c), PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae), From 78f1cd02457252e1ffbc6caa44a17424a45286b8 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Sat, 27 Mar 2010 19:35:46 -0700 Subject: [PATCH 365/478] r8169: fix broken register writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is quite similar to b39fe41f481d20c201012e4483e76c203802dda7 though said registers are not even documented as 64-bit registers - as opposed to the initial TxDescStartAddress ones - but as single bytes which must be combined into 32 bits at the MMIO read/write level before being merged into a 64 bit logical entity. Credits go to Ben Hutchings for the MAR registers (aka "multicast is broken for ages on ARM) and to Timo Teräs for the MAC registers. Signed-off-by: Francois Romieu Signed-off-by: David S. Miller --- drivers/net/r8169.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b93fd23b9f0..7193afc00e4 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2820,8 +2820,8 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) spin_lock_irq(&tp->lock); RTL_W8(Cfg9346, Cfg9346_Unlock); - RTL_W32(MAC0, low); RTL_W32(MAC4, high); + RTL_W32(MAC0, low); RTL_W8(Cfg9346, Cfg9346_Lock); spin_unlock_irq(&tp->lock); @@ -4747,8 +4747,8 @@ static void rtl_set_rx_mode(struct net_device *dev) mc_filter[1] = swab32(data); } - RTL_W32(MAR0 + 0, mc_filter[0]); RTL_W32(MAR0 + 4, mc_filter[1]); + RTL_W32(MAR0 + 0, mc_filter[0]); RTL_W32(RxConfig, tmp); From d2566af8c4860a03ca685ef0910de406679c3e4e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 27 Mar 2010 21:11:56 -0700 Subject: [PATCH 366/478] arch/sparc/kernel: Use set_cpus_allowed_ptr Use set_cpus_allowed_ptr rather than set_cpus_allowed. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression E1,E2; @@ - set_cpus_allowed(E1, cpumask_of_cpu(E2)) + set_cpus_allowed_ptr(E1, cpumask_of(E2)) @@ expression E; identifier I; @@ - set_cpus_allowed(E, I) + set_cpus_allowed_ptr(E, &I) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- arch/sparc/kernel/sysfs.c | 4 ++-- arch/sparc/kernel/us2e_cpufreq.c | 8 ++++---- arch/sparc/kernel/us3_cpufreq.c | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/sparc/kernel/sysfs.c b/arch/sparc/kernel/sysfs.c index ca39c606fe8..1eb8b00aed7 100644 --- a/arch/sparc/kernel/sysfs.c +++ b/arch/sparc/kernel/sysfs.c @@ -107,12 +107,12 @@ static unsigned long run_on_cpu(unsigned long cpu, unsigned long ret; /* should return -EINVAL to userspace */ - if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) + if (set_cpus_allowed_ptr(current, cpumask_of(cpu))) return 0; ret = func(arg); - set_cpus_allowed(current, old_affinity); + set_cpus_allowed_ptr(current, &old_affinity); return ret; } diff --git a/arch/sparc/kernel/us2e_cpufreq.c b/arch/sparc/kernel/us2e_cpufreq.c index 791c15138f3..8f982b76c71 100644 --- a/arch/sparc/kernel/us2e_cpufreq.c +++ b/arch/sparc/kernel/us2e_cpufreq.c @@ -238,12 +238,12 @@ static unsigned int us2e_freq_get(unsigned int cpu) return 0; cpus_allowed = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(cpu)); + set_cpus_allowed_ptr(current, cpumask_of(cpu)); clock_tick = sparc64_get_clock_tick(cpu) / 1000; estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR); - set_cpus_allowed(current, cpus_allowed); + set_cpus_allowed_ptr(current, &cpus_allowed); return clock_tick / estar_to_divisor(estar); } @@ -259,7 +259,7 @@ static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) return; cpus_allowed = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(cpu)); + set_cpus_allowed_ptr(current, cpumask_of(cpu)); new_freq = clock_tick = sparc64_get_clock_tick(cpu) / 1000; new_bits = index_to_estar_mode(index); @@ -281,7 +281,7 @@ static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - set_cpus_allowed(current, cpus_allowed); + set_cpus_allowed_ptr(current, &cpus_allowed); } static int us2e_freq_target(struct cpufreq_policy *policy, diff --git a/arch/sparc/kernel/us3_cpufreq.c b/arch/sparc/kernel/us3_cpufreq.c index 365b6464e2c..f35d1e79454 100644 --- a/arch/sparc/kernel/us3_cpufreq.c +++ b/arch/sparc/kernel/us3_cpufreq.c @@ -86,12 +86,12 @@ static unsigned int us3_freq_get(unsigned int cpu) return 0; cpus_allowed = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(cpu)); + set_cpus_allowed_ptr(current, cpumask_of(cpu)); reg = read_safari_cfg(); ret = get_current_freq(cpu, reg); - set_cpus_allowed(current, cpus_allowed); + set_cpus_allowed_ptr(current, &cpus_allowed); return ret; } @@ -106,7 +106,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) return; cpus_allowed = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(cpu)); + set_cpus_allowed_ptr(current, cpumask_of(cpu)); new_freq = sparc64_get_clock_tick(cpu) / 1000; switch (index) { @@ -140,7 +140,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - set_cpus_allowed(current, cpus_allowed); + set_cpus_allowed_ptr(current, &cpus_allowed); } static int us3_freq_target(struct cpufreq_policy *policy, From bc8a67386fd462914269fa93446e1891955a8bb3 Mon Sep 17 00:00:00 2001 From: "JosephChan@via.com.tw" Date: Thu, 25 Mar 2010 20:51:47 +0800 Subject: [PATCH 367/478] pata_via: fix VT6410/6415/6330 detection issue When using VT6410/6415/6330 chips on some VIA's platforms, the HDD connection to VT6410/6415/6330 cannot be detected. It is because the driver detects wrong via_isa_bridge ID, and then causes this issue to happen. Signed-off-by: Joseph Chan Signed-off-by: Jeff Garzik --- drivers/ata/pata_via.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 95d39c36ace..c59b40710fb 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -576,6 +576,10 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) u8 rev = isa->revision; pci_dev_put(isa); + if ((id->device == 0x0415 || id->device == 0x3164) && + (config->id != id->device)) + continue; + if (rev >= config->rev_min && rev <= config->rev_max) break; } From 193219172691e29813821dc8433317768c6ed1a3 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Sat, 27 Mar 2010 09:56:58 +0100 Subject: [PATCH 368/478] Prevent data corruption in logfs_rewrite_block() The comment was correct, so make the code match the comment. As the new comment indicates, we might be able to do a little less work. But for the current -rc series let's keep it simple and just fix the bug. Signed-off-by: Joern Engel --- fs/logfs/readwrite.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index 7a23b3e7c0a..c3a3a6814b8 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c @@ -1594,7 +1594,6 @@ int logfs_delete(struct inode *inode, pgoff_t index, return ret; } -/* Rewrite cannot mark the inode dirty but has to write it immediatly. */ int logfs_rewrite_block(struct inode *inode, u64 bix, u64 ofs, gc_level_t gc_level, long flags) { @@ -1611,6 +1610,18 @@ int logfs_rewrite_block(struct inode *inode, u64 bix, u64 ofs, if (level != 0) alloc_indirect_block(inode, page, 0); err = logfs_write_buf(inode, page, flags); + if (!err && shrink_level(gc_level) == 0) { + /* Rewrite cannot mark the inode dirty but has to + * write it immediatly. + * Q: Can't we just create an alias for the inode + * instead? And if not, why not? + */ + if (inode->i_ino == LOGFS_INO_MASTER) + logfs_write_anchor(inode->i_sb); + else { + err = __logfs_write_inode(inode, flags); + } + } } logfs_put_write_page(page); return err; From 81def6b9862764924a99ac1b680e73ac8c80ac64 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Sun, 28 Mar 2010 12:47:09 +0200 Subject: [PATCH 369/478] Simplify and fix pad_wbuf A comment in the old code read: /* The math in this function can surely use some love */ And indeed it did. In the case that area->a_used_bytes is exactly 4096 bytes below segment size it fell apart. pad_wbuf is now split into two helpers that are significantly less complicated. Signed-off-by: Joern Engel --- fs/logfs/segment.c | 52 ++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c index 1a14f9910d5..ff9d7f3b4d3 100644 --- a/fs/logfs/segment.c +++ b/fs/logfs/segment.c @@ -93,49 +93,57 @@ void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, } while (len); } -/* - * bdev_writeseg will write full pages. Memset the tail to prevent data leaks. - */ -static void pad_wbuf(struct logfs_area *area, int final) +static void pad_partial_page(struct logfs_area *area) { struct super_block *sb = area->a_sb; - struct logfs_super *super = logfs_super(sb); struct page *page; u64 ofs = dev_ofs(sb, area->a_segno, area->a_used_bytes); pgoff_t index = ofs >> PAGE_SHIFT; long offset = ofs & (PAGE_SIZE-1); u32 len = PAGE_SIZE - offset; - if (len == PAGE_SIZE) { - /* The math in this function can surely use some love */ - len = 0; - } - if (len) { - BUG_ON(area->a_used_bytes >= super->s_segsize); - - page = get_mapping_page(area->a_sb, index, 0); + if (len % PAGE_SIZE) { + page = get_mapping_page(sb, index, 0); BUG_ON(!page); /* FIXME: reserve a pool */ memset(page_address(page) + offset, 0xff, len); SetPagePrivate(page); page_cache_release(page); } +} - if (!final) - return; +static void pad_full_pages(struct logfs_area *area) +{ + struct super_block *sb = area->a_sb; + struct logfs_super *super = logfs_super(sb); + u64 ofs = dev_ofs(sb, area->a_segno, area->a_used_bytes); + u32 len = super->s_segsize - area->a_used_bytes; + pgoff_t index = PAGE_CACHE_ALIGN(ofs) >> PAGE_CACHE_SHIFT; + pgoff_t no_indizes = len >> PAGE_CACHE_SHIFT; + struct page *page; - area->a_used_bytes += len; - for ( ; area->a_used_bytes < super->s_segsize; - area->a_used_bytes += PAGE_SIZE) { - /* Memset another page */ - index++; - page = get_mapping_page(area->a_sb, index, 0); + while (no_indizes) { + page = get_mapping_page(sb, index, 0); BUG_ON(!page); /* FIXME: reserve a pool */ - memset(page_address(page), 0xff, PAGE_SIZE); + SetPageUptodate(page); + memset(page_address(page), 0xff, PAGE_CACHE_SIZE); SetPagePrivate(page); page_cache_release(page); + index++; + no_indizes--; } } +/* + * bdev_writeseg will write full pages. Memset the tail to prevent data leaks. + * Also make sure we allocate (and memset) all pages for final writeout. + */ +static void pad_wbuf(struct logfs_area *area, int final) +{ + pad_partial_page(area); + if (final) + pad_full_pages(area); +} + /* * We have to be careful with the alias tree. Since lookup is done by bix, * it needs to be normalized, so 14, 15, 16, etc. all match when dealing with From 723b2ff40876678b49e61df34fb1d8001e34639d Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Sun, 28 Mar 2010 18:10:07 +0200 Subject: [PATCH 370/478] [LogFS] Clear PagePrivate when moving journal do_logfs_journal_wl_pass() must call freeseg(), thereby clear PagePrivate on all pages of the current journal segment. Signed-off-by: Joern Engel --- fs/logfs/journal.c | 1 + fs/logfs/logfs.h | 1 + fs/logfs/segment.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c index 6ad30a4c905..15454ac7bd9 100644 --- a/fs/logfs/journal.c +++ b/fs/logfs/journal.c @@ -821,6 +821,7 @@ void do_logfs_journal_wl_pass(struct super_block *sb) logfs_set_segment_reserved(sb, segno); } /* Manually move journal_area */ + freeseg(sb, area->a_segno); area->a_segno = super->s_journal_seg[0]; area->a_is_open = 0; area->a_used_bytes = 0; diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h index 12977943137..b84b0eec602 100644 --- a/fs/logfs/logfs.h +++ b/fs/logfs/logfs.h @@ -587,6 +587,7 @@ void move_page_to_btree(struct page *page); int logfs_init_mapping(struct super_block *sb); void logfs_sync_area(struct logfs_area *area); void logfs_sync_segments(struct super_block *sb); +void freeseg(struct super_block *sb, u32 segno); /* area handling */ int logfs_init_areas(struct super_block *sb); diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c index ff9d7f3b4d3..0ecd8f07c11 100644 --- a/fs/logfs/segment.c +++ b/fs/logfs/segment.c @@ -691,7 +691,7 @@ int logfs_segment_delete(struct inode *inode, struct logfs_shadow *shadow) return 0; } -static void freeseg(struct super_block *sb, u32 segno) +void freeseg(struct super_block *sb, u32 segno) { struct logfs_super *super = logfs_super(sb); struct address_space *mapping = super->s_mapping_inode->i_mapping; From 7855f761998893bb6bf861d55df95036fc9e36ab Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 28 Mar 2010 18:56:34 -0700 Subject: [PATCH 371/478] tulip: Add missing parens. As reported by Stephen Rothwell. drivers/net/tulip/uli526x.c: In function 'uli526x_rx_packet': drivers/net/tulip/uli526x.c:861: warning: assignment makes pointer from integer without a cast Signed-off-by: David S. Miller --- drivers/net/tulip/uli526x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 90be57bad39..a4f09d49053 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -858,7 +858,7 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info /* Good packet, send to upper layer */ /* Shorst packet used new SKB */ if ((rxlen < RX_COPY_SIZE) && - ((new_skb = dev_alloc_skb(rxlen + 2) != NULL))) { + (((new_skb = dev_alloc_skb(rxlen + 2)) != NULL))) { skb = new_skb; /* size less than COPY_SIZE, allocate a rxlen SKB */ skb_reserve(skb, 2); /* 16byte align */ From 9ce41aed0d392246eb788786253f242e829fd5e1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 28 Mar 2010 18:58:28 -0700 Subject: [PATCH 372/478] Revert "ide: skip probe if there are no devices on the port (v2)" This reverts commit a20b2a44eca52818ef52a94959480b7e6ea2f528. As requested by David Fries. This makes CDROMs which are slave drives on a ribbon without a master disappear and causes other similar kinds of badness. Signed-off-by: David S. Miller --- drivers/ide/ide-probe.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index fbedd35feb4..4c3d1bfec0c 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -695,14 +695,8 @@ static int ide_probe_port(ide_hwif_t *hwif) if (irqd) disable_irq(hwif->irq); - rc = ide_port_wait_ready(hwif); - if (rc == -ENODEV) { - printk(KERN_INFO "%s: no devices on the port\n", hwif->name); - goto out; - } else if (rc == -EBUSY) - printk(KERN_ERR "%s: not ready before the probe\n", hwif->name); - else - rc = -ENODEV; + if (ide_port_wait_ready(hwif) == -EBUSY) + printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); /* * Second drive should only exist if first drive was found, @@ -713,7 +707,7 @@ static int ide_probe_port(ide_hwif_t *hwif) if (drive->dev_flags & IDE_DFLAG_PRESENT) rc = 0; } -out: + /* * Use cached IRQ number. It might be (and is...) changed by probe * code above From 54c1a859efd9fd6cda05bc700315ba2519c14eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Sun, 28 Mar 2010 07:15:45 +0000 Subject: [PATCH 373/478] ipv6: Don't drop cache route entry unless timer actually expired. This is ipv6 variant of the commit 5e016cbf6.. ("ipv4: Don't drop redirected route cache entry unless PTMU actually expired") by Guenter Roeck . Remove cache route entry in ipv6_negative_advice() only if the timer is expired. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/route.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7fcb0e5d121..0d7713c5c20 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -890,12 +890,17 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) struct rt6_info *rt = (struct rt6_info *) dst; if (rt) { - if (rt->rt6i_flags & RTF_CACHE) - ip6_del_rt(rt); - else + if (rt->rt6i_flags & RTF_CACHE) { + if (rt6_check_expired(rt)) { + ip6_del_rt(rt); + dst = NULL; + } + } else { dst_release(dst); + dst = NULL; + } } - return NULL; + return dst; } static void ip6_link_failure(struct sk_buff *skb) From 94aa8ae13db2ecf2ec1b4e65a65d3fe92b468e0e Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sun, 28 Mar 2010 21:22:50 -0700 Subject: [PATCH 374/478] ceph: fix use after free on mds __unregister_request There was a use after free in __unregister_request that would trigger whenever the request map held the last reference. This appears to have triggered an oops during 'umount -f' when requests are being torn down. Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 5268d404963..5c7920be642 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -532,7 +532,6 @@ static void __unregister_request(struct ceph_mds_client *mdsc, dout("__unregister_request %p tid %lld\n", req, req->r_tid); rb_erase(&req->r_node, &mdsc->request_tree); RB_CLEAR_NODE(&req->r_node); - ceph_mdsc_put_request(req); if (req->r_unsafe_dir) { struct ceph_inode_info *ci = ceph_inode(req->r_unsafe_dir); @@ -541,6 +540,8 @@ static void __unregister_request(struct ceph_mds_client *mdsc, list_del_init(&req->r_unsafe_dir_item); spin_unlock(&ci->i_unsafe_lock); } + + ceph_mdsc_put_request(req); } /* From 5cd165e7057020884e430941c24454d3df9a799d Mon Sep 17 00:00:00 2001 From: Daniel Chen Date: Sun, 28 Mar 2010 13:32:34 -0700 Subject: [PATCH 375/478] ALSA: ac97: Add Toshiba P500 to ac97 jack sense blacklist BugLink: https://launchpad.net/bugs/481058 The OR has verified that both 'Headphone Jack Sense' and 'Line Jack Sense' need to be muted for sound to be audible, so just add the machine's SSID to the ac97 jack sense blacklist. Reported-by: Richard Gagne Tested-by: Richard Gagne Cc: Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 1a59b71c543..e68c98ef404 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1859,6 +1859,7 @@ static unsigned int ad1981_jacks_blacklist[] = { 0x10280160, /* Dell Dimension 2400 */ 0x104380b0, /* Asus A7V8X-MX */ 0x11790241, /* Toshiba Satellite A-15 S127 */ + 0x1179ff10, /* Toshiba P500 */ 0x144dc01a, /* Samsung NP-X20C004/SEG */ 0 /* end */ }; From 9ec8ddad59fadd8021adfea4cb716a49b0e232e9 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Sun, 28 Mar 2010 02:34:40 -0400 Subject: [PATCH 376/478] ALSA: hda: Use LPIB for ga-ma770-ud3 board BugLink: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=575669 The OR states that position_fix=1 is necessary to work around glitching during volume adjustments using PulseAudio. Reported-by: Carlos Laviola Tested-by: Carlos Laviola Cc: Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8b2915631cc..4bb90675f70 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2269,6 +2269,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), From 05ad62a5ee2ec2f65142aa2bf5c8a7e2f9cf9590 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Wed, 10 Mar 2010 00:10:46 -0500 Subject: [PATCH 377/478] Staging: et131x: Properly disable FC in txmac. FC disable is bit 3 of the txmac ctl register, but commit 6720949d5562 ("Staging: et131x: Kil the txmac type") accidentally changed the code to set bit 2 instead. Signed-off-by: Nick Bowler Signed-off-by: Linus Torvalds --- drivers/staging/et131x/et1310_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/et131x/et1310_mac.c b/drivers/staging/et131x/et1310_mac.c index a292b1edc41..737a9f5401d 100644 --- a/drivers/staging/et131x/et1310_mac.c +++ b/drivers/staging/et131x/et1310_mac.c @@ -226,7 +226,7 @@ void ConfigMACRegs2(struct et131x_adapter *etdev) } /* Enable TXMAC */ - ctl |= 0x05; /* TX mac enable, FC disable */ + ctl |= 0x09; /* TX mac enable, FC disable */ writel(ctl, &etdev->regs->txmac.ctl); /* Ready to start the RXDMA/TXDMA engine */ From 88be12c440cfa2fa3f5be83507360aac9ea1c54e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 29 Mar 2010 12:01:50 +0100 Subject: [PATCH 378/478] slow-work: use get_ref wrapper instead of directly calling get_ref Otherwise we can get an oops if the user has no get_ref/put_ref requirement. Signed-off-by: Dave Airlie Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- kernel/slow-work.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/slow-work.c b/kernel/slow-work.c index 7494bbf5a27..7d3f4fa9ef4 100644 --- a/kernel/slow-work.c +++ b/kernel/slow-work.c @@ -637,7 +637,7 @@ int delayed_slow_work_enqueue(struct delayed_slow_work *dwork, goto cancelled; /* the timer holds a reference whilst it is pending */ - ret = work->ops->get_ref(work); + ret = slow_work_get_ref(work); if (ret < 0) goto cant_get_ref; From a53f4f9efaeb1d87cfae066346979d4d70e1abe9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Mar 2010 13:08:52 +0100 Subject: [PATCH 379/478] SLOW_WORK: CONFIG_SLOW_WORK_PROC should be CONFIG_SLOW_WORK_DEBUG CONFIG_SLOW_WORK_PROC was changed to CONFIG_SLOW_WORK_DEBUG, but not in all instances. Change the remaining instances. This makes the debugfs file display the time mark and the owner's description again. Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- fs/fscache/object.c | 6 +++--- fs/fscache/operation.c | 4 ++-- include/linux/fscache-cache.h | 2 +- kernel/slow-work.h | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/fscache/object.c b/fs/fscache/object.c index e513ac599c8..0b589a9b4ff 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -53,7 +53,7 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { static void fscache_object_slow_work_put_ref(struct slow_work *); static int fscache_object_slow_work_get_ref(struct slow_work *); static void fscache_object_slow_work_execute(struct slow_work *); -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG static void fscache_object_slow_work_desc(struct slow_work *, struct seq_file *); #endif static void fscache_initialise_object(struct fscache_object *); @@ -69,7 +69,7 @@ const struct slow_work_ops fscache_object_slow_work_ops = { .get_ref = fscache_object_slow_work_get_ref, .put_ref = fscache_object_slow_work_put_ref, .execute = fscache_object_slow_work_execute, -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG .desc = fscache_object_slow_work_desc, #endif }; @@ -364,7 +364,7 @@ static void fscache_object_slow_work_execute(struct slow_work *work) /* * describe an object for slow-work debugging */ -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG static void fscache_object_slow_work_desc(struct slow_work *work, struct seq_file *m) { diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 313e79a1426..9f6c928d458 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c @@ -500,7 +500,7 @@ static void fscache_op_execute(struct slow_work *work) /* * describe an operation for slow-work debugging */ -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG static void fscache_op_desc(struct slow_work *work, struct seq_file *m) { struct fscache_operation *op = @@ -517,7 +517,7 @@ const struct slow_work_ops fscache_op_slow_work_ops = { .get_ref = fscache_op_get_ref, .put_ref = fscache_op_put_ref, .execute = fscache_op_execute, -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG .desc = fscache_op_desc, #endif }; diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 7be0c6fbe88..c57db27ac86 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -105,7 +105,7 @@ struct fscache_operation { /* operation releaser */ fscache_operation_release_t release; -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG const char *name; /* operation name */ const char *state; /* operation state */ #define fscache_set_op_name(OP, N) do { (OP)->name = (N); } while(0) diff --git a/kernel/slow-work.h b/kernel/slow-work.h index 321f3c59d73..a29ebd1ef41 100644 --- a/kernel/slow-work.h +++ b/kernel/slow-work.h @@ -43,28 +43,28 @@ extern void slow_work_new_thread_desc(struct slow_work *, struct seq_file *); */ static inline void slow_work_set_thread_pid(int id, pid_t pid) { -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG slow_work_pids[id] = pid; #endif } static inline void slow_work_mark_time(struct slow_work *work) { -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG work->mark = CURRENT_TIME; #endif } static inline void slow_work_begin_exec(int id, struct slow_work *work) { -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG slow_work_execs[id] = work; #endif } static inline void slow_work_end_exec(int id, struct slow_work *work) { -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG write_lock(&slow_work_execs_lock); slow_work_execs[id] = NULL; write_unlock(&slow_work_execs_lock); From f7454c5d5c33b84fdbb957b7ad4a432e333b2550 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 24 Mar 2010 16:59:36 +0000 Subject: [PATCH 380/478] frv/chris: fix lines with a missing semicolons Commit b26b2d494b659f9 ("resource/PCI: align functions now return start of resource") added lines with missing semicolons. Add the missing semicolons to the FRV and CRIS arch code. Signed-off-by: David Howells Cc: linux@dominikbrodowski.net Signed-off-by: Linus Torvalds --- arch/cris/arch-v32/drivers/pci/bios.c | 2 +- arch/frv/mb93090-mb00/pci-frv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c index d4b9c36ddc0..bc0cfdad1cb 100644 --- a/arch/cris/arch-v32/drivers/pci/bios.c +++ b/arch/cris/arch-v32/drivers/pci/bios.c @@ -50,7 +50,7 @@ pcibios_align_resource(void *data, const struct resource *res, if ((res->flags & IORESOURCE_IO) && (start & 0x300)) start = (start + 0x3ff) & ~0x3ff; - return start + return start; } int pcibios_enable_resources(struct pci_dev *dev, int mask) diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c index 16bc2cb5649..6b4fb28e9f9 100644 --- a/arch/frv/mb93090-mb00/pci-frv.c +++ b/arch/frv/mb93090-mb00/pci-frv.c @@ -41,7 +41,7 @@ pcibios_align_resource(void *data, const struct resource *res, if ((res->flags & IORESOURCE_IO) && (start & 0x300)) start = (start + 0x3ff) & ~0x3ff; - return start + return start; } From 596b711ed6b5235f8545680ef38ace00f9898c32 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sun, 28 Mar 2010 19:42:54 -0700 Subject: [PATCH 381/478] x86: Make smp_locks end with page alignment Fix: ------------[ cut here ]------------ WARNING: at arch/x86/mm/init.c:342 free_init_pages+0x4c/0xfa() free_init_pages: range [0x40daf000, 0x40db5c24] is not aligned Modules linked in: Pid: 0, comm: swapper Not tainted 2.6.34-rc2-tip-03946-g4f16b23-dirty #50 Call Trace: [<40232e9f>] warn_slowpath_common+0x65/0x7c [<4021c9f0>] ? free_init_pages+0x4c/0xfa [<40881434>] ? _etext+0x0/0x24 [<40232eea>] warn_slowpath_fmt+0x24/0x27 [<4021c9f0>] free_init_pages+0x4c/0xfa [<40881434>] ? _etext+0x0/0x24 [<40d3f4bd>] alternative_instructions+0xf6/0x100 [<40d3fe4f>] check_bugs+0xbd/0xbf [<40d398a7>] start_kernel+0x2d5/0x2e4 [<40d390ce>] i386_start_kernel+0xce/0xd5 ---[ end trace 4eaa2a86a8e2da22 ]--- Comments in vmlinux.lds.S already said: | /* | * smp_locks might be freed after init | * start/end must be page aligned | */ Signed-off-by: Yinghai Lu Acked-by: Johannes Weiner Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Linus Torvalds LKML-Reference: <1269830604-26214-2-git-send-email-yinghai@kernel.org> Signed-off-by: Ingo Molnar --- arch/x86/kernel/vmlinux.lds.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 44879df5569..2cc249718c4 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -291,8 +291,8 @@ SECTIONS .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { __smp_locks = .; *(.smp_locks) - __smp_locks_end = .; . = ALIGN(PAGE_SIZE); + __smp_locks_end = .; } #ifdef CONFIG_X86_64 From 8136b58dd0fce0b4cb649ac690e0493fb6fdacdb Mon Sep 17 00:00:00 2001 From: Cheng Renquan Date: Mon, 29 Mar 2010 19:05:57 +0800 Subject: [PATCH 382/478] ceph: some documentations fixes New documentation should have an entry in the 00-INDEX. Correct git urls. Signed-off-by: Cheng Renquan Signed-off-by: Sage Weil --- Documentation/filesystems/00-INDEX | 2 ++ Documentation/filesystems/ceph.txt | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 3bae418c6ad..4303614b5ad 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX @@ -16,6 +16,8 @@ befs.txt - information about the BeOS filesystem for Linux. bfs.txt - info for the SCO UnixWare Boot Filesystem (BFS). +ceph.txt + - info for the Ceph Distributed File System cifs.txt - description of the CIFS filesystem. coda.txt diff --git a/Documentation/filesystems/ceph.txt b/Documentation/filesystems/ceph.txt index 523fdf0828d..0660c9f5dee 100644 --- a/Documentation/filesystems/ceph.txt +++ b/Documentation/filesystems/ceph.txt @@ -8,7 +8,7 @@ Basic features include: * POSIX semantics * Seamless scaling from 1 to many thousands of nodes - * High availability and reliability. No single points of failure. + * High availability and reliability. No single point of failure. * N-way replication of data across storage nodes * Fast recovery from node failures * Automatic rebalancing of data on node addition/removal @@ -94,7 +94,7 @@ Mount Options wsize=X Specify the maximum write size in bytes. By default there is no - maximu. Ceph will normally size writes based on the file stripe + maximum. Ceph will normally size writes based on the file stripe size. rsize=X @@ -133,7 +133,8 @@ For more information on Ceph, see the home page at http://ceph.newdream.net/ The Linux kernel client source tree is available at - git://ceph.newdream.net/linux-ceph-client.git + git://ceph.newdream.net/git/ceph-client.git + git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git and the source for the full system is at - git://ceph.newdream.net/ceph.git + git://ceph.newdream.net/git/ceph.git From 82593f87b6c1922a8f8317bb165c6c7794fa4639 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 29 Mar 2010 09:53:23 -0700 Subject: [PATCH 383/478] ceph: update discussion list address in MAINTAINERS Signed-off-by: Sage Weil --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 449d4440208..c3b60c024f8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1443,7 +1443,7 @@ F: arch/powerpc/platforms/cell/ CEPH DISTRIBUTED FILE SYSTEM CLIENT M: Sage Weil -L: ceph-devel@lists.sourceforge.net +L: ceph-devel@vger.kernel.org W: http://ceph.newdream.net/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git S: Supported From c967da6a0ba837f762042e931d4afcf72045547c Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sun, 28 Mar 2010 19:42:55 -0700 Subject: [PATCH 384/478] x86: Make sure free_init_pages() frees pages on page boundary When CONFIG_NO_BOOTMEM=y, it could use memory more effiently, or in a more compact fashion. Example: Allocated new RAMDISK: 00ec2000 - 0248ce57 Move RAMDISK from 000000002ea04000 - 000000002ffcee56 to 00ec2000 - 0248ce56 The new RAMDISK's end is not page aligned. Last page could be shared with other users. When free_init_pages are called for initrd or .init, the page could be freed and we could corrupt other data. code segment in free_init_pages(): | for (; addr < end; addr += PAGE_SIZE) { | ClearPageReserved(virt_to_page(addr)); | init_page_count(virt_to_page(addr)); | memset((void *)(addr & ~(PAGE_SIZE-1)), | POISON_FREE_INITMEM, PAGE_SIZE); | free_page(addr); | totalram_pages++; | } last half page could be used as one whole free page. So page align the boundaries. -v2: make the original initramdisk to be aligned, according to Johannes, otherwise we have the chance to lose one page. we still need to keep initrd_end not aligned, otherwise it could confuse decompressor. -v3: change to WARN_ON instead, suggested by Johannes. -v4: use PAGE_ALIGN, suggested by Johannes. We may fix that macro name later to PAGE_ALIGN_UP, and PAGE_ALIGN_DOWN Add comments about assuming ramdisk start is aligned in relocate_initrd(), change to re get ramdisk_image instead of save it to make diff smaller. Add warning for wrong range, suggested by Johannes. -v6: remove one WARN() We need to align beginning in free_init_pages() do not copy more than ramdisk_size, noticed by Johannes Reported-by: Stanislaw Gruszka Tested-by: Stanislaw Gruszka Signed-off-by: Yinghai Lu Acked-by: Johannes Weiner Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Linus Torvalds LKML-Reference: <1269830604-26214-3-git-send-email-yinghai@kernel.org> Signed-off-by: Ingo Molnar --- arch/x86/kernel/head32.c | 4 +++- arch/x86/kernel/head64.c | 3 ++- arch/x86/kernel/setup.c | 10 ++++++---- arch/x86/mm/init.c | 32 ++++++++++++++++++++++++++------ 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index adedeef1ded..b2e24603739 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -44,9 +45,10 @@ void __init i386_start_kernel(void) #ifdef CONFIG_BLK_DEV_INITRD /* Reserve INITRD */ if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { + /* Assume only end is not page aligned */ u64 ramdisk_image = boot_params.hdr.ramdisk_image; u64 ramdisk_size = boot_params.hdr.ramdisk_size; - u64 ramdisk_end = ramdisk_image + ramdisk_size; + u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); reserve_early(ramdisk_image, ramdisk_end, "RAMDISK"); } #endif diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index b5a9896ca1e..7147143fd61 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -103,9 +103,10 @@ void __init x86_64_start_reservations(char *real_mode_data) #ifdef CONFIG_BLK_DEV_INITRD /* Reserve INITRD */ if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { + /* Assume only end is not page aligned */ unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; - unsigned long ramdisk_end = ramdisk_image + ramdisk_size; + unsigned long ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); reserve_early(ramdisk_image, ramdisk_end, "RAMDISK"); } #endif diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 5d7ba1a449b..d76e18570c6 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -314,16 +314,17 @@ static void __init reserve_brk(void) #define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT) static void __init relocate_initrd(void) { - + /* Assume only end is not page aligned */ u64 ramdisk_image = boot_params.hdr.ramdisk_image; u64 ramdisk_size = boot_params.hdr.ramdisk_size; + u64 area_size = PAGE_ALIGN(ramdisk_size); u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT; u64 ramdisk_here; unsigned long slop, clen, mapaddr; char *p, *q; /* We need to move the initrd down into lowmem */ - ramdisk_here = find_e820_area(0, end_of_lowmem, ramdisk_size, + ramdisk_here = find_e820_area(0, end_of_lowmem, area_size, PAGE_SIZE); if (ramdisk_here == -1ULL) @@ -332,7 +333,7 @@ static void __init relocate_initrd(void) /* Note: this includes all the lowmem currently occupied by the initrd, we rely on that fact to keep the data intact. */ - reserve_early(ramdisk_here, ramdisk_here + ramdisk_size, + reserve_early(ramdisk_here, ramdisk_here + area_size, "NEW RAMDISK"); initrd_start = ramdisk_here + PAGE_OFFSET; initrd_end = initrd_start + ramdisk_size; @@ -376,9 +377,10 @@ static void __init relocate_initrd(void) static void __init reserve_initrd(void) { + /* Assume only end is not page aligned */ u64 ramdisk_image = boot_params.hdr.ramdisk_image; u64 ramdisk_size = boot_params.hdr.ramdisk_size; - u64 ramdisk_end = ramdisk_image + ramdisk_size; + u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT; if (!boot_params.hdr.type_of_loader || diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index e71c5cbc8f3..452ee5b8f30 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -331,11 +331,23 @@ int devmem_is_allowed(unsigned long pagenr) void free_init_pages(char *what, unsigned long begin, unsigned long end) { - unsigned long addr = begin; + unsigned long addr; + unsigned long begin_aligned, end_aligned; - if (addr >= end) + /* Make sure boundaries are page aligned */ + begin_aligned = PAGE_ALIGN(begin); + end_aligned = end & PAGE_MASK; + + if (WARN_ON(begin_aligned != begin || end_aligned != end)) { + begin = begin_aligned; + end = end_aligned; + } + + if (begin >= end) return; + addr = begin; + /* * If debugging page accesses then do not free this memory but * mark them not present - any buggy init-section access will @@ -343,7 +355,7 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) */ #ifdef CONFIG_DEBUG_PAGEALLOC printk(KERN_INFO "debug: unmapping init memory %08lx..%08lx\n", - begin, PAGE_ALIGN(end)); + begin, end); set_memory_np(begin, (end - begin) >> PAGE_SHIFT); #else /* @@ -358,8 +370,7 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) for (; addr < end; addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); - memset((void *)(addr & ~(PAGE_SIZE-1)), - POISON_FREE_INITMEM, PAGE_SIZE); + memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); free_page(addr); totalram_pages++; } @@ -376,6 +387,15 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - free_init_pages("initrd memory", start, end); + /* + * end could be not aligned, and We can not align that, + * decompresser could be confused by aligned initrd_end + * We already reserve the end partial page before in + * - i386_start_kernel() + * - x86_64_start_kernel() + * - relocate_initrd() + * So here We can do PAGE_ALIGN() safely to get partial page to be freed + */ + free_init_pages("initrd memory", start, PAGE_ALIGN(end)); } #endif From eed63519e3e74d515d2007ecd895338d0ba2a85c Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Sun, 28 Mar 2010 19:42:56 -0700 Subject: [PATCH 385/478] x86: Do not free zero sized per cpu areas This avoids an infinite loop in free_early_partial(). Add a warning to free_early_partial() to catch future problems. -v5: put back start > end back into WARN_ONCE() -v6: use one line for warning, suggested by Linus -v7: more tests -v8: remove the function name as suggested by Johannes WARN_ONCE() will print out that function name. Signed-off-by: Ian Campbell Signed-off-by: Yinghai Lu Tested-by: Konrad Rzeszutek Wilk Tested-by: Joel Becker Tested-by: Stanislaw Gruszka Acked-by: Johannes Weiner Cc: Peter Zijlstra Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Linus Torvalds LKML-Reference: <1269830604-26214-4-git-send-email-yinghai@kernel.org> Signed-off-by: Ingo Molnar --- kernel/early_res.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/early_res.c b/kernel/early_res.c index 3cb2c661bb7..31aa9332ef3 100644 --- a/kernel/early_res.c +++ b/kernel/early_res.c @@ -333,6 +333,12 @@ void __init free_early_partial(u64 start, u64 end) struct early_res *r; int i; + if (start == end) + return; + + if (WARN_ONCE(start > end, " wrong range [%#llx, %#llx]\n", start, end)) + return; + try_next: i = find_overlapped_early(start, end); if (i >= max_early_res) From 0943846ae05603efd98550f2d475e9c98191bde8 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Mon, 29 Mar 2010 21:13:28 +0200 Subject: [PATCH 386/478] [LogFS] Move reserved segments with journal Fixes a GC livelock. Signed-off-by: Joern Engel --- fs/logfs/journal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c index 15454ac7bd9..25b1345c465 100644 --- a/fs/logfs/journal.c +++ b/fs/logfs/journal.c @@ -800,6 +800,7 @@ void do_logfs_journal_wl_pass(struct super_block *sb) { struct logfs_super *super = logfs_super(sb); struct logfs_area *area = super->s_journal_area; + struct btree_head32 *head = &super->s_reserved_segments; u32 segno, ec; int i, err; @@ -807,6 +808,7 @@ void do_logfs_journal_wl_pass(struct super_block *sb) /* Drop old segments */ journal_for_each(i) if (super->s_journal_seg[i]) { + btree_remove32(head, super->s_journal_seg[i]); logfs_set_segment_unreserved(sb, super->s_journal_seg[i], super->s_journal_ec[i]); @@ -819,6 +821,8 @@ void do_logfs_journal_wl_pass(struct super_block *sb) super->s_journal_seg[i] = segno; super->s_journal_ec[i] = ec; logfs_set_segment_reserved(sb, segno); + err = btree_insert32(head, segno, (void *)1, GFP_KERNEL); + BUG_ON(err); /* mempool should prevent this */ } /* Manually move journal_area */ freeseg(sb, area->a_segno); From 6be7fa06eb4d721df734bd0946b5e63b27c0589b Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Mon, 29 Mar 2010 21:14:52 +0200 Subject: [PATCH 387/478] [LogFS] Erase new journal segments If the device contains on old logfs image and the journal is moved to segment that have never been used by the current logfs and not all journal segments are erased before the next mount, the old content can confuse mount code. To prevent this, always erase the new journal segments. Signed-off-by: Joern Engel --- fs/logfs/journal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c index 25b1345c465..d57c7b07b60 100644 --- a/fs/logfs/journal.c +++ b/fs/logfs/journal.c @@ -823,6 +823,8 @@ void do_logfs_journal_wl_pass(struct super_block *sb) logfs_set_segment_reserved(sb, segno); err = btree_insert32(head, segno, (void *)1, GFP_KERNEL); BUG_ON(err); /* mempool should prevent this */ + err = logfs_erase_segment(sb, segno, 1); + BUG_ON(err); /* FIXME: remount-ro would be nicer */ } /* Manually move journal_area */ freeseg(sb, area->a_segno); From fcc6a7462ec8d8a7d63ec59559e91f8fd6991160 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Mon, 29 Mar 2010 22:02:59 +0200 Subject: [PATCH 388/478] hwmon: (coretemp) Fix cpu model output Avoid hex and decimal confusion when printing out the cpu model. Signed-off-by: Prarit Bhargava Signed-off-by: Jean Delvare --- drivers/hwmon/coretemp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 2d7bceeed0b..f5f975ba36e 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -466,7 +466,7 @@ static int __init coretemp_init(void) family 6 CPU */ if ((c->x86 == 0x6) && (c->x86_model > 0xf)) printk(KERN_WARNING DRVNAME ": Unknown CPU " - "model %x\n", c->x86_model); + "model 0x%x\n", c->x86_model); continue; } From 4d7a5644e4adfafe76c2bd8ee168e3f3b5dae3a8 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Mon, 29 Mar 2010 22:03:00 +0200 Subject: [PATCH 389/478] hwmon: (coretemp) Add missing newline to dev_warn() message Add missing newline to dev_warn() message string. This is more of an issue with older kernels that don't automatically add a newline if it was missing from the end of the previous line. Signed-off-by: Dean Nelson Cc: stable@kernel.org Signed-off-by: Jean Delvare --- drivers/hwmon/coretemp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index f5f975ba36e..e9b7fbc5a44 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -228,7 +228,7 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device * if (err) { dev_warn(dev, "Unable to access MSR 0xEE, for Tjmax, left" - " at default"); + " at default\n"); } else if (eax & 0x40000000) { tjmax = tjmax_ee; } From 3f7cd7ea9383755eef53f92667c520489165667f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 29 Mar 2010 22:03:03 +0200 Subject: [PATCH 390/478] hwmon: (w83793) Saving negative errors in unsigned "ret" is used to store the return value for watchdog_trigger() and it should be signed for the error handling to work. Signed-off-by: Dan Carpenter Acked-by: Hans de Goede Signed-off-by: Jean Delvare --- drivers/hwmon/w83793.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 9de81a4c15a..612807d9715 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -1294,7 +1294,7 @@ static int watchdog_close(struct inode *inode, struct file *filp) static ssize_t watchdog_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset) { - size_t ret; + ssize_t ret; struct w83793_data *data = filp->private_data; if (count) { From b00d8a7e299eab9970b0ba75a4e2ea1df39059ad Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Mon, 29 Mar 2010 22:03:06 +0200 Subject: [PATCH 391/478] hwmon: (asc7621) Add X58 entry in Kconfig Intel X58 have asc7621a chip. So added X58 entry in Kconfig for asc7621. Also arranged existing models in ascending order. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: Jean Delvare --- drivers/hwmon/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e4595e6147b..9be8e1754a0 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -217,8 +217,8 @@ config SENSORS_ASC7621 depends on HWMON && I2C help If you say yes here you get support for the aSC7621 - family of SMBus sensors chip found on most Intel X48, X38, 975, - 965 and 945 desktop boards. Currently supported chips: + family of SMBus sensors chip found on most Intel X38, X48, X58, + 945, 965 and 975 desktop boards. Currently supported chips: aSC7621 aSC7621a From 9e8307ecaf9f8c8b5b3b22145021204c4e73114a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 29 Mar 2010 13:08:52 -0700 Subject: [PATCH 392/478] sparc64: Properly truncate pt_regs framepointer in perf callback. For 32-bit processes, we save the full 64-bits of the regs in pt_regs. But unlike when the userspace actually does load and store instructions, the top 32-bits don't get automatically truncated by the cpu in kernel mode (because the kernel doesn't execute with PSTATE_AM address masking enabled). So we have to do it by hand. Reported-by: Frederic Weisbecker Signed-off-by: David S. Miller --- arch/sparc/kernel/perf_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 9f2b2bac8b2..610112ec518 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -1337,7 +1337,7 @@ static void perf_callchain_user_32(struct pt_regs *regs, callchain_store(entry, PERF_CONTEXT_USER); callchain_store(entry, regs->tpc); - ufp = regs->u_regs[UREG_I6]; + ufp = regs->u_regs[UREG_I6] & 0xffffffffUL; do { struct sparc_stackf32 *usf, sf; unsigned long pc; From c0cd884af045338476b8e69a61fceb3f34ff22f1 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 29 Mar 2010 13:16:02 -0700 Subject: [PATCH 393/478] r8169: offical fix for CVE-2009-4537 (overlength frame DMAs) Official patch to fix the r8169 frame length check error. Based on this initial thread: http://marc.info/?l=linux-netdev&m=126202972828626&w=1 This is the official patch to fix the frame length problems in the r8169 driver. As noted in the previous thread, while this patch incurs a performance hit on the driver, its possible to improve performance dynamically by updating the mtu and rx_copybreak values at runtime to return performance to what it was for those NICS which are unaffected by the ideosyncracy (if there are any). Summary: A while back Eric submitted a patch for r8169 in which the proper allocated frame size was written to RXMaxSize to prevent the NIC from dmaing too much data. This was done in commit fdd7b4c3302c93f6833e338903ea77245eb510b4. A long time prior to that however, Francois posted 126fa4b9ca5d9d7cb7d46f779ad3bd3631ca387c, which expiclitly disabled the MaxSize setting due to the fact that the hardware behaved in odd ways when overlong frames were received on NIC's supported by this driver. This was mentioned in a security conference recently: http://events.ccc.de/congress/2009/Fahrplan//events/3596.en.html It seems that if we can't enable frame size filtering, then, as Eric correctly noticed, we can find ourselves DMA-ing too much data to a buffer, causing corruption. As a result is seems that we are forced to allocate a frame which is ready to handle a maximally sized receive. This obviously has performance issues with it, so to mitigate that issue, this patch does two things: 1) Raises the copybreak value to the frame allocation size, which should force appropriately sized packets to get allocated on rx, rather than a full new 16k buffer. 2) This patch only disables frame filtering initially (i.e., during the NIC open), changing the MTU results in ring buffer allocation of a size in relation to the new mtu (along with a warning indicating that this is dangerous). Because of item (2), individuals who can't cope with the performance hit (or can otherwise filter frames to prevent the bug), or who have hardware they are sure is unaffected by this issue, can manually lower the copybreak and reset the mtu such that performance is restored easily. Signed-off-by: Neil Horman Signed-off-by: David S. Miller --- drivers/net/r8169.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 7193afc00e4..96740051cdc 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -186,7 +186,12 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = { MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); -static int rx_copybreak = 200; +/* + * we set our copybreak very high so that we don't have + * to allocate 16k frames all the time (see note in + * rtl8169_open() + */ +static int rx_copybreak = 16383; static int use_dac; static struct { u32 msg_enable; @@ -3217,9 +3222,13 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) } static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, - struct net_device *dev) + unsigned int mtu) { - unsigned int max_frame = dev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; + unsigned int max_frame = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; + + if (max_frame != 16383) + printk(KERN_WARNING "WARNING! Changing of MTU on this NIC" + "May lead to frame reception errors!\n"); tp->rx_buf_sz = (max_frame > RX_BUF_SIZE) ? max_frame : RX_BUF_SIZE; } @@ -3231,7 +3240,17 @@ static int rtl8169_open(struct net_device *dev) int retval = -ENOMEM; - rtl8169_set_rxbufsize(tp, dev); + /* + * Note that we use a magic value here, its wierd I know + * its done because, some subset of rtl8169 hardware suffers from + * a problem in which frames received that are longer than + * the size set in RxMaxSize register return garbage sizes + * when received. To avoid this we need to turn off filtering, + * which is done by setting a value of 16383 in the RxMaxSize register + * and allocating 16k frames to handle the largest possible rx value + * thats what the magic math below does. + */ + rtl8169_set_rxbufsize(tp, 16383 - VLAN_ETH_HLEN - ETH_FCS_LEN); /* * Rx and Tx desscriptors needs 256 bytes alignment. @@ -3884,7 +3903,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) rtl8169_down(dev); - rtl8169_set_rxbufsize(tp, dev); + rtl8169_set_rxbufsize(tp, dev->mtu); ret = rtl8169_init_ring(dev); if (ret < 0) From de329820e920cd9cfbc2127cad26a37026260cce Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 29 Mar 2010 14:30:19 -0700 Subject: [PATCH 394/478] ext3: fix broken handling of EXT3_STATE_NEW In commit 9df93939b735 ("ext3: Use bitops to read/modify EXT3_I(inode)->i_state") ext3 changed its internal 'i_state' variable to use bitops for its state handling. However, unline the same ext4 change, it didn't actually change the name of the field when it changed the semantics of it. As a result, an old use of 'i_state' remained in fs/ext3/ialloc.c that initialized the field to EXT3_STATE_NEW. And that does not work _at_all_ when we're now working with individually named bits rather than values that get masked. So the code tried to mark the state to be new, but in actual fact set the field to EXT3_STATE_JDATA. Which makes no sense at all, and screws up all the code that checks whether the inode was newly allocated. In particular, it made the xattr code unhappy, and caused various random behavior, like apparently https://bugzilla.redhat.com/show_bug.cgi?id=577911 So fix the initialization, and rename the field to match ext4 so that we don't have this happen again. Cc: James Morris Cc: Stephen Smalley Cc: Daniel J Walsh Cc: Eric Paris Cc: Jan Kara Signed-off-by: Linus Torvalds --- fs/ext3/ialloc.c | 4 +++- fs/ext3/inode.c | 2 +- include/linux/ext3_fs.h | 6 +++--- include/linux/ext3_fs_i.h | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index ef9008b885b..0d0e97ed3ff 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -582,7 +582,9 @@ got: inode->i_generation = sbi->s_next_generation++; spin_unlock(&sbi->s_next_gen_lock); - ei->i_state = EXT3_STATE_NEW; + ei->i_state_flags = 0; + ext3_set_inode_state(inode, EXT3_STATE_NEW); + ei->i_extra_isize = (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ? sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE : 0; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 7f920b7263a..ea33bdf0a30 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -2811,7 +2811,7 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino) inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime); inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0; - ei->i_state = 0; + ei->i_state_flags = 0; ei->i_dir_start_lookup = 0; ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); /* We now have enough fields to check if the inode was active or not. diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index cac84b00666..5f494b46509 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -565,17 +565,17 @@ enum { static inline int ext3_test_inode_state(struct inode *inode, int bit) { - return test_bit(bit, &EXT3_I(inode)->i_state); + return test_bit(bit, &EXT3_I(inode)->i_state_flags); } static inline void ext3_set_inode_state(struct inode *inode, int bit) { - set_bit(bit, &EXT3_I(inode)->i_state); + set_bit(bit, &EXT3_I(inode)->i_state_flags); } static inline void ext3_clear_inode_state(struct inode *inode, int bit) { - clear_bit(bit, &EXT3_I(inode)->i_state); + clear_bit(bit, &EXT3_I(inode)->i_state_flags); } #else /* Assume that user mode programs are passing in an ext3fs superblock, not diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h index 7679acdb519..f42c098aed8 100644 --- a/include/linux/ext3_fs_i.h +++ b/include/linux/ext3_fs_i.h @@ -87,7 +87,7 @@ struct ext3_inode_info { * near to their parent directory's inode. */ __u32 i_block_group; - unsigned long i_state; /* Dynamic state flags for ext3 */ + unsigned long i_state_flags; /* Dynamic state flags for ext3 */ /* block reservation info */ struct ext3_block_alloc_info *i_block_alloc_info; From 570b8fb505896e007fd3bb07573ba6640e51851d Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 30 Mar 2010 00:04:00 +0100 Subject: [PATCH 395/478] CRED: Fix memory leak in error handling Fix a memory leak on an OOM condition in prepare_usermodehelper_creds(). Signed-off-by: Mathieu Desnoyers Signed-off-by: David Howells Signed-off-by: James Morris --- kernel/cred.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/cred.c b/kernel/cred.c index 1ed8ca18790..1b1129d0cce 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -364,7 +364,7 @@ struct cred *prepare_usermodehelper_creds(void) new = kmem_cache_alloc(cred_jar, GFP_ATOMIC); if (!new) - return NULL; + goto free_tgcred; kdebug("prepare_usermodehelper_creds() alloc %p", new); @@ -397,6 +397,10 @@ struct cred *prepare_usermodehelper_creds(void) error: put_cred(new); +free_tgcred: +#ifdef CONFIG_KEYS + kfree(tgcred); +#endif return NULL; } From e971461fc59e3823e1b8a01379ce55c3d2d89c31 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Mar 2010 23:42:09 +0100 Subject: [PATCH 396/478] KEYS: Add MAINTAINERS record Add a MAINTAINERS record for the key management facility. Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 088bd41ac71..3d29fa38988 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3270,6 +3270,16 @@ S: Maintained F: include/linux/kexec.h F: kernel/kexec.c +KEYS/KEYRINGS: +M: David Howells +L: keyrings@linux-nfs.org +S: Maintained +F: Documentation/keys.txt +F: include/linux/key.h +F: include/linux/key-type.h +F: include/keys/ +F: security/keys/ + KGDB M: Jason Wessel L: kgdb-bugreport@lists.sourceforge.net From 2eaa9cfdf33b8d7fb7aff27792192e0019ae8fc6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 30 Mar 2010 09:24:39 -0700 Subject: [PATCH 397/478] Linux 2.6.34-rc3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a5ba759e0fd..67c1001cfbf 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 34 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Man-Eating Seals of Antiquity # *DOCUMENTATION* From 29fb52ca78b4e265ec6c626b0c7b2927953949cf Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 11 Mar 2010 10:01:17 -0500 Subject: [PATCH 398/478] drm/radeon/kms: expose thermal/fan i2c buses Look up i2c bus in the power table and expose it. You'll need to load a hwmon driver for any chips on the bus, this patch just exposes the bus. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/evergreen.c | 1 + drivers/gpu/drm/radeon/r100.c | 1 + drivers/gpu/drm/radeon/r300.c | 1 + drivers/gpu/drm/radeon/r420.c | 1 + drivers/gpu/drm/radeon/r600.c | 1 + drivers/gpu/drm/radeon/radeon.h | 2 + drivers/gpu/drm/radeon/radeon_atombios.c | 51 ++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_pm.c | 6 +++ drivers/gpu/drm/radeon/rs400.c | 1 + drivers/gpu/drm/radeon/rs600.c | 1 + drivers/gpu/drm/radeon/rs690.c | 1 + drivers/gpu/drm/radeon/rv515.c | 1 + drivers/gpu/drm/radeon/rv770.c | 1 + 13 files changed, 69 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 9d6283e26e8..db78d93f7f2 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -747,6 +747,7 @@ int evergreen_init(struct radeon_device *rdev) void evergreen_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); evergreen_suspend(rdev); #if 0 r600_blit_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index ea5ebfefd5e..9d634c8a322 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3443,6 +3443,7 @@ int r100_suspend(struct radeon_device *rdev) void r100_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 1042cead4a6..6d75f811796 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -1335,6 +1335,7 @@ int r300_suspend(struct radeon_device *rdev) void r300_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 2ab35ff41ec..0b8603ca697 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -267,6 +267,7 @@ int r420_suspend(struct radeon_device *rdev) void r420_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 5b00d5e86b8..5aee7fe4717 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2120,6 +2120,7 @@ int r600_init(struct radeon_device *rdev) void r600_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r600_audio_fini(rdev); r600_blit_fini(rdev); r600_cp_fini(rdev); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index bd63f537070..46bfff93250 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -168,6 +168,7 @@ struct radeon_clock { * Power management */ int radeon_pm_init(struct radeon_device *rdev); +void radeon_pm_fini(struct radeon_device *rdev); void radeon_pm_compute_clocks(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); @@ -708,6 +709,7 @@ struct radeon_pm { struct radeon_power_state *requested_power_state; struct radeon_pm_clock_info *requested_clock_mode; struct radeon_power_state *default_power_state; + struct radeon_i2c_chan *i2c_bus; }; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index e4540b2b859..815116e38aa 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1461,6 +1461,30 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) return tv_dac; } +static const char *thermal_controller_names[] = { + "NONE", + "LM63", + "ADM1032", + "ADM1030", + "MUA6649", + "LM64", + "F75375", + "ASC7512", +}; + +static const char *pp_lib_thermal_controller_names[] = { + "NONE", + "LM63", + "ADM1032", + "ADM1030", + "MUA6649", + "LM64", + "F75375", + "RV6xx", + "RV770", + "ADT7473", +}; + union power_info { struct _ATOM_POWERPLAY_INFO info; struct _ATOM_POWERPLAY_INFO_V2 info_2; @@ -1480,6 +1504,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) struct _ATOM_PPLIB_STATE *power_state; int num_modes = 0, i, j; int state_index = 0, mode_index = 0; + struct radeon_i2c_bus_rec i2c_bus; atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); @@ -1489,6 +1514,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if (power_info) { if (frev < 4) { + /* add the i2c bus for thermal/fan chip */ + if (power_info->info.ucOverdriveThermalController > 0) { + DRM_INFO("Possible %s thermal controller at 0x%02x\n", + thermal_controller_names[power_info->info.ucOverdriveThermalController], + power_info->info.ucOverdriveControllerAddress >> 1); + i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine); + rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal"); + } num_modes = power_info->info.ucNumOfPowerModeEntries; if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; @@ -1698,6 +1731,24 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } } } else if (frev == 4) { + /* add the i2c bus for thermal/fan chip */ + /* no support for internal controller yet */ + if (power_info->info_4.sThermalController.ucType > 0) { + if ((power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) && + (power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV770)) { + DRM_INFO("Internal thermal controller %s fan control\n", + (power_info->info_4.sThermalController.ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + } else { + DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", + pp_lib_thermal_controller_names[power_info->info_4.sThermalController.ucType], + power_info->info_4.sThermalController.ucI2cAddress >> 1, + (power_info->info_4.sThermalController.ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info_4.sThermalController.ucI2cLine); + rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal"); + } + } for (i = 0; i < power_info->info_4.ucNumStates; i++) { mode_index = 0; power_state = (struct _ATOM_PPLIB_STATE *) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 4f37b524de7..6458d52be4e 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -257,6 +257,12 @@ int radeon_pm_init(struct radeon_device *rdev) return 0; } +void radeon_pm_fini(struct radeon_device *rdev) +{ + if (rdev->pm.i2c_bus) + radeon_i2c_destroy(rdev->pm.i2c_bus); +} + void radeon_pm_compute_clocks(struct radeon_device *rdev) { struct drm_device *ddev = rdev->ddev; diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 1240e7d9f77..850a90c6a13 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -454,6 +454,7 @@ int rs400_suspend(struct radeon_device *rdev) void rs400_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index e3410c90bd3..3630c165d9c 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -601,6 +601,7 @@ int rs600_suspend(struct radeon_device *rdev) void rs600_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index c39cb50377f..6c92ae3c184 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -658,6 +658,7 @@ int rs690_suspend(struct radeon_device *rdev) void rs690_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 26108b49e98..f85499fa196 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -540,6 +540,7 @@ void rv515_set_safe_registers(struct radeon_device *rdev) void rv515_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 1484d06aad6..2f917db49f2 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1165,6 +1165,7 @@ int rv770_init(struct radeon_device *rdev) void rv770_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r600_blit_fini(rdev); r600_cp_fini(rdev); r600_wb_fini(rdev); From 57f50d70e27f99a9a785c760b2123cdf6a68e2de Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 14 Mar 2010 16:31:36 -0400 Subject: [PATCH 399/478] drm/radeon/kms/pm: fix segfault in clock code Make sure we have a crtc assigned to the encoder before dereferencing it. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 6458d52be4e..a4b57493aa7 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -279,7 +279,8 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) list_for_each_entry(connector, &ddev->mode_config.connector_list, head) { if (connector->encoder && - connector->dpms != DRM_MODE_DPMS_OFF) { + connector->encoder->crtc && + connector->dpms != DRM_MODE_DPMS_OFF) { radeon_crtc = to_radeon_crtc(connector->encoder->crtc); rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); ++count; From f867c60def7a8dcd86657fd38a8920a4354f305e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 5 Mar 2010 14:50:37 -0500 Subject: [PATCH 400/478] drm/radeon/kms: gfx init fixes for r6xx/r7xx This fixes some issues with the last gfx init patch. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 1 + drivers/gpu/drm/radeon/r600_cp.c | 3 +++ drivers/gpu/drm/radeon/rv770.c | 3 +++ 3 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 5aee7fe4717..d568262160e 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1133,6 +1133,7 @@ void r600_gpu_init(struct radeon_device *rdev) /* Setup pipes */ WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); + WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); tmp = R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8); WREG32(VGT_OUT_DEALLOC_CNTL, (tmp * 4) & DEALLOC_DIST_MASK); diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 40416c068d9..68e6f434930 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -1548,10 +1548,13 @@ static void r700_gfx_init(struct drm_device *dev, RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); + RADEON_WRITE(R600_GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); RADEON_WRITE(R700_CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); RADEON_WRITE(R700_CGTS_SYS_TCC_DISABLE, 0); RADEON_WRITE(R700_CGTS_TCC_DISABLE, 0); + RADEON_WRITE(R700_CGTS_USER_SYS_TCC_DISABLE, 0); + RADEON_WRITE(R700_CGTS_USER_TCC_DISABLE, 0); num_qd_pipes = R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK) >> 8); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 2f917db49f2..86d39cb35fe 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -648,10 +648,13 @@ static void rv770_gpu_init(struct radeon_device *rdev) WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); + WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); WREG32(CGTS_SYS_TCC_DISABLE, 0); WREG32(CGTS_TCC_DISABLE, 0); + WREG32(CGTS_USER_SYS_TCC_DISABLE, 0); + WREG32(CGTS_USER_TCC_DISABLE, 0); num_qd_pipes = R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8); From 06abdb0ec6b91f634631404012c4d646389e9e0b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 15 Mar 2010 01:36:32 -0400 Subject: [PATCH 401/478] drm/radeon/kms/pm: fix typo in power table parsing Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 815116e38aa..92e68869716 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1734,7 +1734,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) /* add the i2c bus for thermal/fan chip */ /* no support for internal controller yet */ if (power_info->info_4.sThermalController.ucType > 0) { - if ((power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) && + if ((power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) || (power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV770)) { DRM_INFO("Internal thermal controller %s fan control\n", (power_info->info_4.sThermalController.ucFanParameters & From 9e7b414edbf5e037c1462bbd8676465ed2ae0ac3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Mar 2010 17:08:06 -0400 Subject: [PATCH 402/478] drm/radeon/kms: init rdev->num_crtc at asic init Replace hardcoded numbers with rdev->num_crtc. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_asic.c | 10 ++++++++++ drivers/gpu/drm/radeon/radeon_display.c | 9 --------- drivers/gpu/drm/radeon/radeon_irq_kms.c | 14 ++++++-------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 6d2a5457c2c..dd23dcfbde1 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -700,6 +700,16 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->asic->set_memory_clock = NULL; } + /* set the number of crtcs */ + if (rdev->flags & RADEON_SINGLE_CRTC) + rdev->num_crtc = 1; + else { + if (ASIC_IS_DCE4(rdev)) + rdev->num_crtc = 6; + else + rdev->num_crtc = 2; + } + return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index ff5f09953c0..d65931d2e77 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1003,15 +1003,6 @@ int radeon_modeset_init(struct radeon_device *rdev) radeon_combios_check_hardcoded_edid(rdev); } - if (rdev->flags & RADEON_SINGLE_CRTC) - rdev->num_crtc = 1; - else { - if (ASIC_IS_DCE4(rdev)) - rdev->num_crtc = 6; - else - rdev->num_crtc = 2; - } - /* allocate crtcs */ for (i = 0; i < rdev->num_crtc; i++) { radeon_crtc_init(rdev->ddev, i); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 3cfd60fd008..68519b406ca 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -67,9 +67,10 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ rdev->irq.sw_int = false; - for (i = 0; i < 2; i++) { + for (i = 0; i < rdev->num_crtc; i++) rdev->irq.crtc_vblank_int[i] = false; - } + for (i = 0; i < 6; i++) + rdev->irq.hpd[i] = false; radeon_irq_set(rdev); /* Clear bits */ radeon_irq_process(rdev); @@ -95,22 +96,19 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) } /* Disable *all* interrupts */ rdev->irq.sw_int = false; - for (i = 0; i < 2; i++) { + for (i = 0; i < rdev->num_crtc; i++) rdev->irq.crtc_vblank_int[i] = false; + for (i = 0; i < 6; i++) rdev->irq.hpd[i] = false; - } radeon_irq_set(rdev); } int radeon_irq_kms_init(struct radeon_device *rdev) { int r = 0; - int num_crtc = 2; - if (rdev->flags & RADEON_SINGLE_CRTC) - num_crtc = 1; spin_lock_init(&rdev->irq.sw_lock); - r = drm_vblank_init(rdev->ddev, num_crtc); + r = drm_vblank_init(rdev->ddev, rdev->num_crtc); if (r) { return r; } From f47299c55a837af1727bc601e1fc0fa33adaeda5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Mar 2010 20:54:38 -0400 Subject: [PATCH 403/478] drm/radeon/kms: display watermark fixes - rs780/880 were using the wrong bandwidth functions - convert r1xx-r4xx to use the same pm sclk/mclk structs as r5xx+ - move bandwidth setup to a common function Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 9 ++---- drivers/gpu/drm/radeon/r100.c | 8 ++--- drivers/gpu/drm/radeon/r300.c | 1 + drivers/gpu/drm/radeon/r520.c | 8 +---- drivers/gpu/drm/radeon/r600.c | 9 ++---- drivers/gpu/drm/radeon/radeon.h | 2 ++ drivers/gpu/drm/radeon/radeon_asic.c | 41 +++++++++++++++++++++++++- drivers/gpu/drm/radeon/radeon_device.c | 30 +++++++++++++++++++ drivers/gpu/drm/radeon/rs600.c | 2 ++ drivers/gpu/drm/radeon/rs690.c | 11 +------ drivers/gpu/drm/radeon/rv515.c | 8 +---- drivers/gpu/drm/radeon/rv770.c | 9 ++---- 12 files changed, 87 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index db78d93f7f2..647a0efdc35 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -437,7 +437,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) int evergreen_mc_init(struct radeon_device *rdev) { - fixed20_12 a; u32 tmp; int chansize, numchan; @@ -482,12 +481,8 @@ int evergreen_mc_init(struct radeon_device *rdev) rdev->mc.real_vram_size = rdev->mc.aper_size; } r600_vram_gtt_location(rdev, &rdev->mc); - /* FIXME: we should enforce default clock in case GPU is not in - * default setup - */ - a.full = rfixed_const(100); - rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); - rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); + radeon_update_bandwidth_info(rdev); + return 0; } diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 9d634c8a322..e35cf193282 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2025,6 +2025,7 @@ void r100_mc_init(struct radeon_device *rdev) radeon_vram_location(rdev, &rdev->mc, base); if (!(rdev->flags & RADEON_IS_AGP)) radeon_gtt_location(rdev, &rdev->mc); + radeon_update_bandwidth_info(rdev); } @@ -2416,11 +2417,8 @@ void r100_bandwidth_update(struct radeon_device *rdev) /* * determine is there is enough bw for current mode */ - mclk_ff.full = rfixed_const(rdev->clock.default_mclk); - temp_ff.full = rfixed_const(100); - mclk_ff.full = rfixed_div(mclk_ff, temp_ff); - sclk_ff.full = rfixed_const(rdev->clock.default_sclk); - sclk_ff.full = rfixed_div(sclk_ff, temp_ff); + sclk_ff = rdev->pm.sclk; + mclk_ff = rdev->pm.mclk; temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); temp_ff.full = rfixed_const(temp); diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 6d75f811796..63fe2750f3a 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -482,6 +482,7 @@ void r300_mc_init(struct radeon_device *rdev) radeon_vram_location(rdev, &rdev->mc, base); if (!(rdev->flags & RADEON_IS_AGP)) radeon_gtt_location(rdev, &rdev->mc); + radeon_update_bandwidth_info(rdev); } void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes) diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index f6d8541ebb9..3c44b8d3931 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -122,19 +122,13 @@ static void r520_vram_get_type(struct radeon_device *rdev) void r520_mc_init(struct radeon_device *rdev) { - fixed20_12 a; r520_vram_get_type(rdev); r100_vram_init_sizes(rdev); radeon_vram_location(rdev, &rdev->mc, 0); if (!(rdev->flags & RADEON_IS_AGP)) radeon_gtt_location(rdev, &rdev->mc); - /* FIXME: we should enforce default clock in case GPU is not in - * default setup - */ - a.full = rfixed_const(100); - rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); - rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); + radeon_update_bandwidth_info(rdev); } void r520_mc_program(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d568262160e..1aac8bf4086 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -676,7 +676,6 @@ void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) int r600_mc_init(struct radeon_device *rdev) { - fixed20_12 a; u32 tmp; int chansize, numchan; @@ -720,14 +719,10 @@ int r600_mc_init(struct radeon_device *rdev) rdev->mc.real_vram_size = rdev->mc.aper_size; } r600_vram_gtt_location(rdev, &rdev->mc); - /* FIXME: we should enforce default clock in case GPU is not in - * default setup - */ - a.full = rfixed_const(100); - rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); - rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); + if (rdev->flags & RADEON_IS_IGP) rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); + radeon_update_bandwidth_info(rdev); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 46bfff93250..4ee5cb98956 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -699,6 +699,7 @@ struct radeon_pm { fixed20_12 ht_bandwidth; fixed20_12 core_bandwidth; fixed20_12 sclk; + fixed20_12 mclk; fixed20_12 needed_bandwidth; /* XXX: use a define for num power modes */ struct radeon_power_state power_state[8]; @@ -1179,6 +1180,7 @@ extern void radeon_gart_restore(struct radeon_device *rdev); extern int radeon_modeset_init(struct radeon_device *rdev); extern void radeon_modeset_fini(struct radeon_device *rdev); extern bool radeon_card_posted(struct radeon_device *rdev); +extern void radeon_update_bandwidth_info(struct radeon_device *rdev); extern bool radeon_boot_test_post_card(struct radeon_device *rdev); extern int radeon_clocks_init(struct radeon_device *rdev); extern void radeon_clocks_fini(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index dd23dcfbde1..a4b4bc9fa32 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -543,6 +543,43 @@ static struct radeon_asic r600_asic = { .ioctl_wait_idle = r600_ioctl_wait_idle, }; +static struct radeon_asic rs780_asic = { + .init = &r600_init, + .fini = &r600_fini, + .suspend = &r600_suspend, + .resume = &r600_resume, + .cp_commit = &r600_cp_commit, + .vga_set_state = &r600_vga_set_state, + .gpu_reset = &r600_gpu_reset, + .gart_tlb_flush = &r600_pcie_gart_tlb_flush, + .gart_set_page = &rs600_gart_set_page, + .ring_test = &r600_ring_test, + .ring_ib_execute = &r600_ring_ib_execute, + .irq_set = &r600_irq_set, + .irq_process = &r600_irq_process, + .get_vblank_counter = &rs600_get_vblank_counter, + .fence_ring_emit = &r600_fence_ring_emit, + .cs_parse = &r600_cs_parse, + .copy_blit = &r600_copy_blit, + .copy_dma = &r600_copy_blit, + .copy = &r600_copy_blit, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = NULL, + .set_memory_clock = NULL, + .get_pcie_lanes = NULL, + .set_pcie_lanes = NULL, + .set_clock_gating = NULL, + .set_surface_reg = r600_set_surface_reg, + .clear_surface_reg = r600_clear_surface_reg, + .bandwidth_update = &rs690_bandwidth_update, + .hpd_init = &r600_hpd_init, + .hpd_fini = &r600_hpd_fini, + .hpd_sense = &r600_hpd_sense, + .hpd_set_polarity = &r600_hpd_set_polarity, + .ioctl_wait_idle = r600_ioctl_wait_idle, +}; + static struct radeon_asic rv770_asic = { .init = &rv770_init, .fini = &rv770_fini, @@ -673,9 +710,11 @@ int radeon_asic_init(struct radeon_device *rdev) case CHIP_RV620: case CHIP_RV635: case CHIP_RV670: + rdev->asic = &r600_asic; + break; case CHIP_RS780: case CHIP_RS880: - rdev->asic = &r600_asic; + rdev->asic = &rs780_asic; break; case CHIP_RV770: case CHIP_RV730: diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 581b75ad6ce..6bedc2117f7 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -241,6 +241,36 @@ bool radeon_card_posted(struct radeon_device *rdev) } +void radeon_update_bandwidth_info(struct radeon_device *rdev) +{ + fixed20_12 a; + u32 sclk, mclk; + + if (rdev->flags & RADEON_IS_IGP) { + sclk = radeon_get_engine_clock(rdev); + mclk = rdev->clock.default_mclk; + + a.full = rfixed_const(100); + rdev->pm.sclk.full = rfixed_const(sclk); + rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); + rdev->pm.mclk.full = rfixed_const(mclk); + rdev->pm.mclk.full = rfixed_div(rdev->pm.mclk, a); + + a.full = rfixed_const(16); + /* core_bandwidth = sclk(Mhz) * 16 */ + rdev->pm.core_bandwidth.full = rfixed_div(rdev->pm.sclk, a); + } else { + sclk = radeon_get_engine_clock(rdev); + mclk = radeon_get_memory_clock(rdev); + + a.full = rfixed_const(100); + rdev->pm.sclk.full = rfixed_const(sclk); + rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); + rdev->pm.mclk.full = rfixed_const(mclk); + rdev->pm.mclk.full = rfixed_div(rdev->pm.mclk, a); + } +} + bool radeon_boot_test_post_card(struct radeon_device *rdev) { if (radeon_card_posted(rdev)) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 3630c165d9c..df7a855c18e 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -475,8 +475,10 @@ void rs600_mc_init(struct radeon_device *rdev) rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); base = RREG32_MC(R_000004_MC_FB_LOCATION); base = G_000004_MC_FB_START(base) << 16; + rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); radeon_vram_location(rdev, &rdev->mc, base); radeon_gtt_location(rdev, &rdev->mc); + radeon_update_bandwidth_info(rdev); } void rs600_bandwidth_update(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 6c92ae3c184..e356935b028 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -132,7 +132,6 @@ void rs690_pm_info(struct radeon_device *rdev) void rs690_mc_init(struct radeon_device *rdev) { - fixed20_12 a; u64 base; rs400_gart_adjust_size(rdev); @@ -146,18 +145,10 @@ void rs690_mc_init(struct radeon_device *rdev) base = RREG32_MC(R_000100_MCCFG_FB_LOCATION); base = G_000100_MC_FB_START(base) << 16; rs690_pm_info(rdev); - /* FIXME: we should enforce default clock in case GPU is not in - * default setup - */ - a.full = rfixed_const(100); - rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); - rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); - a.full = rfixed_const(16); - /* core_bandwidth = sclk(Mhz) * 16 */ - rdev->pm.core_bandwidth.full = rfixed_div(rdev->pm.sclk, a); rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); radeon_vram_location(rdev, &rdev->mc, base); radeon_gtt_location(rdev, &rdev->mc); + radeon_update_bandwidth_info(rdev); } void rs690_line_buffer_adjust(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index f85499fa196..d94291add6d 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -280,19 +280,13 @@ static void rv515_vram_get_type(struct radeon_device *rdev) void rv515_mc_init(struct radeon_device *rdev) { - fixed20_12 a; rv515_vram_get_type(rdev); r100_vram_init_sizes(rdev); radeon_vram_location(rdev, &rdev->mc, 0); if (!(rdev->flags & RADEON_IS_AGP)) radeon_gtt_location(rdev, &rdev->mc); - /* FIXME: we should enforce default clock in case GPU is not in - * default setup - */ - a.full = rfixed_const(100); - rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); - rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); + radeon_update_bandwidth_info(rdev); } uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 86d39cb35fe..ef946a3af74 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -868,7 +868,6 @@ static void rv770_gpu_init(struct radeon_device *rdev) int rv770_mc_init(struct radeon_device *rdev) { - fixed20_12 a; u32 tmp; int chansize, numchan; @@ -912,12 +911,8 @@ int rv770_mc_init(struct radeon_device *rdev) rdev->mc.real_vram_size = rdev->mc.aper_size; } r600_vram_gtt_location(rdev, &rdev->mc); - /* FIXME: we should enforce default clock in case GPU is not in - * default setup - */ - a.full = rfixed_const(100); - rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); - rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); + radeon_update_bandwidth_info(rdev); + return 0; } From f95df9ca6896978108201a77422a1ae2cdc595ec Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 21 Mar 2010 14:02:25 -0400 Subject: [PATCH 404/478] drm/radeon/kms: never treat rs4xx as AGP RS4xx+ IGP chips use an internal gart, however, some of them have the agp cap bits set in their pci configs. Make sure to clear the AGP flag as AGP will not work with them. Should fix fdo bug 27225 Signed-off-by: Alex Deucher cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_device.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 6bedc2117f7..60ec47b7164 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -562,6 +562,14 @@ int radeon_device_init(struct radeon_device *rdev, return r; radeon_check_arguments(rdev); + /* all of the newer IGP chips have an internal gart + * However some rs4xx report as AGP, so remove that here. + */ + if ((rdev->family >= CHIP_RS400) && + (rdev->flags & RADEON_IS_IGP)) { + rdev->flags &= ~RADEON_IS_AGP; + } + if (rdev->flags & RADEON_IS_AGP && radeon_agpmode == -1) { radeon_agp_disable(rdev); } From b2f8ccd84059f7d0c3e4f67d577abca391bc1868 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 21 Mar 2010 11:09:24 -0400 Subject: [PATCH 405/478] drm/radeon/kms: fix display bandwidth setup on rs4xx I missed rs4xx in 7f1e613daf0fdd0884316ab25a749db3c671329e Fixes fdo bug 27219. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/rs400.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 850a90c6a13..18d6efb8907 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -265,6 +265,7 @@ void rs400_mc_init(struct radeon_device *rdev) base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16; radeon_vram_location(rdev, &rdev->mc, base); radeon_gtt_location(rdev, &rdev->mc); + radeon_update_bandwidth_info(rdev); } uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg) From c1bcad9d16831859373d8f579fa1e146409f9960 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Mar 2010 19:50:59 -0400 Subject: [PATCH 406/478] drm/radeon/kms: remove lvds quirks - no longer needed with the latest new pll algo fixes. - also don't use lcd pll limits. They don't seem to work well for all systems. If we have a case where they are useful, we can set the flag for that case. fixes fdo bug 27083 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 6 ------ drivers/gpu/drm/radeon/radeon_atombios.c | 27 ------------------------ 2 files changed, 33 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 7c30e2e74c8..94aa6b293e0 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -521,12 +521,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) adjusted_clock = mode->clock * 2; - /* LVDS PLL quirks */ - if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - pll->algo = dig->pll_algo; - pll->flags |= RADEON_PLL_IS_LCD; - } } else { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 92e68869716..3733cb78779 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1128,30 +1128,6 @@ static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct return ss; } -static void radeon_atom_apply_lvds_quirks(struct drm_device *dev, - struct radeon_encoder_atom_dig *lvds) -{ - - /* Toshiba A300-1BU laptop panel doesn't like new pll divider algo */ - if ((dev->pdev->device == 0x95c4) && - (dev->pdev->subsystem_vendor == 0x1179) && - (dev->pdev->subsystem_device == 0xff50)) { - if ((lvds->native_mode.hdisplay == 1280) && - (lvds->native_mode.vdisplay == 800)) - lvds->pll_algo = PLL_ALGO_LEGACY; - } - - /* Dell Studio 15 laptop panel doesn't like new pll divider algo */ - if ((dev->pdev->device == 0x95c4) && - (dev->pdev->subsystem_vendor == 0x1028) && - (dev->pdev->subsystem_device == 0x029f)) { - if ((lvds->native_mode.hdisplay == 1280) && - (lvds->native_mode.vdisplay == 800)) - lvds->pll_algo = PLL_ALGO_LEGACY; - } - -} - union lvds_info { struct _ATOM_LVDS_INFO info; struct _ATOM_LVDS_INFO_V12 info_12; @@ -1234,9 +1210,6 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct lvds->pll_algo = PLL_ALGO_LEGACY; } - /* LVDS quirks */ - radeon_atom_apply_lvds_quirks(dev, lvds); - encoder->native_mode = lvds->native_mode; } return lvds; From a084e6ee6e64a76f1a9665d527203cdab7d6048f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Mar 2010 01:04:01 -0400 Subject: [PATCH 407/478] drm/radeon/kms/atom: make sure tables are valid (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that atom cmd and data tables are valid before using them. (v2) - fix some whitespace errors noticed by Rafał Miłecki - check a few more cases Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 32 ++- drivers/gpu/drm/radeon/atom.h | 6 +- drivers/gpu/drm/radeon/atombios_crtc.c | 15 +- drivers/gpu/drm/radeon/radeon_atombios.c | 347 +++++++++++------------ drivers/gpu/drm/radeon/radeon_display.c | 5 +- drivers/gpu/drm/radeon/radeon_encoders.c | 15 +- drivers/gpu/drm/radeon/rs690.c | 74 +++-- 7 files changed, 262 insertions(+), 232 deletions(-) diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index b7fe660985c..247f8ee7e94 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -1295,12 +1295,16 @@ void atom_destroy(struct atom_context *ctx) kfree(ctx); } -void atom_parse_data_header(struct atom_context *ctx, int index, +bool atom_parse_data_header(struct atom_context *ctx, int index, uint16_t * size, uint8_t * frev, uint8_t * crev, uint16_t * data_start) { int offset = index * 2 + 4; int idx = CU16(ctx->data_table + offset); + u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4); + + if (!mdt[index]) + return false; if (size) *size = CU16(idx); @@ -1309,38 +1313,42 @@ void atom_parse_data_header(struct atom_context *ctx, int index, if (crev) *crev = CU8(idx + 3); *data_start = idx; - return; + return true; } -void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, +bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, uint8_t * crev) { int offset = index * 2 + 4; int idx = CU16(ctx->cmd_table + offset); + u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4); + + if (!mct[index]) + return false; if (frev) *frev = CU8(idx + 2); if (crev) *crev = CU8(idx + 3); - return; + return true; } int atom_allocate_fb_scratch(struct atom_context *ctx) { int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware); uint16_t data_offset; - int usage_bytes; + int usage_bytes = 0; struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage; - atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset); + if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) { + firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset); - firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset); + DRM_DEBUG("atom firmware requested %08x %dkb\n", + firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware, + firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb); - DRM_DEBUG("atom firmware requested %08x %dkb\n", - firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware, - firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb); - - usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024; + usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024; + } if (usage_bytes == 0) usage_bytes = 20 * 1024; /* allocate some scratch memory */ diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h index 1b262631480..cd1b64ab5ca 100644 --- a/drivers/gpu/drm/radeon/atom.h +++ b/drivers/gpu/drm/radeon/atom.h @@ -143,8 +143,10 @@ struct atom_context *atom_parse(struct card_info *, void *); int atom_execute_table(struct atom_context *, int, uint32_t *); int atom_asic_init(struct atom_context *); void atom_destroy(struct atom_context *); -void atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start); -void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev, uint8_t *crev); +bool atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, + uint8_t *frev, uint8_t *crev, uint16_t *data_start); +bool atom_parse_cmd_header(struct atom_context *ctx, int index, + uint8_t *frev, uint8_t *crev); int atom_allocate_fb_scratch(struct atom_context *ctx); #include "atom-types.h" #include "atombios.h" diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 94aa6b293e0..56107b3a997 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -541,8 +541,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, int index; index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); - atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, - &crev); + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, + &crev)) + return adjusted_clock; memset(&args, 0, sizeof(args)); @@ -630,8 +631,9 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc) memset(&args, 0, sizeof(args)); index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); - atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, - &crev); + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, + &crev)) + return; switch (frev) { case 1: @@ -705,8 +707,9 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode &ref_div, &post_div); index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); - atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, - &crev); + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, + &crev)) + return; switch (frev) { case 1: diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 3733cb78779..f0ea7f8da67 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -75,46 +75,45 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec)); i2c.valid = false; - atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset); + if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) { + i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); - i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); + for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { + gpio = &i2c_info->asGPIO_Info[i]; + if (gpio->sucI2cId.ucAccess == id) { + i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; + i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; + i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; + i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4; + i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4; + i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4; + i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4; + i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4; + i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift); + i2c.mask_data_mask = (1 << gpio->ucDataMaskShift); + i2c.en_clk_mask = (1 << gpio->ucClkEnShift); + i2c.en_data_mask = (1 << gpio->ucDataEnShift); + i2c.y_clk_mask = (1 << gpio->ucClkY_Shift); + i2c.y_data_mask = (1 << gpio->ucDataY_Shift); + i2c.a_clk_mask = (1 << gpio->ucClkA_Shift); + i2c.a_data_mask = (1 << gpio->ucDataA_Shift); - for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { - gpio = &i2c_info->asGPIO_Info[i]; + if (gpio->sucI2cId.sbfAccess.bfHW_Capable) + i2c.hw_capable = true; + else + i2c.hw_capable = false; - if (gpio->sucI2cId.ucAccess == id) { - i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; - i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; - i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; - i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4; - i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4; - i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4; - i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4; - i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4; - i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift); - i2c.mask_data_mask = (1 << gpio->ucDataMaskShift); - i2c.en_clk_mask = (1 << gpio->ucClkEnShift); - i2c.en_data_mask = (1 << gpio->ucDataEnShift); - i2c.y_clk_mask = (1 << gpio->ucClkY_Shift); - i2c.y_data_mask = (1 << gpio->ucDataY_Shift); - i2c.a_clk_mask = (1 << gpio->ucClkA_Shift); - i2c.a_data_mask = (1 << gpio->ucDataA_Shift); + if (gpio->sucI2cId.ucAccess == 0xa0) + i2c.mm_i2c = true; + else + i2c.mm_i2c = false; - if (gpio->sucI2cId.sbfAccess.bfHW_Capable) - i2c.hw_capable = true; - else - i2c.hw_capable = false; + i2c.i2c_id = gpio->sucI2cId.ucAccess; - if (gpio->sucI2cId.ucAccess == 0xa0) - i2c.mm_i2c = true; - else - i2c.mm_i2c = false; - - i2c.i2c_id = gpio->sucI2cId.ucAccess; - - i2c.valid = true; - break; + i2c.valid = true; + break; + } } } @@ -135,20 +134,21 @@ static inline struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rd memset(&gpio, 0, sizeof(struct radeon_gpio_rec)); gpio.valid = false; - atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset); + if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) { + gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset); - gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset); + num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / + sizeof(ATOM_GPIO_PIN_ASSIGNMENT); - num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_GPIO_PIN_ASSIGNMENT); - - for (i = 0; i < num_indices; i++) { - pin = &gpio_info->asGPIO_Pin[i]; - if (id == pin->ucGPIO_ID) { - gpio.id = pin->ucGPIO_ID; - gpio.reg = pin->usGpioPin_AIndex * 4; - gpio.mask = (1 << pin->ucGpioPinBitShift); - gpio.valid = true; - break; + for (i = 0; i < num_indices; i++) { + pin = &gpio_info->asGPIO_Pin[i]; + if (id == pin->ucGPIO_ID) { + gpio.id = pin->ucGPIO_ID; + gpio.reg = pin->usGpioPin_AIndex * 4; + gpio.mask = (1 << pin->ucGpioPinBitShift); + gpio.valid = true; + break; + } } } @@ -395,9 +395,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) struct radeon_gpio_rec gpio; struct radeon_hpd hpd; - atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); - - if (data_offset == 0) + if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) return false; if (crev < 2) @@ -449,37 +447,43 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); - atom_parse_data_header(ctx, index, &size, &frev, - &crev, &igp_offset); + if (atom_parse_data_header(ctx, index, &size, &frev, + &crev, &igp_offset)) { - if (crev >= 2) { - igp_obj = - (ATOM_INTEGRATED_SYSTEM_INFO_V2 - *) (ctx->bios + igp_offset); + if (crev >= 2) { + igp_obj = + (ATOM_INTEGRATED_SYSTEM_INFO_V2 + *) (ctx->bios + igp_offset); - if (igp_obj) { - uint32_t slot_config, ct; + if (igp_obj) { + uint32_t slot_config, ct; - if (con_obj_num == 1) - slot_config = - igp_obj-> - ulDDISlot1Config; - else - slot_config = - igp_obj-> - ulDDISlot2Config; + if (con_obj_num == 1) + slot_config = + igp_obj-> + ulDDISlot1Config; + else + slot_config = + igp_obj-> + ulDDISlot2Config; - ct = (slot_config >> 16) & 0xff; - connector_type = - object_connector_convert - [ct]; - connector_object_id = ct; - igp_lane_info = - slot_config & 0xffff; + ct = (slot_config >> 16) & 0xff; + connector_type = + object_connector_convert + [ct]; + connector_object_id = ct; + igp_lane_info = + slot_config & 0xffff; + } else + continue; } else continue; - } else - continue; + } else { + igp_lane_info = 0; + connector_type = + object_connector_convert[con_obj_id]; + connector_object_id = con_obj_id; + } } else { igp_lane_info = 0; connector_type = @@ -627,20 +631,23 @@ static uint16_t atombios_get_connector_object_id(struct drm_device *dev, uint8_t frev, crev; ATOM_XTMDS_INFO *xtmds; - atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); - xtmds = (ATOM_XTMDS_INFO *)(ctx->bios + data_offset); + if (atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) { + xtmds = (ATOM_XTMDS_INFO *)(ctx->bios + data_offset); - if (xtmds->ucSupportedLink & ATOM_XTMDS_SUPPORTED_DUALLINK) { - if (connector_type == DRM_MODE_CONNECTOR_DVII) - return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I; - else - return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D; - } else { - if (connector_type == DRM_MODE_CONNECTOR_DVII) - return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I; - else - return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D; - } + if (xtmds->ucSupportedLink & ATOM_XTMDS_SUPPORTED_DUALLINK) { + if (connector_type == DRM_MODE_CONNECTOR_DVII) + return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I; + else + return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D; + } else { + if (connector_type == DRM_MODE_CONNECTOR_DVII) + return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I; + else + return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D; + } + } else + return supported_devices_connector_object_id_convert + [connector_type]; } else { return supported_devices_connector_object_id_convert [connector_type]; @@ -672,7 +679,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct int i, j, max_device; struct bios_connector bios_connectors[ATOM_MAX_SUPPORTED_DEVICE]; - atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); + if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) + return false; supported_devices = (union atom_supported_devices *)(ctx->bios + data_offset); @@ -865,14 +873,11 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) struct radeon_pll *mpll = &rdev->clock.mpll; uint16_t data_offset; - atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, - &crev, &data_offset); - - firmware_info = - (union firmware_info *)(mode_info->atom_context->bios + - data_offset); - - if (firmware_info) { + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + firmware_info = + (union firmware_info *)(mode_info->atom_context->bios + + data_offset); /* pixel clocks */ p1pll->reference_freq = le16_to_cpu(firmware_info->info.usReferenceClock); @@ -1006,13 +1011,10 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev) u8 frev, crev; u16 data_offset; - atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, - &crev, &data_offset); - - igp_info = (union igp_info *)(mode_info->atom_context->bios + + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + igp_info = (union igp_info *)(mode_info->atom_context->bios + data_offset); - - if (igp_info) { switch (crev) { case 1: if (igp_info->info.ucMemoryType & 0xf0) @@ -1043,14 +1045,12 @@ bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder, uint16_t maxfreq; int i; - atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, - &crev, &data_offset); + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + tmds_info = + (struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios + + data_offset); - tmds_info = - (struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios + - data_offset); - - if (tmds_info) { maxfreq = le16_to_cpu(tmds_info->usMaxFrequency); for (i = 0; i < 4; i++) { tmds->tmds_pll[i].freq = @@ -1099,13 +1099,11 @@ static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct if (id > ATOM_MAX_SS_ENTRY) return NULL; - atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, - &crev, &data_offset); + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + ss_info = + (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset); - ss_info = - (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset); - - if (ss_info) { ss = kzalloc(sizeof(struct radeon_atom_ss), GFP_KERNEL); @@ -1146,13 +1144,10 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct uint8_t frev, crev; struct radeon_encoder_atom_dig *lvds = NULL; - atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, - &crev, &data_offset); - - lvds_info = - (union lvds_info *)(mode_info->atom_context->bios + data_offset); - - if (lvds_info) { + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + lvds_info = + (union lvds_info *)(mode_info->atom_context->bios + data_offset); lvds = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); @@ -1228,11 +1223,11 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder) uint8_t bg, dac; struct radeon_encoder_primary_dac *p_dac = NULL; - atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + dac_info = (struct _COMPASSIONATE_DATA *) + (mode_info->atom_context->bios + data_offset); - dac_info = (struct _COMPASSIONATE_DATA *)(mode_info->atom_context->bios + data_offset); - - if (dac_info) { p_dac = kzalloc(sizeof(struct radeon_encoder_primary_dac), GFP_KERNEL); if (!p_dac) @@ -1257,7 +1252,9 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, u8 frev, crev; u16 data_offset, misc; - atom_parse_data_header(mode_info->atom_context, data_index, NULL, &frev, &crev, &data_offset); + if (!atom_parse_data_header(mode_info->atom_context, data_index, NULL, + &frev, &crev, &data_offset)) + return false; switch (crev) { case 1: @@ -1349,47 +1346,50 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev) struct _ATOM_ANALOG_TV_INFO *tv_info; enum radeon_tv_std tv_std = TV_STD_NTSC; - atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { - tv_info = (struct _ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset); + tv_info = (struct _ATOM_ANALOG_TV_INFO *) + (mode_info->atom_context->bios + data_offset); - switch (tv_info->ucTV_BootUpDefaultStandard) { - case ATOM_TV_NTSC: - tv_std = TV_STD_NTSC; - DRM_INFO("Default TV standard: NTSC\n"); - break; - case ATOM_TV_NTSCJ: - tv_std = TV_STD_NTSC_J; - DRM_INFO("Default TV standard: NTSC-J\n"); - break; - case ATOM_TV_PAL: - tv_std = TV_STD_PAL; - DRM_INFO("Default TV standard: PAL\n"); - break; - case ATOM_TV_PALM: - tv_std = TV_STD_PAL_M; - DRM_INFO("Default TV standard: PAL-M\n"); - break; - case ATOM_TV_PALN: - tv_std = TV_STD_PAL_N; - DRM_INFO("Default TV standard: PAL-N\n"); - break; - case ATOM_TV_PALCN: - tv_std = TV_STD_PAL_CN; - DRM_INFO("Default TV standard: PAL-CN\n"); - break; - case ATOM_TV_PAL60: - tv_std = TV_STD_PAL_60; - DRM_INFO("Default TV standard: PAL-60\n"); - break; - case ATOM_TV_SECAM: - tv_std = TV_STD_SECAM; - DRM_INFO("Default TV standard: SECAM\n"); - break; - default: - tv_std = TV_STD_NTSC; - DRM_INFO("Unknown TV standard; defaulting to NTSC\n"); - break; + switch (tv_info->ucTV_BootUpDefaultStandard) { + case ATOM_TV_NTSC: + tv_std = TV_STD_NTSC; + DRM_INFO("Default TV standard: NTSC\n"); + break; + case ATOM_TV_NTSCJ: + tv_std = TV_STD_NTSC_J; + DRM_INFO("Default TV standard: NTSC-J\n"); + break; + case ATOM_TV_PAL: + tv_std = TV_STD_PAL; + DRM_INFO("Default TV standard: PAL\n"); + break; + case ATOM_TV_PALM: + tv_std = TV_STD_PAL_M; + DRM_INFO("Default TV standard: PAL-M\n"); + break; + case ATOM_TV_PALN: + tv_std = TV_STD_PAL_N; + DRM_INFO("Default TV standard: PAL-N\n"); + break; + case ATOM_TV_PALCN: + tv_std = TV_STD_PAL_CN; + DRM_INFO("Default TV standard: PAL-CN\n"); + break; + case ATOM_TV_PAL60: + tv_std = TV_STD_PAL_60; + DRM_INFO("Default TV standard: PAL-60\n"); + break; + case ATOM_TV_SECAM: + tv_std = TV_STD_SECAM; + DRM_INFO("Default TV standard: SECAM\n"); + break; + default: + tv_std = TV_STD_NTSC; + DRM_INFO("Unknown TV standard; defaulting to NTSC\n"); + break; + } } return tv_std; } @@ -1407,11 +1407,12 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) uint8_t bg, dac; struct radeon_encoder_tv_dac *tv_dac = NULL; - atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { - dac_info = (struct _COMPASSIONATE_DATA *)(mode_info->atom_context->bios + data_offset); + dac_info = (struct _COMPASSIONATE_DATA *) + (mode_info->atom_context->bios + data_offset); - if (dac_info) { tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); if (!tv_dac) @@ -1479,13 +1480,11 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) int state_index = 0, mode_index = 0; struct radeon_i2c_bus_rec i2c_bus; - atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); - - power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); - rdev->pm.default_power_state = NULL; - if (power_info) { + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); if (frev < 4) { /* add the i2c bus for thermal/fan chip */ if (power_info->info.ucOverdriveThermalController > 0) { diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index d65931d2e77..eca714c381d 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -368,10 +368,9 @@ static bool radeon_setup_enc_conn(struct drm_device *dev) if (rdev->bios) { if (rdev->is_atom_bios) { - if (rdev->family >= CHIP_R600) + ret = radeon_get_atom_connector_info_from_supported_devices_table(dev); + if (ret == false) ret = radeon_get_atom_connector_info_from_object_table(dev); - else - ret = radeon_get_atom_connector_info_from_supported_devices_table(dev); } else { ret = radeon_get_legacy_connector_info_from_bios(dev); if (ret == false) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index a236c75496c..fd4052f71bf 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -519,7 +519,8 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) break; } - atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; switch (frev) { case 1: @@ -725,7 +726,8 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) } num = dig->dig_encoder + 1; - atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; args.v1.ucAction = action; args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); @@ -813,7 +815,8 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } } - atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; args.v1.ucAction = action; if (action == ATOM_TRANSMITTER_ACTION_INIT) { @@ -1103,7 +1106,8 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) memset(&args, 0, sizeof(args)); - atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; switch (frev) { case 1: @@ -1411,7 +1415,8 @@ atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *conn memset(&args, 0, sizeof(args)); - atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return false; args.sDacload.ucMisc = 0; diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index e356935b028..f758d5cc116 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -58,42 +58,57 @@ static void rs690_gpu_init(struct radeon_device *rdev) } } +union igp_info { + struct _ATOM_INTEGRATED_SYSTEM_INFO info; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_v2; +}; + void rs690_pm_info(struct radeon_device *rdev) { int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); - struct _ATOM_INTEGRATED_SYSTEM_INFO *info; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 *info_v2; - void *ptr; + union igp_info *info; uint16_t data_offset; uint8_t frev, crev; fixed20_12 tmp; - atom_parse_data_header(rdev->mode_info.atom_context, index, NULL, - &frev, &crev, &data_offset); - ptr = rdev->mode_info.atom_context->bios + data_offset; - info = (struct _ATOM_INTEGRATED_SYSTEM_INFO *)ptr; - info_v2 = (struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 *)ptr; - /* Get various system informations from bios */ - switch (crev) { - case 1: - tmp.full = rfixed_const(100); - rdev->pm.igp_sideport_mclk.full = rfixed_const(info->ulBootUpMemoryClock); - rdev->pm.igp_sideport_mclk.full = rfixed_div(rdev->pm.igp_sideport_mclk, tmp); - rdev->pm.igp_system_mclk.full = rfixed_const(le16_to_cpu(info->usK8MemoryClock)); - rdev->pm.igp_ht_link_clk.full = rfixed_const(le16_to_cpu(info->usFSBClock)); - rdev->pm.igp_ht_link_width.full = rfixed_const(info->ucHTLinkWidth); - break; - case 2: - tmp.full = rfixed_const(100); - rdev->pm.igp_sideport_mclk.full = rfixed_const(info_v2->ulBootUpSidePortClock); - rdev->pm.igp_sideport_mclk.full = rfixed_div(rdev->pm.igp_sideport_mclk, tmp); - rdev->pm.igp_system_mclk.full = rfixed_const(info_v2->ulBootUpUMAClock); - rdev->pm.igp_system_mclk.full = rfixed_div(rdev->pm.igp_system_mclk, tmp); - rdev->pm.igp_ht_link_clk.full = rfixed_const(info_v2->ulHTLinkFreq); - rdev->pm.igp_ht_link_clk.full = rfixed_div(rdev->pm.igp_ht_link_clk, tmp); - rdev->pm.igp_ht_link_width.full = rfixed_const(le16_to_cpu(info_v2->usMinHTLinkWidth)); - break; - default: + if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL, + &frev, &crev, &data_offset)) { + info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset); + + /* Get various system informations from bios */ + switch (crev) { + case 1: + tmp.full = rfixed_const(100); + rdev->pm.igp_sideport_mclk.full = rfixed_const(info->info.ulBootUpMemoryClock); + rdev->pm.igp_sideport_mclk.full = rfixed_div(rdev->pm.igp_sideport_mclk, tmp); + rdev->pm.igp_system_mclk.full = rfixed_const(le16_to_cpu(info->info.usK8MemoryClock)); + rdev->pm.igp_ht_link_clk.full = rfixed_const(le16_to_cpu(info->info.usFSBClock)); + rdev->pm.igp_ht_link_width.full = rfixed_const(info->info.ucHTLinkWidth); + break; + case 2: + tmp.full = rfixed_const(100); + rdev->pm.igp_sideport_mclk.full = rfixed_const(info->info_v2.ulBootUpSidePortClock); + rdev->pm.igp_sideport_mclk.full = rfixed_div(rdev->pm.igp_sideport_mclk, tmp); + rdev->pm.igp_system_mclk.full = rfixed_const(info->info_v2.ulBootUpUMAClock); + rdev->pm.igp_system_mclk.full = rfixed_div(rdev->pm.igp_system_mclk, tmp); + rdev->pm.igp_ht_link_clk.full = rfixed_const(info->info_v2.ulHTLinkFreq); + rdev->pm.igp_ht_link_clk.full = rfixed_div(rdev->pm.igp_ht_link_clk, tmp); + rdev->pm.igp_ht_link_width.full = rfixed_const(le16_to_cpu(info->info_v2.usMinHTLinkWidth)); + break; + default: + tmp.full = rfixed_const(100); + /* We assume the slower possible clock ie worst case */ + /* DDR 333Mhz */ + rdev->pm.igp_sideport_mclk.full = rfixed_const(333); + /* FIXME: system clock ? */ + rdev->pm.igp_system_mclk.full = rfixed_const(100); + rdev->pm.igp_system_mclk.full = rfixed_div(rdev->pm.igp_system_mclk, tmp); + rdev->pm.igp_ht_link_clk.full = rfixed_const(200); + rdev->pm.igp_ht_link_width.full = rfixed_const(8); + DRM_ERROR("No integrated system info for your GPU, using safe default\n"); + break; + } + } else { tmp.full = rfixed_const(100); /* We assume the slower possible clock ie worst case */ /* DDR 333Mhz */ @@ -104,7 +119,6 @@ void rs690_pm_info(struct radeon_device *rdev) rdev->pm.igp_ht_link_clk.full = rfixed_const(200); rdev->pm.igp_ht_link_width.full = rfixed_const(8); DRM_ERROR("No integrated system info for your GPU, using safe default\n"); - break; } /* Compute various bandwidth */ /* k8_bandwidth = (memory_clk / 2) * 2 * 8 * 0.5 = memory_clk * 4 */ From 97f23b3d85a4d734a8584dade3a34579931c8f8d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 19 Mar 2010 10:33:44 +1000 Subject: [PATCH 408/478] drm/radeon/kms: don't print error on -ERESTARTSYS. We can get this if the user moves the mouse when we are waiting to move some stuff around in the validate. Don't fail. Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 70ba02ed772..dd190f9315d 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -243,7 +243,8 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) } r = radeon_cs_parser_relocs(&parser); if (r) { - DRM_ERROR("Failed to parse relocation !\n"); + if (r != -ERESTARTSYS) + DRM_ERROR("Failed to parse relocation %d!\n", r); radeon_cs_parser_fini(&parser, r); mutex_unlock(&rdev->cs_mutex); return r; From f9274562026558ab54a29331cf13e9ebec8cc890 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 17 Mar 2010 14:44:29 +0000 Subject: [PATCH 409/478] drm/radeon/kms: avoid possible oops (call gart_fini before gart_disable) radeon_gart_fini might call GART unbind callback function which might try to access GART table but if gart_disable is call first the GART table will be unmapped so any access to it will oops. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 2 +- drivers/gpu/drm/radeon/r300.c | 2 +- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/rs400.c | 2 +- drivers/gpu/drm/radeon/rs600.c | 2 +- drivers/gpu/drm/radeon/rv770.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index e35cf193282..739a44783ef 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -236,9 +236,9 @@ int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) void r100_pci_gart_fini(struct radeon_device *rdev) { + radeon_gart_fini(rdev); r100_pci_gart_disable(rdev); radeon_gart_table_ram_free(rdev); - radeon_gart_fini(rdev); } int r100_irq_set(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 63fe2750f3a..1023eeb6587 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -165,9 +165,9 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev) void rv370_pcie_gart_fini(struct radeon_device *rdev) { + radeon_gart_fini(rdev); rv370_pcie_gart_disable(rdev); radeon_gart_table_vram_free(rdev); - radeon_gart_fini(rdev); } void r300_fence_ring_emit(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1aac8bf4086..518f8d335f3 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -492,9 +492,9 @@ void r600_pcie_gart_disable(struct radeon_device *rdev) void r600_pcie_gart_fini(struct radeon_device *rdev) { + radeon_gart_fini(rdev); r600_pcie_gart_disable(rdev); radeon_gart_table_vram_free(rdev); - radeon_gart_fini(rdev); } void r600_agp_enable(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 18d6efb8907..590815c4700 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -203,9 +203,9 @@ void rs400_gart_disable(struct radeon_device *rdev) void rs400_gart_fini(struct radeon_device *rdev) { + radeon_gart_fini(rdev); rs400_gart_disable(rdev); radeon_gart_table_ram_free(rdev); - radeon_gart_fini(rdev); } int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index df7a855c18e..30c4b46f352 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -268,9 +268,9 @@ void rs600_gart_disable(struct radeon_device *rdev) void rs600_gart_fini(struct radeon_device *rdev) { + radeon_gart_fini(rdev); rs600_gart_disable(rdev); radeon_gart_table_vram_free(rdev); - radeon_gart_fini(rdev); } #define R600_PTE_VALID (1 << 0) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index ef946a3af74..9f37d2efb0a 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -126,9 +126,9 @@ void rv770_pcie_gart_disable(struct radeon_device *rdev) void rv770_pcie_gart_fini(struct radeon_device *rdev) { + radeon_gart_fini(rdev); rv770_pcie_gart_disable(rdev); radeon_gart_table_vram_free(rdev); - radeon_gart_fini(rdev); } From fcbc451ba1948fba967198bd150ecbd10bbb7075 Mon Sep 17 00:00:00 2001 From: Pauli Nieminen Date: Fri, 19 Mar 2010 07:44:33 +0000 Subject: [PATCH 410/478] drm/radeon/kms: Fix NULL pointer dereference if memory allocation failed. When there is allocation failure in radeon_cs_parser_relocs parser->nrelocs is not cleaned. This causes NULL pointer defeference in radeon_cs_parser_fini when clean up code is trying to loop over the relocation array and free the objects. Fix adds a check for a possible NULL pointer in clean up code. Signed-off-by: Pauli Nieminen Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cs.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index dd190f9315d..f9b0fe002c0 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -193,9 +193,11 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error) radeon_bo_list_fence(&parser->validated, parser->ib->fence); } radeon_bo_list_unreserve(&parser->validated); - for (i = 0; i < parser->nrelocs; i++) { - if (parser->relocs[i].gobj) - drm_gem_object_unreference_unlocked(parser->relocs[i].gobj); + if (parser->relocs != NULL) { + for (i = 0; i < parser->nrelocs; i++) { + if (parser->relocs[i].gobj) + drm_gem_object_unreference_unlocked(parser->relocs[i].gobj); + } } kfree(parser->track); kfree(parser->relocs); From da58405860b992d2bb21ebae5d685fe3204dd3f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 18 Mar 2010 11:56:54 +0000 Subject: [PATCH 411/478] drm: Return ENODEV if the inode mapping changes Replace a BUG_ON with an error code in the event that the inode mapping changes between calls to drm_open. This may happen for instance if udev is loaded subsequent to the original opening of the device: [ 644.291870] kernel BUG at drivers/gpu/drm/drm_fops.c:146! [ 644.291876] invalid opcode: 0000 [#1] SMP [ 644.291882] last sysfs file: /sys/kernel/uevent_seqnum [ 644.291888] [ 644.291895] Pid: 7276, comm: lt-cairo-test-s Not tainted 2.6.34-rc1 #2 N150/N210/N220 /N150/N210/N220 [ 644.291903] EIP: 0060:[] EFLAGS: 00210283 CPU: 0 [ 644.291912] EIP is at drm_open+0x4b1/0x4e2 [ 644.291918] EAX: f72d8d18 EBX: f790a400 ECX: f73176b8 EDX: 00000000 [ 644.291923] ESI: f790a414 EDI: f790a414 EBP: f647ae20 ESP: f647adfc [ 644.291929] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 [ 644.291937] Process lt-cairo-test-s (pid: 7276, ti=f647a000 task=f73f5c80 task.ti=f647a000) [ 644.291941] Stack: [ 644.291945] 00000000 f7bb7400 00000080 f6451100 f73176b8 f6479214 f6451100 f73176b8 [ 644.291957] <0> c1297ce0 f647ae34 c11c6c04 f73176b8 f7949800 00000000 f647ae54 c1080ac5 [ 644.291969] <0> f7949800 f6451100 00000000 f6451100 f73176b8 f6452780 f647ae70 c107d1e6 [ 644.291982] Call Trace: [ 644.291991] [] ? drm_stub_open+0x8a/0xb8 [ 644.292000] [] ? chrdev_open+0xef/0x106 [ 644.292008] [] ? __dentry_open+0xd4/0x1a6 [ 644.292015] [] ? nameidata_to_filp+0x31/0x45 [ 644.292022] [] ? chrdev_open+0x0/0x106 [ 644.292030] [] ? do_last+0x346/0x423 [ 644.292037] [] ? do_filp_open+0x190/0x415 [ 644.292046] [] ? handle_mm_fault+0x214/0x710 [ 644.292053] [] ? do_sys_open+0x4d/0xe9 [ 644.292061] [] ? do_page_fault+0x211/0x23f [ 644.292068] [] ? sys_open+0x23/0x2b [ 644.292075] [] ? sysenter_do_call+0x12/0x26 [ 644.292079] Code: 89 f0 89 55 dc e8 8d 96 0a 00 8b 45 e0 8b 55 dc 83 78 04 01 75 28 8b 83 18 02 00 00 85 c0 74 0f 8b 4d ec 3b 81 ac 00 00 00 74 13 <0f> 0b eb fe 8b 4d ec 8b 81 ac 00 00 00 89 83 18 02 00 00 89 f0 [ 644.292143] EIP: [] drm_open+0x4b1/0x4e2 SS:ESP 0068:f647adfc [ 644.292175] ---[ end trace 2ddd476af89a60fa ]--- Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fops.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 08d14df3bb4..4804872f8b1 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -140,14 +140,16 @@ int drm_open(struct inode *inode, struct file *filp) spin_unlock(&dev->count_lock); } out: - mutex_lock(&dev->struct_mutex); - if (minor->type == DRM_MINOR_LEGACY) { - BUG_ON((dev->dev_mapping != NULL) && - (dev->dev_mapping != inode->i_mapping)); - if (dev->dev_mapping == NULL) - dev->dev_mapping = inode->i_mapping; + if (!retcode) { + mutex_lock(&dev->struct_mutex); + if (minor->type == DRM_MINOR_LEGACY) { + if (dev->dev_mapping == NULL) + dev->dev_mapping = inode->i_mapping; + else if (dev->dev_mapping != inode->i_mapping) + retcode = -ENODEV; + } + mutex_unlock(&dev->struct_mutex); } - mutex_unlock(&dev->struct_mutex); return retcode; } From d8fe2fa90ea9df694dcc022271391e7547772e1b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 18:45:32 -0400 Subject: [PATCH 412/478] drm/radeon/r600: remove some regs are not safe regs for command buffers Only the drm should be touching them. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/reg_srcs/r600 | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600 index 8f414a5f520..1d3340032ca 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r600 +++ b/drivers/gpu/drm/radeon/reg_srcs/r600 @@ -824,8 +824,6 @@ r600 0x9400 0x00028428 CB_FOG_GREEN 0x00028424 CB_FOG_RED 0x00008040 WAIT_UNTIL -0x00008950 CC_GC_SHADER_PIPE_CONFIG -0x00008954 GC_USER_SHADER_PIPE_CONFIG 0x00009714 VC_ENHANCE 0x00009830 DB_DEBUG 0x00009838 DB_WATERMARKS @@ -834,4 +832,3 @@ r600 0x9400 0x00009504 TA_CNTL 0x00009700 VC_CNTL 0x00009718 VC_CONFIG -0x0000A02C SMX_DC_MC_INTF_CTL From 5898b1f33c881fe1352464efd15faf7d26513b98 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 13:57:29 -0400 Subject: [PATCH 413/478] drm/radeon/kms: fix some typos in r6xx/r7xx hpd setup Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 518f8d335f3..5509354c7c8 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2396,19 +2396,19 @@ static void r600_disable_interrupt_state(struct radeon_device *rdev) WREG32(DC_HPD4_INT_CONTROL, tmp); if (ASIC_IS_DCE32(rdev)) { tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY; - WREG32(DC_HPD5_INT_CONTROL, 0); + WREG32(DC_HPD5_INT_CONTROL, tmp); tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY; - WREG32(DC_HPD6_INT_CONTROL, 0); + WREG32(DC_HPD6_INT_CONTROL, tmp); } } else { WREG32(DACA_AUTODETECT_INT_CONTROL, 0); WREG32(DACB_AUTODETECT_INT_CONTROL, 0); tmp = RREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL) & DC_HOT_PLUG_DETECTx_INT_POLARITY; - WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, 0); + WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp); tmp = RREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL) & DC_HOT_PLUG_DETECTx_INT_POLARITY; - WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, 0); + WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp); tmp = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & DC_HOT_PLUG_DETECTx_INT_POLARITY; - WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, 0); + WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, tmp); } } @@ -2834,14 +2834,14 @@ restart_ih: break; case 10: if (disp_int_cont2 & DC_HPD5_INTERRUPT) { - disp_int_cont &= ~DC_HPD5_INTERRUPT; + disp_int_cont2 &= ~DC_HPD5_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD5\n"); } break; case 12: if (disp_int_cont2 & DC_HPD6_INTERRUPT) { - disp_int_cont &= ~DC_HPD6_INTERRUPT; + disp_int_cont2 &= ~DC_HPD6_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD6\n"); } From 5f77df368c84d0a4a5913c8c78f0c6fa0b0db674 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Mar 2010 14:52:32 -0400 Subject: [PATCH 414/478] drm/radeon/r6xx/r7xx: CS parser fixes - Drop some more safe regs taht userspace shouldn't hit - Constant base regs need relocs. This allows us to use constant buffers rather than the constant register file. Also we don't want userspace to be able to set arbitrary mc base values for the const caches. - Track SQ_CONFIG so we know whether userspace is using the cfile or constant buffers. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_cs.c | 70 +++++++++++++++++++++++++--- drivers/gpu/drm/radeon/r600d.h | 49 +++++++++++++++++++ drivers/gpu/drm/radeon/reg_srcs/r600 | 53 --------------------- 3 files changed, 112 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index cd2c63bce50..c39c1bc1301 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -45,6 +45,7 @@ struct r600_cs_track { u32 nbanks; u32 npipes; /* value we track */ + u32 sq_config; u32 nsamples; u32 cb_color_base_last[8]; struct radeon_bo *cb_color_bo[8]; @@ -141,6 +142,8 @@ static void r600_cs_track_init(struct r600_cs_track *track) { int i; + /* assume DX9 mode */ + track->sq_config = DX9_CONSTS; for (i = 0; i < 8; i++) { track->cb_color_base_last[i] = 0; track->cb_color_size[i] = 0; @@ -715,6 +718,9 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx tmp =radeon_get_ib_value(p, idx); ib[idx] = 0; break; + case SQ_CONFIG: + track->sq_config = radeon_get_ib_value(p, idx); + break; case R_028800_DB_DEPTH_CONTROL: track->db_depth_control = radeon_get_ib_value(p, idx); break; @@ -869,6 +875,54 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx case SQ_PGM_START_VS: case SQ_PGM_START_GS: case SQ_PGM_START_PS: + case SQ_ALU_CONST_CACHE_GS_0: + case SQ_ALU_CONST_CACHE_GS_1: + case SQ_ALU_CONST_CACHE_GS_2: + case SQ_ALU_CONST_CACHE_GS_3: + case SQ_ALU_CONST_CACHE_GS_4: + case SQ_ALU_CONST_CACHE_GS_5: + case SQ_ALU_CONST_CACHE_GS_6: + case SQ_ALU_CONST_CACHE_GS_7: + case SQ_ALU_CONST_CACHE_GS_8: + case SQ_ALU_CONST_CACHE_GS_9: + case SQ_ALU_CONST_CACHE_GS_10: + case SQ_ALU_CONST_CACHE_GS_11: + case SQ_ALU_CONST_CACHE_GS_12: + case SQ_ALU_CONST_CACHE_GS_13: + case SQ_ALU_CONST_CACHE_GS_14: + case SQ_ALU_CONST_CACHE_GS_15: + case SQ_ALU_CONST_CACHE_PS_0: + case SQ_ALU_CONST_CACHE_PS_1: + case SQ_ALU_CONST_CACHE_PS_2: + case SQ_ALU_CONST_CACHE_PS_3: + case SQ_ALU_CONST_CACHE_PS_4: + case SQ_ALU_CONST_CACHE_PS_5: + case SQ_ALU_CONST_CACHE_PS_6: + case SQ_ALU_CONST_CACHE_PS_7: + case SQ_ALU_CONST_CACHE_PS_8: + case SQ_ALU_CONST_CACHE_PS_9: + case SQ_ALU_CONST_CACHE_PS_10: + case SQ_ALU_CONST_CACHE_PS_11: + case SQ_ALU_CONST_CACHE_PS_12: + case SQ_ALU_CONST_CACHE_PS_13: + case SQ_ALU_CONST_CACHE_PS_14: + case SQ_ALU_CONST_CACHE_PS_15: + case SQ_ALU_CONST_CACHE_VS_0: + case SQ_ALU_CONST_CACHE_VS_1: + case SQ_ALU_CONST_CACHE_VS_2: + case SQ_ALU_CONST_CACHE_VS_3: + case SQ_ALU_CONST_CACHE_VS_4: + case SQ_ALU_CONST_CACHE_VS_5: + case SQ_ALU_CONST_CACHE_VS_6: + case SQ_ALU_CONST_CACHE_VS_7: + case SQ_ALU_CONST_CACHE_VS_8: + case SQ_ALU_CONST_CACHE_VS_9: + case SQ_ALU_CONST_CACHE_VS_10: + case SQ_ALU_CONST_CACHE_VS_11: + case SQ_ALU_CONST_CACHE_VS_12: + case SQ_ALU_CONST_CACHE_VS_13: + case SQ_ALU_CONST_CACHE_VS_14: + case SQ_ALU_CONST_CACHE_VS_15: r = r600_cs_packet_next_reloc(p, &reloc); if (r) { dev_warn(p->dev, "bad SET_CONTEXT_REG " @@ -1226,13 +1280,15 @@ static int r600_packet3_check(struct radeon_cs_parser *p, } break; case PACKET3_SET_ALU_CONST: - start_reg = (idx_value << 2) + PACKET3_SET_ALU_CONST_OFFSET; - end_reg = 4 * pkt->count + start_reg - 4; - if ((start_reg < PACKET3_SET_ALU_CONST_OFFSET) || - (start_reg >= PACKET3_SET_ALU_CONST_END) || - (end_reg >= PACKET3_SET_ALU_CONST_END)) { - DRM_ERROR("bad SET_ALU_CONST\n"); - return -EINVAL; + if (track->sq_config & DX9_CONSTS) { + start_reg = (idx_value << 2) + PACKET3_SET_ALU_CONST_OFFSET; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_ALU_CONST_OFFSET) || + (start_reg >= PACKET3_SET_ALU_CONST_END) || + (end_reg >= PACKET3_SET_ALU_CONST_END)) { + DRM_ERROR("bad SET_ALU_CONST\n"); + return -EINVAL; + } } break; case PACKET3_SET_BOOL_CONST: diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 5b2e4d44282..59c1f8793e6 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -77,6 +77,55 @@ #define CB_COLOR0_FRAG 0x280e0 #define CB_COLOR0_MASK 0x28100 +#define SQ_ALU_CONST_CACHE_PS_0 0x28940 +#define SQ_ALU_CONST_CACHE_PS_1 0x28944 +#define SQ_ALU_CONST_CACHE_PS_2 0x28948 +#define SQ_ALU_CONST_CACHE_PS_3 0x2894c +#define SQ_ALU_CONST_CACHE_PS_4 0x28950 +#define SQ_ALU_CONST_CACHE_PS_5 0x28954 +#define SQ_ALU_CONST_CACHE_PS_6 0x28958 +#define SQ_ALU_CONST_CACHE_PS_7 0x2895c +#define SQ_ALU_CONST_CACHE_PS_8 0x28960 +#define SQ_ALU_CONST_CACHE_PS_9 0x28964 +#define SQ_ALU_CONST_CACHE_PS_10 0x28968 +#define SQ_ALU_CONST_CACHE_PS_11 0x2896c +#define SQ_ALU_CONST_CACHE_PS_12 0x28970 +#define SQ_ALU_CONST_CACHE_PS_13 0x28974 +#define SQ_ALU_CONST_CACHE_PS_14 0x28978 +#define SQ_ALU_CONST_CACHE_PS_15 0x2897c +#define SQ_ALU_CONST_CACHE_VS_0 0x28980 +#define SQ_ALU_CONST_CACHE_VS_1 0x28984 +#define SQ_ALU_CONST_CACHE_VS_2 0x28988 +#define SQ_ALU_CONST_CACHE_VS_3 0x2898c +#define SQ_ALU_CONST_CACHE_VS_4 0x28990 +#define SQ_ALU_CONST_CACHE_VS_5 0x28994 +#define SQ_ALU_CONST_CACHE_VS_6 0x28998 +#define SQ_ALU_CONST_CACHE_VS_7 0x2899c +#define SQ_ALU_CONST_CACHE_VS_8 0x289a0 +#define SQ_ALU_CONST_CACHE_VS_9 0x289a4 +#define SQ_ALU_CONST_CACHE_VS_10 0x289a8 +#define SQ_ALU_CONST_CACHE_VS_11 0x289ac +#define SQ_ALU_CONST_CACHE_VS_12 0x289b0 +#define SQ_ALU_CONST_CACHE_VS_13 0x289b4 +#define SQ_ALU_CONST_CACHE_VS_14 0x289b8 +#define SQ_ALU_CONST_CACHE_VS_15 0x289bc +#define SQ_ALU_CONST_CACHE_GS_0 0x289c0 +#define SQ_ALU_CONST_CACHE_GS_1 0x289c4 +#define SQ_ALU_CONST_CACHE_GS_2 0x289c8 +#define SQ_ALU_CONST_CACHE_GS_3 0x289cc +#define SQ_ALU_CONST_CACHE_GS_4 0x289d0 +#define SQ_ALU_CONST_CACHE_GS_5 0x289d4 +#define SQ_ALU_CONST_CACHE_GS_6 0x289d8 +#define SQ_ALU_CONST_CACHE_GS_7 0x289dc +#define SQ_ALU_CONST_CACHE_GS_8 0x289e0 +#define SQ_ALU_CONST_CACHE_GS_9 0x289e4 +#define SQ_ALU_CONST_CACHE_GS_10 0x289e8 +#define SQ_ALU_CONST_CACHE_GS_11 0x289ec +#define SQ_ALU_CONST_CACHE_GS_12 0x289f0 +#define SQ_ALU_CONST_CACHE_GS_13 0x289f4 +#define SQ_ALU_CONST_CACHE_GS_14 0x289f8 +#define SQ_ALU_CONST_CACHE_GS_15 0x289fc + #define CONFIG_MEMSIZE 0x5428 #define CONFIG_CNTL 0x5424 #define CP_STAT 0x8680 diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600 index 1d3340032ca..bc062f9a847 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r600 +++ b/drivers/gpu/drm/radeon/reg_srcs/r600 @@ -280,7 +280,6 @@ r600 0x9400 0x00028E00 PA_SU_POLY_OFFSET_FRONT_SCALE 0x00028814 PA_SU_SC_MODE_CNTL 0x00028C08 PA_SU_VTX_CNTL -0x00008C00 SQ_CONFIG 0x00008C04 SQ_GPR_RESOURCE_MGMT_1 0x00008C08 SQ_GPR_RESOURCE_MGMT_2 0x00008C10 SQ_STACK_RESOURCE_MGMT_1 @@ -380,54 +379,6 @@ r600 0x9400 0x000281B4 SQ_ALU_CONST_BUFFER_SIZE_VS_13 0x000281B8 SQ_ALU_CONST_BUFFER_SIZE_VS_14 0x000281BC SQ_ALU_CONST_BUFFER_SIZE_VS_15 -0x000289C0 SQ_ALU_CONST_CACHE_GS_0 -0x000289C4 SQ_ALU_CONST_CACHE_GS_1 -0x000289C8 SQ_ALU_CONST_CACHE_GS_2 -0x000289CC SQ_ALU_CONST_CACHE_GS_3 -0x000289D0 SQ_ALU_CONST_CACHE_GS_4 -0x000289D4 SQ_ALU_CONST_CACHE_GS_5 -0x000289D8 SQ_ALU_CONST_CACHE_GS_6 -0x000289DC SQ_ALU_CONST_CACHE_GS_7 -0x000289E0 SQ_ALU_CONST_CACHE_GS_8 -0x000289E4 SQ_ALU_CONST_CACHE_GS_9 -0x000289E8 SQ_ALU_CONST_CACHE_GS_10 -0x000289EC SQ_ALU_CONST_CACHE_GS_11 -0x000289F0 SQ_ALU_CONST_CACHE_GS_12 -0x000289F4 SQ_ALU_CONST_CACHE_GS_13 -0x000289F8 SQ_ALU_CONST_CACHE_GS_14 -0x000289FC SQ_ALU_CONST_CACHE_GS_15 -0x00028940 SQ_ALU_CONST_CACHE_PS_0 -0x00028944 SQ_ALU_CONST_CACHE_PS_1 -0x00028948 SQ_ALU_CONST_CACHE_PS_2 -0x0002894C SQ_ALU_CONST_CACHE_PS_3 -0x00028950 SQ_ALU_CONST_CACHE_PS_4 -0x00028954 SQ_ALU_CONST_CACHE_PS_5 -0x00028958 SQ_ALU_CONST_CACHE_PS_6 -0x0002895C SQ_ALU_CONST_CACHE_PS_7 -0x00028960 SQ_ALU_CONST_CACHE_PS_8 -0x00028964 SQ_ALU_CONST_CACHE_PS_9 -0x00028968 SQ_ALU_CONST_CACHE_PS_10 -0x0002896C SQ_ALU_CONST_CACHE_PS_11 -0x00028970 SQ_ALU_CONST_CACHE_PS_12 -0x00028974 SQ_ALU_CONST_CACHE_PS_13 -0x00028978 SQ_ALU_CONST_CACHE_PS_14 -0x0002897C SQ_ALU_CONST_CACHE_PS_15 -0x00028980 SQ_ALU_CONST_CACHE_VS_0 -0x00028984 SQ_ALU_CONST_CACHE_VS_1 -0x00028988 SQ_ALU_CONST_CACHE_VS_2 -0x0002898C SQ_ALU_CONST_CACHE_VS_3 -0x00028990 SQ_ALU_CONST_CACHE_VS_4 -0x00028994 SQ_ALU_CONST_CACHE_VS_5 -0x00028998 SQ_ALU_CONST_CACHE_VS_6 -0x0002899C SQ_ALU_CONST_CACHE_VS_7 -0x000289A0 SQ_ALU_CONST_CACHE_VS_8 -0x000289A4 SQ_ALU_CONST_CACHE_VS_9 -0x000289A8 SQ_ALU_CONST_CACHE_VS_10 -0x000289AC SQ_ALU_CONST_CACHE_VS_11 -0x000289B0 SQ_ALU_CONST_CACHE_VS_12 -0x000289B4 SQ_ALU_CONST_CACHE_VS_13 -0x000289B8 SQ_ALU_CONST_CACHE_VS_14 -0x000289BC SQ_ALU_CONST_CACHE_VS_15 0x000288D8 SQ_PGM_CF_OFFSET_ES 0x000288DC SQ_PGM_CF_OFFSET_FS 0x000288D4 SQ_PGM_CF_OFFSET_GS @@ -497,9 +448,7 @@ r600 0x9400 0x0000A020 SMX_DC_CTL0 0x0000A024 SMX_DC_CTL1 0x0000A028 SMX_DC_CTL2 -0x00009608 TC_CNTL 0x00009604 TC_INVALIDATE -0x00009490 TD_CNTL 0x00009400 TD_FILTER4 0x00009404 TD_FILTER4_1 0x00009408 TD_FILTER4_2 @@ -829,6 +778,4 @@ r600 0x9400 0x00009838 DB_WATERMARKS 0x00028D28 DB_SRESULTS_COMPARE_STATE0 0x00028D44 DB_ALPHA_TO_MASK -0x00009504 TA_CNTL 0x00009700 VC_CNTL -0x00009718 VC_CONFIG From fdb43528d4697b0e81e27a0d6539e744c2965cf2 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Mar 2010 15:24:14 -0400 Subject: [PATCH 415/478] drm/radeon/kms: bump the version for r6xx/r7xx const buffer support Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 6eec0ece6a6..54ec04928d9 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -42,9 +42,10 @@ * KMS wrapper. * - 2.0.0 - initial interface * - 2.1.0 - add square tiling interface + * - 2.2.0 - add r6xx/r7xx const buffer support */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 1 +#define KMS_DRIVER_MINOR 2 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); From 6bb118012ab0462d5ebc3ab17eb278416532cf15 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Mar 2010 15:26:51 -0400 Subject: [PATCH 416/478] drm/radeon: bump the UMS driver version for r6xx/r7xx const buffer support Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_drv.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index ec55f2b23c2..448eba89d1e 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -107,9 +107,10 @@ * 1.30- Add support for occlusion queries * 1.31- Add support for num Z pipes from GET_PARAM * 1.32- fixes for rv740 setup + * 1.33- Add r6xx/r7xx const buffer support */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 32 +#define DRIVER_MINOR 33 #define DRIVER_PATCHLEVEL 0 enum radeon_cp_microcode_version { From 97586c422b38c4c12e2b5011d59c401d03d09ed6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Mar 2010 19:36:33 -0400 Subject: [PATCH 417/478] drm/radeon/r6xx/r7xx: further safe reg clean up - remove a few more drm only regs - remove sampler, alu, bool, loop constant regs. They are set via separate packet3's already Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/reg_srcs/r600 | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600 index bc062f9a847..af0da4ae3f5 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r600 +++ b/drivers/gpu/drm/radeon/reg_srcs/r600 @@ -26,20 +26,16 @@ r600 0x9400 0x00028408 VGT_INDX_OFFSET 0x00028AA0 VGT_INSTANCE_STEP_RATE_0 0x00028AA4 VGT_INSTANCE_STEP_RATE_1 -0x000088C0 VGT_LAST_COPY_STATE 0x00028400 VGT_MAX_VTX_INDX -0x000088D8 VGT_MC_LAT_CNTL 0x00028404 VGT_MIN_VTX_INDX 0x00028A94 VGT_MULTI_PRIM_IB_RESET_EN 0x0002840C VGT_MULTI_PRIM_IB_RESET_INDX 0x00008970 VGT_NUM_INDICES 0x00008974 VGT_NUM_INSTANCES 0x00028A10 VGT_OUTPUT_PATH_CNTL -0x00028C5C VGT_OUT_DEALLOC_CNTL 0x00028A84 VGT_PRIMITIVEID_EN 0x00008958 VGT_PRIMITIVE_TYPE 0x00028AB4 VGT_REUSE_OFF -0x00028C58 VGT_VERTEX_REUSE_BLOCK_CNTL 0x00028AB8 VGT_VTX_CNT_EN 0x000088B0 VGT_VTX_VECT_EJECT_REG 0x00028810 PA_CL_CLIP_CNTL @@ -319,18 +315,6 @@ r600 0x9400 0x000283FC SQ_VTX_SEMANTIC_31 0x000288E0 SQ_VTX_SEMANTIC_CLEAR 0x0003CFF4 SQ_VTX_START_INST_LOC -0x0003C000 SQ_TEX_SAMPLER_WORD0_0 -0x0003C004 SQ_TEX_SAMPLER_WORD1_0 -0x0003C008 SQ_TEX_SAMPLER_WORD2_0 -0x00030000 SQ_ALU_CONSTANT0_0 -0x00030004 SQ_ALU_CONSTANT1_0 -0x00030008 SQ_ALU_CONSTANT2_0 -0x0003000C SQ_ALU_CONSTANT3_0 -0x0003E380 SQ_BOOL_CONST_0 -0x0003E384 SQ_BOOL_CONST_1 -0x0003E388 SQ_BOOL_CONST_2 -0x0003E200 SQ_LOOP_CONST_0 -0x0003E200 SQ_LOOP_CONST_DX10_0 0x000281C0 SQ_ALU_CONST_BUFFER_SIZE_GS_0 0x000281C4 SQ_ALU_CONST_BUFFER_SIZE_GS_1 0x000281C8 SQ_ALU_CONST_BUFFER_SIZE_GS_2 @@ -445,9 +429,6 @@ r600 0x9400 0x00028438 SX_ALPHA_REF 0x00028410 SX_ALPHA_TEST_CONTROL 0x00028350 SX_MISC -0x0000A020 SMX_DC_CTL0 -0x0000A024 SMX_DC_CTL1 -0x0000A028 SMX_DC_CTL2 0x00009604 TC_INVALIDATE 0x00009400 TD_FILTER4 0x00009404 TD_FILTER4_1 From e1e8a5dd4faf356b5d31c620c5787eaa83ee831d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Mar 2010 17:14:37 -0400 Subject: [PATCH 418/478] drm/radeon/kms: fix macbookpro connector quirk Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index f0ea7f8da67..1fff95505cf 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -264,6 +264,8 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, if ((supported_device == ATOM_DEVICE_CRT1_SUPPORT) || (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) return false; + if (supported_device == ATOM_DEVICE_CRT2_SUPPORT) + *line_mux = 0x90; } /* ASUS HD 3600 XT board lists the DVI port as HDMI */ From b8c40d6269d5e515341599b2e395f2dab4490d74 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 25 Mar 2010 18:29:05 +0000 Subject: [PATCH 419/478] drm: fix build error when SYSRQ is disabled Fix build error when CONFIG_MAGIC_SYSRQ is not enabled: drivers/gpu/drm/drm_fb_helper.c:915: error: 'sysrq_drm_fb_helper_restore_op' undeclared (first use in this function) drivers/gpu/drm/drm_fb_helper.c:929: error: 'sysrq_drm_fb_helper_restore_op' undeclared (first use in this function) Signed-off-by: Randy Dunlap Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 50549703584..99487237111 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -283,6 +283,8 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { .help_msg = "force-fb(V)", .action_msg = "Restore framebuffer console", }; +#else +static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { }; #endif static void drm_fb_helper_on(struct fb_info *info) From 3ca82da3ebe019facd611184385897fa614e6b9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 26 Mar 2010 19:18:55 +0000 Subject: [PATCH 420/478] drm/radeon/kms: Only restrict BO to visible VRAM size when pinning to VRAM. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prevented radeon.test=1 from testing transfers from/to GTT beyond the visible VRAM size. Signed-off-by: Michel Dänzer Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_object.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index fc9d00ac6b1..dc7e3f44913 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -185,8 +185,10 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) return 0; } radeon_ttm_placement_from_domain(bo, domain); - /* force to pin into visible video ram */ - bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT; + if (domain == RADEON_GEM_DOMAIN_VRAM) { + /* force to pin into visible video ram */ + bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT; + } for (i = 0; i < bo->placement.num_placement; i++) bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); From d9c9fe3622d15e7e84121ffedef60f4080ab4f03 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 29 Mar 2010 17:39:44 -0400 Subject: [PATCH 421/478] drm/radeon/kms/atom: minor fixes to transmitter setup - 8 lane links are not valid for DP - remove unused num var Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 54 +++++++++--------------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index fd4052f71bf..6f334519a06 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -708,7 +708,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) struct radeon_connector_atom_dig *dig_connector = radeon_get_atom_connector_priv_from_encoder(encoder); union dig_encoder_control args; - int index = 0, num = 0; + int index = 0; uint8_t frev, crev; if (!dig || !dig_connector) @@ -724,7 +724,6 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) else index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); } - num = dig->dig_encoder + 1; if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) return; @@ -786,7 +785,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t struct drm_connector *connector; struct radeon_connector *radeon_connector; union dig_transmitter_control args; - int index = 0, num = 0; + int index = 0; uint8_t frev, crev; bool is_dp = false; int pll_id = 0; @@ -862,15 +861,12 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: args.v3.acConfig.ucTransmitterSel = 0; - num = 0; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: args.v3.acConfig.ucTransmitterSel = 1; - num = 1; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: args.v3.acConfig.ucTransmitterSel = 2; - num = 2; break; } @@ -881,23 +877,19 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v3.acConfig.fCoherentMode = 1; } } else if (ASIC_IS_DCE32(rdev)) { - if (dig->dig_encoder == 1) - args.v2.acConfig.ucEncoderSel = 1; + args.v2.acConfig.ucEncoderSel = dig->dig_encoder; if (dig_connector->linkb) args.v2.acConfig.ucLinkSel = 1; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: args.v2.acConfig.ucTransmitterSel = 0; - num = 0; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: args.v2.acConfig.ucTransmitterSel = 1; - num = 1; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: args.v2.acConfig.ucTransmitterSel = 2; - num = 2; break; } @@ -915,31 +907,25 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t else args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - if (rdev->flags & RADEON_IS_IGP) { - if (radeon_encoder->pixel_clock > 165000) { - if (dig_connector->igp_lane_info & 0x3) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; - else if (dig_connector->igp_lane_info & 0xc) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; - } else { - if (dig_connector->igp_lane_info & 0x1) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; - else if (dig_connector->igp_lane_info & 0x2) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; - else if (dig_connector->igp_lane_info & 0x4) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; - else if (dig_connector->igp_lane_info & 0x8) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; - } + if ((rdev->flags & RADEON_IS_IGP) && + (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) { + if (is_dp || (radeon_encoder->pixel_clock <= 165000)) { + if (dig_connector->igp_lane_info & 0x1) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else if (dig_connector->igp_lane_info & 0x2) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; + else if (dig_connector->igp_lane_info & 0x4) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; + else if (dig_connector->igp_lane_info & 0x8) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; + } else { + if (dig_connector->igp_lane_info & 0x3) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; + else if (dig_connector->igp_lane_info & 0xc) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; } - break; } - if (radeon_encoder->pixel_clock > 165000) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; - if (dig_connector->linkb) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; else @@ -950,6 +936,8 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { if (dig->coherent_mode) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; } } From 7f768957f407f7b8c8793eedaf7512049d092f29 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 29 Mar 2010 14:06:10 -0400 Subject: [PATCH 422/478] drm/radeon/kms/dp: remove extraneous training complete call Looks like a copy/paste typo from when evergreen support was added. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 8a133bda00a..ca776b29513 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -750,9 +750,6 @@ void dp_link_train(struct drm_encoder *encoder, else radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE, dig_connector->dp_clock, enc_id, 0); - - radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE, - dig_connector->dp_clock, enc_id, 0); } int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, From 9f998ad7e92a1653b6b396b1278e75560a8be519 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 29 Mar 2010 21:37:08 -0400 Subject: [PATCH 423/478] drm/radeon/kms: minor fixes for eDP with LCD* device tags (v2) Some systems have LCD* rather than DFP* device tags in the bios for eDP connectors; notably the new apple iMac. This fixes things up so eDP connectors with either tag will work. v2: fix typo Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 13 +++++++++---- drivers/gpu/drm/radeon/radeon_encoders.c | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 56107b3a997..fd4ef6d1884 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -581,11 +581,16 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, } } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { /* may want to enable SS on DP/eDP eventually */ - args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_SS_ENABLE; - if (mode->clock > 165000) + /*args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_SS_ENABLE;*/ + if (encoder_mode == ATOM_ENCODER_MODE_DP) args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_DUAL_LINK; + DISPPLL_CONFIG_COHERENT_MODE; + else { + if (mode->clock > 165000) + args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_DUAL_LINK; + } } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 6f334519a06..cbc6fa20cf5 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -302,7 +302,7 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, } if (ASIC_IS_DCE3(rdev) && - (radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT))) { + (radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT))) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); radeon_dp_set_link_config(connector, mode); } From 3b01a1191fe76bd11e5743eceed7c25d8157239e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 30 Mar 2010 02:03:48 -0400 Subject: [PATCH 424/478] drm/radeon/kms/dp: disable training pattern on the sink at the end of link training Seems to have gotten lost in the evergreen merge. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index ca776b29513..28b31c64f48 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -745,6 +745,9 @@ void dp_link_train(struct drm_encoder *encoder, >> DP_TRAIN_PRE_EMPHASIS_SHIFT); /* disable the training pattern on the sink */ + dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE); + + /* disable the training pattern on the source */ if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE); else From f46c01208da1881591e3f55ca77d37f54469f8e4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 31 Mar 2010 00:33:27 -0400 Subject: [PATCH 425/478] drm/radeon/kms: display watermark updates (v2) - Add module option to force the display priority 0 = auto, 1 = normal, 2 = high - Default to high on r3xx/r4xx/rv515 chips Fixes flickering problems during heavy acceleration due to underflow to the display controllers - Fill in minimal support for RS600 v2 - update display priority when bandwidth is updated so the user can change the parameter at runtime and it will take affect on the next modeset. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 2 + drivers/gpu/drm/radeon/radeon.h | 2 + drivers/gpu/drm/radeon/radeon_display.c | 17 ++++++++ drivers/gpu/drm/radeon/radeon_drv.c | 4 ++ drivers/gpu/drm/radeon/rs600.c | 25 +++++++++++- drivers/gpu/drm/radeon/rs600d.h | 53 +++++++++++++++++++++++++ drivers/gpu/drm/radeon/rs690.c | 35 +++++++++++----- drivers/gpu/drm/radeon/rs690d.h | 3 ++ drivers/gpu/drm/radeon/rv515.c | 35 +++++++++++----- 9 files changed, 155 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 739a44783ef..138ddd49dfc 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2389,6 +2389,8 @@ void r100_bandwidth_update(struct radeon_device *rdev) uint32_t pixel_bytes1 = 0; uint32_t pixel_bytes2 = 0; + radeon_update_display_priority(rdev); + if (rdev->mode_info.crtcs[0]->base.enabled) { mode1 = &rdev->mode_info.crtcs[0]->base.mode; pixel_bytes1 = rdev->mode_info.crtcs[0]->base.fb->bits_per_pixel / 8; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 4ee5cb98956..1710b9e3ef7 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -91,6 +91,7 @@ extern int radeon_tv; extern int radeon_new_pll; extern int radeon_dynpm; extern int radeon_audio; +extern int radeon_disp_priority; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting @@ -1181,6 +1182,7 @@ extern int radeon_modeset_init(struct radeon_device *rdev); extern void radeon_modeset_fini(struct radeon_device *rdev); extern bool radeon_card_posted(struct radeon_device *rdev); extern void radeon_update_bandwidth_info(struct radeon_device *rdev); +extern void radeon_update_display_priority(struct radeon_device *rdev); extern bool radeon_boot_test_post_card(struct radeon_device *rdev); extern int radeon_clocks_init(struct radeon_device *rdev); extern void radeon_clocks_fini(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index eca714c381d..b8d67282824 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -971,6 +971,23 @@ static int radeon_modeset_create_props(struct radeon_device *rdev) return 0; } +void radeon_update_display_priority(struct radeon_device *rdev) +{ + /* adjustment options for the display watermarks */ + if ((radeon_disp_priority == 0) || (radeon_disp_priority > 2)) { + /* set display priority to high for r3xx, rv515 chips + * this avoids flickering due to underflow to the + * display controllers during heavy acceleration. + */ + if (ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV515)) + rdev->disp_priority = 2; + else + rdev->disp_priority = 0; + } else + rdev->disp_priority = radeon_disp_priority; + +} + int radeon_modeset_init(struct radeon_device *rdev) { int i; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 54ec04928d9..6fd511eec96 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -92,6 +92,7 @@ int radeon_tv = 1; int radeon_new_pll = -1; int radeon_dynpm = -1; int radeon_audio = 1; +int radeon_disp_priority = 0; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -135,6 +136,9 @@ module_param_named(dynpm, radeon_dynpm, int, 0444); MODULE_PARM_DESC(audio, "Audio enable (0 = disable)"); module_param_named(audio, radeon_audio, int, 0444); +MODULE_PARM_DESC(disp_priority, "Display Priority (0 = auto, 1 = normal, 2 = high)"); +module_param_named(disp_priority, radeon_disp_priority, int, 0444); + static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 30c4b46f352..abf824c2123 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -483,7 +483,30 @@ void rs600_mc_init(struct radeon_device *rdev) void rs600_bandwidth_update(struct radeon_device *rdev) { - /* FIXME: implement, should this be like rs690 ? */ + struct drm_display_mode *mode0 = NULL; + struct drm_display_mode *mode1 = NULL; + u32 d1mode_priority_a_cnt, d2mode_priority_a_cnt; + /* FIXME: implement full support */ + + radeon_update_display_priority(rdev); + + if (rdev->mode_info.crtcs[0]->base.enabled) + mode0 = &rdev->mode_info.crtcs[0]->base.mode; + if (rdev->mode_info.crtcs[1]->base.enabled) + mode1 = &rdev->mode_info.crtcs[1]->base.mode; + + rs690_line_buffer_adjust(rdev, mode0, mode1); + + if (rdev->disp_priority == 2) { + d1mode_priority_a_cnt = RREG32(R_006548_D1MODE_PRIORITY_A_CNT); + d2mode_priority_a_cnt = RREG32(R_006D48_D2MODE_PRIORITY_A_CNT); + d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); + d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); + WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); + WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); + WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); + WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); + } } uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg) diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h index c1c8f5885cb..e52d2695510 100644 --- a/drivers/gpu/drm/radeon/rs600d.h +++ b/drivers/gpu/drm/radeon/rs600d.h @@ -535,4 +535,57 @@ #define G_00016C_INVALIDATE_L1_TLB(x) (((x) >> 20) & 0x1) #define C_00016C_INVALIDATE_L1_TLB 0xFFEFFFFF +#define R_006548_D1MODE_PRIORITY_A_CNT 0x006548 +#define S_006548_D1MODE_PRIORITY_MARK_A(x) (((x) & 0x7FFF) << 0) +#define G_006548_D1MODE_PRIORITY_MARK_A(x) (((x) >> 0) & 0x7FFF) +#define C_006548_D1MODE_PRIORITY_MARK_A 0xFFFF8000 +#define S_006548_D1MODE_PRIORITY_A_OFF(x) (((x) & 0x1) << 16) +#define G_006548_D1MODE_PRIORITY_A_OFF(x) (((x) >> 16) & 0x1) +#define C_006548_D1MODE_PRIORITY_A_OFF 0xFFFEFFFF +#define S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(x) (((x) & 0x1) << 20) +#define G_006548_D1MODE_PRIORITY_A_ALWAYS_ON(x) (((x) >> 20) & 0x1) +#define C_006548_D1MODE_PRIORITY_A_ALWAYS_ON 0xFFEFFFFF +#define S_006548_D1MODE_PRIORITY_A_FORCE_MASK(x) (((x) & 0x1) << 24) +#define G_006548_D1MODE_PRIORITY_A_FORCE_MASK(x) (((x) >> 24) & 0x1) +#define C_006548_D1MODE_PRIORITY_A_FORCE_MASK 0xFEFFFFFF +#define R_00654C_D1MODE_PRIORITY_B_CNT 0x00654C +#define S_00654C_D1MODE_PRIORITY_MARK_B(x) (((x) & 0x7FFF) << 0) +#define G_00654C_D1MODE_PRIORITY_MARK_B(x) (((x) >> 0) & 0x7FFF) +#define C_00654C_D1MODE_PRIORITY_MARK_B 0xFFFF8000 +#define S_00654C_D1MODE_PRIORITY_B_OFF(x) (((x) & 0x1) << 16) +#define G_00654C_D1MODE_PRIORITY_B_OFF(x) (((x) >> 16) & 0x1) +#define C_00654C_D1MODE_PRIORITY_B_OFF 0xFFFEFFFF +#define S_00654C_D1MODE_PRIORITY_B_ALWAYS_ON(x) (((x) & 0x1) << 20) +#define G_00654C_D1MODE_PRIORITY_B_ALWAYS_ON(x) (((x) >> 20) & 0x1) +#define C_00654C_D1MODE_PRIORITY_B_ALWAYS_ON 0xFFEFFFFF +#define S_00654C_D1MODE_PRIORITY_B_FORCE_MASK(x) (((x) & 0x1) << 24) +#define G_00654C_D1MODE_PRIORITY_B_FORCE_MASK(x) (((x) >> 24) & 0x1) +#define C_00654C_D1MODE_PRIORITY_B_FORCE_MASK 0xFEFFFFFF +#define R_006D48_D2MODE_PRIORITY_A_CNT 0x006D48 +#define S_006D48_D2MODE_PRIORITY_MARK_A(x) (((x) & 0x7FFF) << 0) +#define G_006D48_D2MODE_PRIORITY_MARK_A(x) (((x) >> 0) & 0x7FFF) +#define C_006D48_D2MODE_PRIORITY_MARK_A 0xFFFF8000 +#define S_006D48_D2MODE_PRIORITY_A_OFF(x) (((x) & 0x1) << 16) +#define G_006D48_D2MODE_PRIORITY_A_OFF(x) (((x) >> 16) & 0x1) +#define C_006D48_D2MODE_PRIORITY_A_OFF 0xFFFEFFFF +#define S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(x) (((x) & 0x1) << 20) +#define G_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(x) (((x) >> 20) & 0x1) +#define C_006D48_D2MODE_PRIORITY_A_ALWAYS_ON 0xFFEFFFFF +#define S_006D48_D2MODE_PRIORITY_A_FORCE_MASK(x) (((x) & 0x1) << 24) +#define G_006D48_D2MODE_PRIORITY_A_FORCE_MASK(x) (((x) >> 24) & 0x1) +#define C_006D48_D2MODE_PRIORITY_A_FORCE_MASK 0xFEFFFFFF +#define R_006D4C_D2MODE_PRIORITY_B_CNT 0x006D4C +#define S_006D4C_D2MODE_PRIORITY_MARK_B(x) (((x) & 0x7FFF) << 0) +#define G_006D4C_D2MODE_PRIORITY_MARK_B(x) (((x) >> 0) & 0x7FFF) +#define C_006D4C_D2MODE_PRIORITY_MARK_B 0xFFFF8000 +#define S_006D4C_D2MODE_PRIORITY_B_OFF(x) (((x) & 0x1) << 16) +#define G_006D4C_D2MODE_PRIORITY_B_OFF(x) (((x) >> 16) & 0x1) +#define C_006D4C_D2MODE_PRIORITY_B_OFF 0xFFFEFFFF +#define S_006D4C_D2MODE_PRIORITY_B_ALWAYS_ON(x) (((x) & 0x1) << 20) +#define G_006D4C_D2MODE_PRIORITY_B_ALWAYS_ON(x) (((x) >> 20) & 0x1) +#define C_006D4C_D2MODE_PRIORITY_B_ALWAYS_ON 0xFFEFFFFF +#define S_006D4C_D2MODE_PRIORITY_B_FORCE_MASK(x) (((x) & 0x1) << 24) +#define G_006D4C_D2MODE_PRIORITY_B_FORCE_MASK(x) (((x) >> 24) & 0x1) +#define C_006D4C_D2MODE_PRIORITY_B_FORCE_MASK 0xFEFFFFFF + #endif diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index f758d5cc116..bbf3da790fd 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -400,10 +400,12 @@ void rs690_bandwidth_update(struct radeon_device *rdev) struct drm_display_mode *mode1 = NULL; struct rs690_watermark wm0; struct rs690_watermark wm1; - u32 tmp; + u32 tmp, d1mode_priority_a_cnt, d2mode_priority_a_cnt; fixed20_12 priority_mark02, priority_mark12, fill_rate; fixed20_12 a, b; + radeon_update_display_priority(rdev); + if (rdev->mode_info.crtcs[0]->base.enabled) mode0 = &rdev->mode_info.crtcs[0]->base.mode; if (rdev->mode_info.crtcs[1]->base.enabled) @@ -413,7 +415,8 @@ void rs690_bandwidth_update(struct radeon_device *rdev) * modes if the user specifies HIGH for displaypriority * option. */ - if (rdev->disp_priority == 2) { + if ((rdev->disp_priority == 2) && + ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))) { tmp = RREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER); tmp &= C_000104_MC_DISP0R_INIT_LAT; tmp &= C_000104_MC_DISP1R_INIT_LAT; @@ -488,10 +491,16 @@ void rs690_bandwidth_update(struct radeon_device *rdev) priority_mark12.full = 0; if (wm1.priority_mark_max.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark_max.full; - WREG32(R_006548_D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02)); - WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02)); - WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12)); - WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12)); + d1mode_priority_a_cnt = rfixed_trunc(priority_mark02); + d2mode_priority_a_cnt = rfixed_trunc(priority_mark12); + if (rdev->disp_priority == 2) { + d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); + d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); + } + WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); + WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); + WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); + WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } else if (mode0) { if (rfixed_trunc(wm0.dbpp) > 64) a.full = rfixed_mul(wm0.dbpp, wm0.num_line_pair); @@ -518,8 +527,11 @@ void rs690_bandwidth_update(struct radeon_device *rdev) priority_mark02.full = 0; if (wm0.priority_mark_max.full > priority_mark02.full) priority_mark02.full = wm0.priority_mark_max.full; - WREG32(R_006548_D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02)); - WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02)); + d1mode_priority_a_cnt = rfixed_trunc(priority_mark02); + if (rdev->disp_priority == 2) + d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); + WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); + WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, S_006D48_D2MODE_PRIORITY_A_OFF(1)); WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, @@ -550,12 +562,15 @@ void rs690_bandwidth_update(struct radeon_device *rdev) priority_mark12.full = 0; if (wm1.priority_mark_max.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark_max.full; + d2mode_priority_a_cnt = rfixed_trunc(priority_mark12); + if (rdev->disp_priority == 2) + d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); WREG32(R_006548_D1MODE_PRIORITY_A_CNT, S_006548_D1MODE_PRIORITY_A_OFF(1)); WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, S_00654C_D1MODE_PRIORITY_B_OFF(1)); - WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12)); - WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12)); + WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); + WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } } diff --git a/drivers/gpu/drm/radeon/rs690d.h b/drivers/gpu/drm/radeon/rs690d.h index 62d31e7a897..36e6398a98a 100644 --- a/drivers/gpu/drm/radeon/rs690d.h +++ b/drivers/gpu/drm/radeon/rs690d.h @@ -182,6 +182,9 @@ #define S_006548_D1MODE_PRIORITY_A_OFF(x) (((x) & 0x1) << 16) #define G_006548_D1MODE_PRIORITY_A_OFF(x) (((x) >> 16) & 0x1) #define C_006548_D1MODE_PRIORITY_A_OFF 0xFFFEFFFF +#define S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(x) (((x) & 0x1) << 20) +#define G_006548_D1MODE_PRIORITY_A_ALWAYS_ON(x) (((x) >> 20) & 0x1) +#define C_006548_D1MODE_PRIORITY_A_ALWAYS_ON 0xFFEFFFFF #define S_006548_D1MODE_PRIORITY_A_FORCE_MASK(x) (((x) & 0x1) << 24) #define G_006548_D1MODE_PRIORITY_A_FORCE_MASK(x) (((x) >> 24) & 0x1) #define C_006548_D1MODE_PRIORITY_A_FORCE_MASK 0xFEFFFFFF diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index d94291add6d..1cf233f7e51 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -1016,7 +1016,7 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) struct drm_display_mode *mode1 = NULL; struct rv515_watermark wm0; struct rv515_watermark wm1; - u32 tmp; + u32 tmp, d1mode_priority_a_cnt, d2mode_priority_a_cnt; fixed20_12 priority_mark02, priority_mark12, fill_rate; fixed20_12 a, b; @@ -1084,10 +1084,16 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) priority_mark12.full = 0; if (wm1.priority_mark_max.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark_max.full; - WREG32(D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02)); - WREG32(D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02)); - WREG32(D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12)); - WREG32(D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12)); + d1mode_priority_a_cnt = rfixed_trunc(priority_mark02); + d2mode_priority_a_cnt = rfixed_trunc(priority_mark12); + if (rdev->disp_priority == 2) { + d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; + d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; + } + WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); + WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); + WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); + WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } else if (mode0) { if (rfixed_trunc(wm0.dbpp) > 64) a.full = rfixed_div(wm0.dbpp, wm0.num_line_pair); @@ -1114,8 +1120,11 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) priority_mark02.full = 0; if (wm0.priority_mark_max.full > priority_mark02.full) priority_mark02.full = wm0.priority_mark_max.full; - WREG32(D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02)); - WREG32(D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02)); + d1mode_priority_a_cnt = rfixed_trunc(priority_mark02); + if (rdev->disp_priority == 2) + d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; + WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); + WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); WREG32(D2MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF); WREG32(D2MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF); } else { @@ -1144,10 +1153,13 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) priority_mark12.full = 0; if (wm1.priority_mark_max.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark_max.full; + d2mode_priority_a_cnt = rfixed_trunc(priority_mark12); + if (rdev->disp_priority == 2) + d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; WREG32(D1MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF); WREG32(D1MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF); - WREG32(D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12)); - WREG32(D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12)); + WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); + WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } } @@ -1157,6 +1169,8 @@ void rv515_bandwidth_update(struct radeon_device *rdev) struct drm_display_mode *mode0 = NULL; struct drm_display_mode *mode1 = NULL; + radeon_update_display_priority(rdev); + if (rdev->mode_info.crtcs[0]->base.enabled) mode0 = &rdev->mode_info.crtcs[0]->base.mode; if (rdev->mode_info.crtcs[1]->base.enabled) @@ -1166,7 +1180,8 @@ void rv515_bandwidth_update(struct radeon_device *rdev) * modes if the user specifies HIGH for displaypriority * option. */ - if (rdev->disp_priority == 2) { + if ((rdev->disp_priority == 2) && + (rdev->family == CHIP_RV515)) { tmp = RREG32_MC(MC_MISC_LAT_TIMER); tmp &= ~MC_DISP1R_INIT_LAT_MASK; tmp &= ~MC_DISP0R_INIT_LAT_MASK; From c414a117c6094c3f86b533f97beaf45ef9075f03 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 30 Mar 2010 17:22:32 -0400 Subject: [PATCH 426/478] drm/radeon/kms: disable MSI on IGP chips Doesn't seem to work reliably and the pci quirks don't always work. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 68519b406ca..a212041e8b0 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -114,13 +114,11 @@ int radeon_irq_kms_init(struct radeon_device *rdev) } /* enable msi */ rdev->msi_enabled = 0; - /* MSIs don't seem to work on my rs780; - * not sure about rs880 or other rs780s. - * Needs more investigation. + /* MSIs don't seem to work reliably on all IGP + * chips. Disable MSI on them for now. */ if ((rdev->family >= CHIP_RV380) && - (rdev->family != CHIP_RS780) && - (rdev->family != CHIP_RS880)) { + (!(rdev->flags & RADEON_IS_IGP))) { int ret = pci_enable_msi(rdev->pdev); if (!ret) { rdev->msi_enabled = 1; From ac1aade6876465060ebf9a71675dcb7305f0bafa Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 14 Mar 2010 12:22:44 -0400 Subject: [PATCH 427/478] drm/radeon/kms: use new pre/post_xfer i2c bit algo hooks This allows us to remove the internal bit algo bus used by the radeon i2c algo. We now register a radeon algo adapter if the gpio line is hw capable and the hw inplementation is available, otherwise we register a bit algo adapter. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 2 +- drivers/gpu/drm/radeon/radeon_i2c.c | 133 ++++++++++----------- drivers/gpu/drm/radeon/radeon_mode.h | 8 +- 3 files changed, 64 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index ee0083f982d..60d59816b94 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -940,7 +940,7 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector) if (radeon_connector->edid) kfree(radeon_connector->edid); if (radeon_dig_connector->dp_i2c_bus) - radeon_i2c_destroy_dp(radeon_dig_connector->dp_i2c_bus); + radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus); kfree(radeon_connector->con_priv); drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index f007fcb1191..352110fd68f 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -59,6 +59,7 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector) return false; } +/* bit banging i2c */ static void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state) { @@ -181,6 +182,24 @@ static void set_data(void *i2c_priv, int data) WREG32(rec->en_data_reg, val); } +static int pre_xfer(struct i2c_adapter *i2c_adap) +{ + struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap); + + radeon_i2c_do_lock(i2c, 1); + + return 0; +} + +static void post_xfer(struct i2c_adapter *i2c_adap) +{ + struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap); + + radeon_i2c_do_lock(i2c, 0); +} + +/* hw i2c */ + static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) { u32 sclk = radeon_get_engine_clock(rdev); @@ -757,26 +776,13 @@ done: return ret; } -static int radeon_sw_i2c_xfer(struct i2c_adapter *i2c_adap, +static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) -{ - struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap); - int ret; - - radeon_i2c_do_lock(i2c, 1); - ret = i2c_transfer(&i2c->algo.radeon.bit_adapter, msgs, num); - radeon_i2c_do_lock(i2c, 0); - - return ret; -} - -static int radeon_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg *msgs, int num) { struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap); struct radeon_device *rdev = i2c->dev->dev_private; struct radeon_i2c_bus_rec *rec = &i2c->rec; - int ret; + int ret = 0; switch (rdev->family) { case CHIP_R100: @@ -797,16 +803,12 @@ static int radeon_i2c_xfer(struct i2c_adapter *i2c_adap, case CHIP_RV410: case CHIP_RS400: case CHIP_RS480: - if (rec->hw_capable) - ret = r100_hw_i2c_xfer(i2c_adap, msgs, num); - else - ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num); + ret = r100_hw_i2c_xfer(i2c_adap, msgs, num); break; case CHIP_RS600: case CHIP_RS690: case CHIP_RS740: /* XXX fill in hw i2c implementation */ - ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num); break; case CHIP_RV515: case CHIP_R520: @@ -814,20 +816,16 @@ static int radeon_i2c_xfer(struct i2c_adapter *i2c_adap, case CHIP_RV560: case CHIP_RV570: case CHIP_R580: - if (rec->hw_capable) { - if (rec->mm_i2c) - ret = r100_hw_i2c_xfer(i2c_adap, msgs, num); - else - ret = r500_hw_i2c_xfer(i2c_adap, msgs, num); - } else - ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num); + if (rec->mm_i2c) + ret = r100_hw_i2c_xfer(i2c_adap, msgs, num); + else + ret = r500_hw_i2c_xfer(i2c_adap, msgs, num); break; case CHIP_R600: case CHIP_RV610: case CHIP_RV630: case CHIP_RV670: /* XXX fill in hw i2c implementation */ - ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num); break; case CHIP_RV620: case CHIP_RV635: @@ -838,7 +836,6 @@ static int radeon_i2c_xfer(struct i2c_adapter *i2c_adap, case CHIP_RV710: case CHIP_RV740: /* XXX fill in hw i2c implementation */ - ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num); break; case CHIP_CEDAR: case CHIP_REDWOOD: @@ -846,7 +843,6 @@ static int radeon_i2c_xfer(struct i2c_adapter *i2c_adap, case CHIP_CYPRESS: case CHIP_HEMLOCK: /* XXX fill in hw i2c implementation */ - ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num); break; default: DRM_ERROR("i2c: unhandled radeon chip\n"); @@ -857,20 +853,21 @@ static int radeon_i2c_xfer(struct i2c_adapter *i2c_adap, return ret; } -static u32 radeon_i2c_func(struct i2c_adapter *adap) +static u32 radeon_hw_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static const struct i2c_algorithm radeon_i2c_algo = { - .master_xfer = radeon_i2c_xfer, - .functionality = radeon_i2c_func, + .master_xfer = radeon_hw_i2c_xfer, + .functionality = radeon_hw_i2c_func, }; struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, struct radeon_i2c_bus_rec *rec, const char *name) { + struct radeon_device *rdev = dev->dev_private; struct radeon_i2c_chan *i2c; int ret; @@ -878,37 +875,41 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, if (i2c == NULL) return NULL; - /* set the internal bit adapter */ - i2c->algo.radeon.bit_adapter.owner = THIS_MODULE; - i2c_set_adapdata(&i2c->algo.radeon.bit_adapter, i2c); - sprintf(i2c->algo.radeon.bit_adapter.name, "Radeon internal i2c bit bus %s", name); - i2c->algo.radeon.bit_adapter.algo_data = &i2c->algo.radeon.bit_data; - i2c->algo.radeon.bit_data.setsda = set_data; - i2c->algo.radeon.bit_data.setscl = set_clock; - i2c->algo.radeon.bit_data.getsda = get_data; - i2c->algo.radeon.bit_data.getscl = get_clock; - i2c->algo.radeon.bit_data.udelay = 20; - /* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always - * make this, 2 jiffies is a lot more reliable */ - i2c->algo.radeon.bit_data.timeout = 2; - i2c->algo.radeon.bit_data.data = i2c; - ret = i2c_bit_add_bus(&i2c->algo.radeon.bit_adapter); - if (ret) { - DRM_ERROR("Failed to register internal bit i2c %s\n", name); - goto out_free; - } - /* set the radeon i2c adapter */ - i2c->dev = dev; i2c->rec = *rec; i2c->adapter.owner = THIS_MODULE; + i2c->dev = dev; i2c_set_adapdata(&i2c->adapter, i2c); - sprintf(i2c->adapter.name, "Radeon i2c %s", name); - i2c->adapter.algo_data = &i2c->algo.radeon; - i2c->adapter.algo = &radeon_i2c_algo; - ret = i2c_add_adapter(&i2c->adapter); - if (ret) { - DRM_ERROR("Failed to register i2c %s\n", name); - goto out_free; + if (rec->hw_capable && + ((rdev->family <= CHIP_RS480) || + ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580)))) { + /* set the radeon hw i2c adapter */ + sprintf(i2c->adapter.name, "Radeon i2c hw bus %s", name); + i2c->adapter.algo = &radeon_i2c_algo; + ret = i2c_add_adapter(&i2c->adapter); + if (ret) { + DRM_ERROR("Failed to register hw i2c %s\n", name); + goto out_free; + } + } else { + /* set the radeon bit adapter */ + sprintf(i2c->adapter.name, "Radeon i2c bit bus %s", name); + i2c->adapter.algo_data = &i2c->algo.bit; + i2c->algo.bit.pre_xfer = pre_xfer; + i2c->algo.bit.post_xfer = post_xfer; + i2c->algo.bit.setsda = set_data; + i2c->algo.bit.setscl = set_clock; + i2c->algo.bit.getsda = get_data; + i2c->algo.bit.getscl = get_clock; + i2c->algo.bit.udelay = 20; + /* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always + * make this, 2 jiffies is a lot more reliable */ + i2c->algo.bit.timeout = 2; + i2c->algo.bit.data = i2c; + ret = i2c_bit_add_bus(&i2c->adapter); + if (ret) { + DRM_ERROR("Failed to register bit i2c %s\n", name); + goto out_free; + } } return i2c; @@ -953,16 +954,6 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) { if (!i2c) return; - i2c_del_adapter(&i2c->algo.radeon.bit_adapter); - i2c_del_adapter(&i2c->adapter); - kfree(i2c); -} - -void radeon_i2c_destroy_dp(struct radeon_i2c_chan *i2c) -{ - if (!i2c) - return; - i2c_del_adapter(&i2c->adapter); kfree(i2c); } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 55a41757eed..0b8e32776b1 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -173,17 +173,12 @@ struct radeon_pll { enum radeon_pll_algo algo; }; -struct i2c_algo_radeon_data { - struct i2c_adapter bit_adapter; - struct i2c_algo_bit_data bit_data; -}; - struct radeon_i2c_chan { struct i2c_adapter adapter; struct drm_device *dev; union { + struct i2c_algo_bit_data bit; struct i2c_algo_dp_aux_data dp; - struct i2c_algo_radeon_data radeon; } algo; struct radeon_i2c_bus_rec rec; }; @@ -435,7 +430,6 @@ extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, struct radeon_i2c_bus_rec *rec, const char *name); extern void radeon_i2c_destroy(struct radeon_i2c_chan *i2c); -extern void radeon_i2c_destroy_dp(struct radeon_i2c_chan *i2c); extern void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus, u8 slave_addr, u8 addr, From e2b0a8e1e697dbcd62574a32f4f96151d21bdd36 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Mar 2010 02:07:37 -0400 Subject: [PATCH 428/478] drm/radeon/kms: add hw_i2c module option Turn off hw i2c by default except for mm i2c which is hw only until we sort out the remaining prescale issues on older chips. hw i2c can be enabled with hw_i2c=1. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_drv.c | 4 ++++ drivers/gpu/drm/radeon/radeon_i2c.c | 8 +++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 1710b9e3ef7..034218c3dbb 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -92,6 +92,7 @@ extern int radeon_new_pll; extern int radeon_dynpm; extern int radeon_audio; extern int radeon_disp_priority; +extern int radeon_hw_i2c; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 6fd511eec96..055a51732dc 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -93,6 +93,7 @@ int radeon_new_pll = -1; int radeon_dynpm = -1; int radeon_audio = 1; int radeon_disp_priority = 0; +int radeon_hw_i2c = 0; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -139,6 +140,9 @@ module_param_named(audio, radeon_audio, int, 0444); MODULE_PARM_DESC(disp_priority, "Display Priority (0 = auto, 1 = normal, 2 = high)"); module_param_named(disp_priority, radeon_disp_priority, int, 0444); +MODULE_PARM_DESC(hw_i2c, "hw i2c engine enable (0 = disable)"); +module_param_named(hw_i2c, radeon_hw_i2c, int, 0444); + static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 352110fd68f..5def6f5dff3 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -879,9 +879,11 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, i2c->adapter.owner = THIS_MODULE; i2c->dev = dev; i2c_set_adapdata(&i2c->adapter, i2c); - if (rec->hw_capable && - ((rdev->family <= CHIP_RS480) || - ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580)))) { + if (rec->mm_i2c || + (rec->hw_capable && + radeon_hw_i2c && + ((rdev->family <= CHIP_RS480) || + ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) { /* set the radeon hw i2c adapter */ sprintf(i2c->adapter.name, "Radeon i2c hw bus %s", name); i2c->adapter.algo = &radeon_i2c_algo; From 30d1872d9eb3663b4cf7bdebcbf5cd465674cced Mon Sep 17 00:00:00 2001 From: Nikolaus Schulz Date: Thu, 1 Apr 2010 02:21:10 +0900 Subject: [PATCH 429/478] fat: fix buffer overflow in vfat_create_shortname() When using the string representation of a random counter as part of the base name, ensure that it is no longer than 4 bytes. Since we are repeatedly decrementing the counter in a loop until we have found a unique base name, the counter may wrap around zero; therefore, it is not enough to mask its higher bits before entering the loop, this must be done inside the loop. [hirofumi@mail.parknet.co.jp: use snprintf()] Signed-off-by: Nikolaus Schulz Cc: stable@kernel.org Signed-off-by: OGAWA Hirofumi Signed-off-by: Linus Torvalds --- fs/fat/namei_vfat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index c1ef5015486..6fcc7e71fba 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -309,7 +309,7 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, { struct fat_mount_options *opts = &MSDOS_SB(dir->i_sb)->options; wchar_t *ip, *ext_start, *end, *name_start; - unsigned char base[9], ext[4], buf[8], *p; + unsigned char base[9], ext[4], buf[5], *p; unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; int chl, chi; int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen; @@ -467,7 +467,7 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, return 0; } - i = jiffies & 0xffff; + i = jiffies; sz = (jiffies >> 16) & 0x7; if (baselen > 2) { baselen = numtail2_baselen; @@ -476,7 +476,7 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, name_res[baselen + 4] = '~'; name_res[baselen + 5] = '1' + sz; while (1) { - sprintf(buf, "%04X", i); + snprintf(buf, sizeof(buf), "%04X", i & 0xffff); memcpy(&name_res[baselen], buf, 4); if (vfat_find_form(dir, name_res) < 0) break; From 167215118a88dd56a1ab8c8d33e279d6d40f57b6 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 2 Mar 2010 22:24:12 +0100 Subject: [PATCH 430/478] asus-laptop: fix warning in asus_handle_init In function 'asus_laptop_get_info': warning: passing argument 3 of 'asus_handle_init' from incompatible pointer type note: expected 'char **' but argument is of type 'const char **' Introduced by commit c21085108a02e1b838c34f3650c8cc9fbd178615 ("asus-laptop: fix style problems reported by checkpath.pl"). Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index db5f7db2ba3..475ab50732a 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -139,7 +139,7 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " /* Backlight */ static acpi_handle lcd_switch_handle; -static const char *lcd_switch_paths[] = { +static char *lcd_switch_paths[] = { "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ @@ -153,7 +153,7 @@ static const char *lcd_switch_paths[] = { #define METHOD_SWITCH_DISPLAY "SDSP" static acpi_handle display_get_handle; -static const char *display_get_paths[] = { +static char *display_get_paths[] = { /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ "\\_SB.PCI0.P0P1.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */ From ee027e4aed3077c4bb3b585c67528eec0e7222df Mon Sep 17 00:00:00 2001 From: Yong Wang Date: Sun, 21 Mar 2010 10:26:34 +0800 Subject: [PATCH 431/478] eeepc-wmi: new driver for WMI based hotkeys on Eee PC laptops Add a WMI driver for Eee PC laptops. Currently it only supports hotkeys. Signed-off-by: Yong Wang Signed-off-by: Matthew Garrett Acked-by: Dmitry Torokhov --- drivers/platform/x86/Kconfig | 10 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/eeepc-wmi.c | 157 +++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 drivers/platform/x86/eeepc-wmi.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index e631dbeafd7..7bec4588c26 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -385,6 +385,16 @@ config EEEPC_LAPTOP If you have an Eee PC laptop, say Y or M here. +config EEEPC_WMI + tristate "Eee PC WMI Hotkey Driver (EXPERIMENTAL)" + depends on ACPI_WMI + depends on INPUT + depends on EXPERIMENTAL + ---help--- + Say Y here if you want to support WMI-based hotkeys on Eee PC laptops. + + To compile this driver as a module, choose M here: the module will + be called eeepc-wmi. config ACPI_WMI tristate "WMI" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 9cd9fa0a27e..a906490e353 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o +obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c new file mode 100644 index 00000000000..2466b7b7fb0 --- /dev/null +++ b/drivers/platform/x86/eeepc-wmi.c @@ -0,0 +1,157 @@ +/* + * Eee PC WMI hotkey driver + * + * Copyright(C) 2010 Intel Corporation. + * + * Portions based on wistron_btns.c: + * Copyright (C) 2005 Miloslav Trmac + * Copyright (C) 2005 Bernhard Rosenkraenzer + * Copyright (C) 2005 Dmitry Torokhov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Yong Wang "); +MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); +MODULE_LICENSE("GPL"); + +#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" + +MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); + +#define NOTIFY_BRNUP_MIN 0x11 +#define NOTIFY_BRNUP_MAX 0x1f +#define NOTIFY_BRNDOWN_MIN 0x20 +#define NOTIFY_BRNDOWN_MAX 0x2e + +static const struct key_entry eeepc_wmi_keymap[] = { + /* Sleep already handled via generic ACPI code */ + { KE_KEY, 0x5d, { KEY_WLAN } }, + { KE_KEY, 0x32, { KEY_MUTE } }, + { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, + { KE_KEY, 0x30, { KEY_VOLUMEUP } }, + { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, + { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } }, + { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, + { KE_END, 0}, +}; + +static struct input_dev *eeepc_wmi_input_dev; + +static void eeepc_wmi_notify(u32 value, void *context) +{ + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + int code; + + status = wmi_get_event_data(value, &response); + if (status != AE_OK) { + pr_err("EEEPC WMI: bad event status 0x%x\n", status); + return; + } + + obj = (union acpi_object *)response.pointer; + + if (obj && obj->type == ACPI_TYPE_INTEGER) { + code = obj->integer.value; + + if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) + code = NOTIFY_BRNUP_MIN; + else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) + code = NOTIFY_BRNDOWN_MIN; + + if (!sparse_keymap_report_event(eeepc_wmi_input_dev, + code, 1, true)) + pr_info("EEEPC WMI: Unknown key %x pressed\n", code); + } + + kfree(obj); +} + +static int eeepc_wmi_input_setup(void) +{ + int err; + + eeepc_wmi_input_dev = input_allocate_device(); + if (!eeepc_wmi_input_dev) + return -ENOMEM; + + eeepc_wmi_input_dev->name = "Eee PC WMI hotkeys"; + eeepc_wmi_input_dev->phys = "wmi/input0"; + eeepc_wmi_input_dev->id.bustype = BUS_HOST; + + err = sparse_keymap_setup(eeepc_wmi_input_dev, eeepc_wmi_keymap, NULL); + if (err) + goto err_free_dev; + + err = input_register_device(eeepc_wmi_input_dev); + if (err) + goto err_free_keymap; + + return 0; + +err_free_keymap: + sparse_keymap_free(eeepc_wmi_input_dev); +err_free_dev: + input_free_device(eeepc_wmi_input_dev); + return err; +} + +static int __init eeepc_wmi_init(void) +{ + int err; + acpi_status status; + + if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID)) { + pr_warning("EEEPC WMI: No known WMI GUID found\n"); + return -ENODEV; + } + + err = eeepc_wmi_input_setup(); + if (err) + return err; + + status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, + eeepc_wmi_notify, NULL); + if (ACPI_FAILURE(status)) { + sparse_keymap_free(eeepc_wmi_input_dev); + input_unregister_device(eeepc_wmi_input_dev); + pr_err("EEEPC WMI: Unable to register notify handler - %d\n", + status); + return -ENODEV; + } + + return 0; +} + +static void __exit eeepc_wmi_exit(void) +{ + wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); + sparse_keymap_free(eeepc_wmi_input_dev); + input_unregister_device(eeepc_wmi_input_dev); +} + +module_init(eeepc_wmi_init); +module_exit(eeepc_wmi_exit); From fb668c2fed628179c7aa409a0de39a2b96bed18c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 31 Mar 2010 14:42:11 -0400 Subject: [PATCH 432/478] drm/radeon/kms/evergreen: get DP working Need to enable the VID stream after link training Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index cbc6fa20cf5..52d6f96f274 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1044,16 +1044,25 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) if (is_dig) { switch (mode) { case DRM_MODE_DPMS_ON: - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); - { + if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + dp_link_train(encoder, connector); + if (ASIC_IS_DCE4(rdev)) + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON); } + if (!ASIC_IS_DCE4(rdev)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + if (!ASIC_IS_DCE4(rdev)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { + if (ASIC_IS_DCE4(rdev)) + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF); + } break; } } else { From 9e5786bd14cb9ffe29ebe66d41cedf03311b0d30 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 31 Mar 2010 13:38:56 +1000 Subject: [PATCH 433/478] drm/radeon/kms: add sanity check to wptr. If we resume in a bad way, we'll get 0xffffffff in wptr, and then oops with no console. This just adds a sanity check so that we can avoid the oops and hopefully get more details out of people's systems. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 138ddd49dfc..c8f4b0300b7 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -744,6 +744,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) udelay(10); rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); rdev->cp.wptr = RREG32(RADEON_CP_RB_WPTR); + /* protect against crazy HW on resume */ + rdev->cp.wptr &= rdev->cp.ptr_mask; /* Set cp mode to bus mastering & enable cp*/ WREG32(RADEON_CP_CSQ_MODE, REG_SET(RADEON_INDIRECT2_START, indirect2_start) | From 08a370fa758fae7e387274ca3571ce625d7f829b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 31 Mar 2010 13:42:50 +1000 Subject: [PATCH 434/478] drm/radeon/kms: rs400/480 should set common registers. These GPUs should be setting these registers up also. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/rs400.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 590815c4700..626aaf082b1 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -390,6 +390,8 @@ static int rs400_startup(struct radeon_device *rdev) { int r; + r100_set_common_regs(rdev); + rs400_mc_program(rdev); /* Resume clock */ r300_clock_startup(rdev); From d668046c13024d74af7d04a124ba55f406380fe7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 31 Mar 2010 13:41:35 +1000 Subject: [PATCH 435/478] drm/radeon/kms: enable ACPI powermanagement mode on radeon gpus. Some GPUs have an APM/ACPI PM mode selection switch and some BIOSes set this to APM. We really want this in ACPI mode for Linux. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 7 +++++++ drivers/gpu/drm/radeon/radeon_reg.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index c8f4b0300b7..3ae51ada1ab 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -1809,6 +1809,7 @@ void r100_set_common_regs(struct radeon_device *rdev) { struct drm_device *dev = rdev->ddev; bool force_dac2 = false; + u32 tmp; /* set these so they don't interfere with anything */ WREG32(RADEON_OV0_SCALE_CNTL, 0); @@ -1880,6 +1881,12 @@ void r100_set_common_regs(struct radeon_device *rdev) WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); WREG32(RADEON_DAC_CNTL2, dac2_cntl); } + + /* switch PM block to ACPI mode */ + tmp = RREG32_PLL(RADEON_PLL_PWRMGT_CNTL); + tmp &= ~RADEON_PM_MODE_SEL; + WREG32_PLL(RADEON_PLL_PWRMGT_CNTL, tmp); + } /* diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 5c0dc082d33..eabbc9cf30a 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -346,6 +346,7 @@ # define RADEON_TVPLL_PWRMGT_OFF (1 << 30) # define RADEON_TVCLK_TURNOFF (1 << 31) #define RADEON_PLL_PWRMGT_CNTL 0x0015 /* PLL */ +# define RADEON_PM_MODE_SEL (1 << 13) # define RADEON_TCL_BYPASS_DISABLE (1 << 20) #define RADEON_CLR_CMP_CLR_3D 0x1a24 #define RADEON_CLR_CMP_CLR_DST 0x15c8 From eb1e79611cc9bfe21978230e3521e77ea2d7874a Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 23 Mar 2010 00:08:59 +0100 Subject: [PATCH 436/478] perf: Correctly align perf event tracing buffer The trace event buffer used by perf to record raw sample events is typed as an array of char and may then not be aligned to 8 by alloc_percpu(). But we need it to be aligned to 8 in sparc64 because we cast this buffer into a random structure type built by the TRACE_EVENT() macro to store the traces. So if a random 64 bits field is accessed inside, it may be not under an expected good alignment. Use an array of long instead to force the appropriate alignment, and perform a compile time check to ensure the size in byte of the buffer is a multiple of sizeof(long) so that its actual size doesn't get shrinked under us. This fixes unaligned accesses reported while using perf lock in sparc 64. Suggested-by: David Miller Suggested-by: Tejun Heo Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras Cc: Ingo Molnar Cc: David Miller Cc: Steven Rostedt --- kernel/trace/trace_event_perf.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 81f691eb3a3..0565bb42566 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -17,7 +17,12 @@ EXPORT_SYMBOL_GPL(perf_arch_fetch_caller_regs); static char *perf_trace_buf; static char *perf_trace_buf_nmi; -typedef typeof(char [PERF_MAX_TRACE_SIZE]) perf_trace_t ; +/* + * Force it to be aligned to unsigned long to avoid misaligned accesses + * suprises + */ +typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)]) + perf_trace_t; /* Count the events in use (per event id, not per instance) */ static int total_ref_count; @@ -130,6 +135,8 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type, char *trace_buf, *raw_data; int pc, cpu; + BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long)); + pc = preempt_count(); /* Protect the per cpu buffer, begin the rcu read side */ @@ -152,7 +159,7 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type, raw_data = per_cpu_ptr(trace_buf, cpu); /* zero the dead bytes from align to not leak stack to user */ - *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; + memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64)); entry = (struct trace_entry *)raw_data; tracing_generic_entry_update(entry, *irq_flags, pc); From e49a5bd38159dfb1928fd25b173bc9de4bbadb21 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 22 Mar 2010 19:40:03 +0100 Subject: [PATCH 437/478] perf: Use hot regs with software sched switch/migrate events Scheduler's task migration events don't work because they always pass NULL regs perf_sw_event(). The event hence gets filtered in perf_swevent_add(). Scheduler's context switches events use task_pt_regs() to get the context when the event occured which is a wrong thing to do as this won't give us the place in the kernel where we went to sleep but the place where we left userspace. The result is even more wrong if we switch from a kernel thread. Use the hot regs snapshot for both events as they belong to the non-interrupt/exception based events family. Unlike page faults or so that provide the regs matching the exact origin of the event, we need to save the current context. This makes the task migration event working and fix the context switch callchains and origin ip. Example: perf record -a -e cs Before: 10.91% ksoftirqd/0 0 [k] 0000000000000000 | --- (nil) perf_callchain perf_prepare_sample __perf_event_overflow perf_swevent_overflow perf_swevent_add perf_swevent_ctx_event do_perf_sw_event __perf_sw_event perf_event_task_sched_out schedule run_ksoftirqd kthread kernel_thread_helper After: 23.77% hald-addon-stor [kernel.kallsyms] [k] schedule | --- schedule | |--60.00%-- schedule_timeout | wait_for_common | wait_for_completion | blk_execute_rq | scsi_execute | scsi_execute_req | sr_test_unit_ready | | | |--66.67%-- sr_media_change | | media_changed | | cdrom_media_changed | | sr_block_media_changed | | check_disk_change | | cdrom_open v2: Always build perf_arch_fetch_caller_regs() now that software events need that too. They don't need it from modules, unlike trace events, so we keep the EXPORT_SYMBOL in trace_event_perf.c Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras Cc: Ingo Molnar Cc: David Miller --- arch/x86/kernel/cpu/perf_event.c | 2 -- include/linux/perf_event.h | 21 ++++++++++++++------- kernel/perf_event.c | 4 +--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 60398a0d947..5fb490c6ee5 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1702,7 +1702,6 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) return entry; } -#ifdef CONFIG_EVENT_TRACING void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip) { regs->ip = ip; @@ -1714,4 +1713,3 @@ void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int ski regs->cs = __KERNEL_CS; local_save_flags(regs->flags); } -#endif diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 95477038a72..c8e37544040 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -842,13 +842,6 @@ extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64); -static inline void -perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr) -{ - if (atomic_read(&perf_swevent_enabled[event_id])) - __perf_sw_event(event_id, nr, nmi, regs, addr); -} - extern void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip); @@ -887,6 +880,20 @@ static inline void perf_fetch_caller_regs(struct pt_regs *regs, int skip) return perf_arch_fetch_caller_regs(regs, ip, skip); } +static inline void +perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr) +{ + if (atomic_read(&perf_swevent_enabled[event_id])) { + struct pt_regs hot_regs; + + if (!regs) { + perf_fetch_caller_regs(&hot_regs, 1); + regs = &hot_regs; + } + __perf_sw_event(event_id, nr, nmi, regs, addr); + } +} + extern void __perf_event_mmap(struct vm_area_struct *vma); static inline void perf_event_mmap(struct vm_area_struct *vma) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 574ee58a304..b0feb4795af 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1164,11 +1164,9 @@ void perf_event_task_sched_out(struct task_struct *task, struct perf_event_context *ctx = task->perf_event_ctxp; struct perf_event_context *next_ctx; struct perf_event_context *parent; - struct pt_regs *regs; int do_switch = 1; - regs = task_pt_regs(task); - perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, regs, 0); + perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0); if (likely(!ctx || !cpuctx->task_ctx)) return; From ab310b5edb8b601bcb02491ed6f7676da4fd1757 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Tue, 30 Mar 2010 14:05:07 -0500 Subject: [PATCH 438/478] x86,kgdb: Always initialize the hw breakpoint attribute It is required to call hw_breakpoint_init() on an attr before using it in any other calls. This fixes the problem where kgdb will sometimes fail to initialize on x86_64. Signed-off-by: Jason Wessel Cc: Ingo Molnar Cc: 2.6.33 LKML-Reference: <1269975907-27602-1-git-send-email-jason.wessel@windriver.com> Signed-off-by: Frederic Weisbecker --- arch/x86/kernel/kgdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index bfba6019d76..b2258ca9100 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -618,8 +618,8 @@ int kgdb_arch_init(void) * portion of kgdb because this operation requires mutexs to * complete. */ + hw_breakpoint_init(&attr); attr.bp_addr = (unsigned long)kgdb_arch_init; - attr.type = PERF_TYPE_BREAKPOINT; attr.bp_len = HW_BREAKPOINT_LEN_1; attr.bp_type = HW_BREAKPOINT_W; attr.disabled = 1; From 0c4ec16b86e6a823bc6e9fbe08a724d517eb3c24 Mon Sep 17 00:00:00 2001 From: "Steven J. Magnani" Date: Wed, 24 Feb 2010 14:54:15 -0600 Subject: [PATCH 439/478] microblaze: Fix "kstack=" parsing The "kstack=" command line parameter is not parsed correctly. All proper values are interpreted as zero. Signed-off-by: Steven J. Magnani Signed-off-by: Michal Simek --- arch/microblaze/kernel/traps.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c index eaaaf805f31..5e4570ef515 100644 --- a/arch/microblaze/kernel/traps.c +++ b/arch/microblaze/kernel/traps.c @@ -22,13 +22,11 @@ void trap_init(void) __enable_hw_exceptions(); } -static int kstack_depth_to_print = 24; +static unsigned long kstack_depth_to_print = 24; static int __init kstack_setup(char *s) { - kstack_depth_to_print = strict_strtoul(s, 0, NULL); - - return 1; + return !strict_strtoul(s, 0, &kstack_depth_to_print); } __setup("kstack=", kstack_setup); From 699d17bc14edceb710998349fa74e66be3042372 Mon Sep 17 00:00:00 2001 From: Arun Bhanu Date: Fri, 12 Mar 2010 16:31:40 +0800 Subject: [PATCH 440/478] microblaze: Add a missing single quote to make 'make help' happy 'make ARCH=microblaze help' fails with the following error due to a missing single quote. /bin/sh: -c: line 0: unexpected EOF while looking for matching `'' /bin/sh: -c: line 1: syntax error: unexpected end of file make: *** [help] Error 2 Signed-off-by: Arun Bhanu Signed-off-by: Michal Simek --- arch/microblaze/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile index 836832dd9b2..538afcef331 100644 --- a/arch/microblaze/Makefile +++ b/arch/microblaze/Makefile @@ -84,7 +84,7 @@ define archhelp echo '* linux.bin - Create raw binary' echo ' linux.bin.gz - Create compressed raw binary' echo ' simpleImage.
- ELF image with $(arch)/boot/dts/
.dts linked in' - echo ' - stripped elf with fdt blob + echo ' - stripped elf with fdt blob' echo ' simpleImage.
.unstrip - full ELF image with fdt blob' echo ' *_defconfig - Select default config from arch/microblaze/configs' echo '' From 8a8804f1ab2d3226bfa9f9a64c4316f9a01f8ee9 Mon Sep 17 00:00:00 2001 From: Arun Bhanu Date: Wed, 17 Mar 2010 16:06:03 +0800 Subject: [PATCH 441/478] microblaze: Fix Makefile to delete build generated files 'make clean' does not to delete the following build generated file: arch/microblaze/boot/linux.bin.ub 'make mrproper' does not to delete the following build generated files: arch/microblaze/boot/simpleImage.* Fix the Makefile to delete these build generated files. See [1] for a discussion on why simpleImage.* files are deleted with 'make mrproper' and not with 'make clean'. [1] http://lkml.org/lkml/2010/3/12/96 Signed-off-by: Arun Bhanu Signed-off-by: Michal Simek --- arch/microblaze/Makefile | 2 ++ arch/microblaze/boot/Makefile | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile index 538afcef331..72f6e858374 100644 --- a/arch/microblaze/Makefile +++ b/arch/microblaze/Makefile @@ -94,3 +94,5 @@ define archhelp echo ' name of a dts file from the arch/microblaze/boot/dts/ directory' echo ' (minus the .dts extension).' endef + +MRPROPER_FILES += $(boot)/simpleImage.* diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index 902cf9846c3..a1fc3242178 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -64,4 +64,4 @@ $(obj)/%.dtb: $(dtstree)/%.dts FORCE clean-kernel += linux.bin linux.bin.gz simpleImage.* -clean-files += *.dtb simpleImage.*.unstrip +clean-files += *.dtb simpleImage.*.unstrip linux.bin.ub From 6fa114e0f18fb33b66fd5ee9037052830198a8c4 Mon Sep 17 00:00:00 2001 From: Arun Bhanu Date: Wed, 17 Mar 2010 16:06:04 +0800 Subject: [PATCH 442/478] microblaze: Makefile cleanups If CONFIG_INITRAMFS_SOURCE is set, "scripts/gen_initramfs_list.sh" checks if the cpio image exists. Remove the duplicate check from the Makefile. Remove the "clean-kernel" variable which is unused in the Makefile and is not used by the Kbuild. Signed-off-by: Arun Bhanu Signed-off-by: Michal Simek --- arch/microblaze/boot/Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index a1fc3242178..57f50c2371c 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -23,8 +23,6 @@ $(obj)/system.dtb: $(obj)/$(DTB).dtb endif $(obj)/linux.bin: vmlinux FORCE - [ -n $(CONFIG_INITRAMFS_SOURCE) ] && [ ! -e $(CONFIG_INITRAMFS_SOURCE) ] && \ - touch $(CONFIG_INITRAMFS_SOURCE) || echo "No CPIO image" $(call if_changed,objcopy) $(call if_changed,uimage) @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' @@ -62,6 +60,4 @@ quiet_cmd_dtc = DTC $@ $(obj)/%.dtb: $(dtstree)/%.dts FORCE $(call if_changed,dtc) -clean-kernel += linux.bin linux.bin.gz simpleImage.* - clean-files += *.dtb simpleImage.*.unstrip linux.bin.ub From 4009819cf90c26e3ec7b0ed949d5ff37c568e197 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 3 Mar 2010 17:03:21 +0100 Subject: [PATCH 443/478] microblaze: Remove memset in free_init_pages We don't need to do it. Signed-off-by: Michal Simek --- arch/microblaze/mm/init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c index 1608e2e1a44..45b4bce606b 100644 --- a/arch/microblaze/mm/init.c +++ b/arch/microblaze/mm/init.c @@ -165,7 +165,6 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) for (addr = begin; addr < end; addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); - memset((void *)addr, 0xcc, PAGE_SIZE); free_page(addr); totalram_pages++; } From 40db0834337ef0cde586feeb5588e45f0349098b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 5 Mar 2010 15:34:12 +0100 Subject: [PATCH 444/478] microblaze: Remove segment.h I would like to use asm-generic uaccess.h where are segment macros defined. This is just first step. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/processor.h | 1 - arch/microblaze/include/asm/segment.h | 49 ----------------------- arch/microblaze/include/asm/thread_info.h | 5 ++- arch/microblaze/include/asm/uaccess.h | 30 +++++++++++++- arch/microblaze/kernel/process.c | 1 + 5 files changed, 34 insertions(+), 52 deletions(-) delete mode 100644 arch/microblaze/include/asm/segment.h diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h index 563c6b9453f..8eeb09211ec 100644 --- a/arch/microblaze/include/asm/processor.h +++ b/arch/microblaze/include/asm/processor.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/arch/microblaze/include/asm/segment.h b/arch/microblaze/include/asm/segment.h deleted file mode 100644 index 0e7102c3fb1..00000000000 --- a/arch/microblaze/include/asm/segment.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2008-2009 Michal Simek - * Copyright (C) 2008-2009 PetaLogix - * Copyright (C) 2006 Atmark Techno, Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#ifndef _ASM_MICROBLAZE_SEGMENT_H -#define _ASM_MICROBLAZE_SEGMENT_H - -# ifndef __ASSEMBLY__ - -typedef struct { - unsigned long seg; -} mm_segment_t; - -/* - * On Microblaze the fs value is actually the top of the corresponding - * address space. - * - * The fs value determines whether argument validity checking should be - * performed or not. If get_fs() == USER_DS, checking is performed, with - * get_fs() == KERNEL_DS, checking is bypassed. - * - * For historical reasons, these macros are grossly misnamed. - * - * For non-MMU arch like Microblaze, KERNEL_DS and USER_DS is equal. - */ -# define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) - -# ifndef CONFIG_MMU -# define KERNEL_DS MAKE_MM_SEG(0) -# define USER_DS KERNEL_DS -# else -# define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) -# define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) -# endif - -# define get_ds() (KERNEL_DS) -# define get_fs() (current_thread_info()->addr_limit) -# define set_fs(val) (current_thread_info()->addr_limit = (val)) - -# define segment_eq(a, b) ((a).seg == (b).seg) - -# endif /* __ASSEMBLY__ */ -#endif /* _ASM_MICROBLAZE_SEGMENT_H */ diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h index 6e92885d381..b2ca80f6464 100644 --- a/arch/microblaze/include/asm/thread_info.h +++ b/arch/microblaze/include/asm/thread_info.h @@ -19,7 +19,6 @@ #ifndef __ASSEMBLY__ # include # include -# include /* * low level task data that entry.S needs immediate access to @@ -60,6 +59,10 @@ struct cpu_context { __u32 fsr; }; +typedef struct { + unsigned long seg; +} mm_segment_t; + struct thread_info { struct task_struct *task; /* main task structure */ struct exec_domain *exec_domain; /* execution domain */ diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 371bd6e56d9..a8f794d03c5 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -22,12 +22,40 @@ #include #include #include -#include #include #define VERIFY_READ 0 #define VERIFY_WRITE 1 +/* + * On Microblaze the fs value is actually the top of the corresponding + * address space. + * + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons, these macros are grossly misnamed. + * + * For non-MMU arch like Microblaze, KERNEL_DS and USER_DS is equal. + */ +# define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) + +# ifndef CONFIG_MMU +# define KERNEL_DS MAKE_MM_SEG(0) +# define USER_DS KERNEL_DS +# else +# define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) +# define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) +# endif + +# define get_ds() (KERNEL_DS) +# define get_fs() (current_thread_info()->addr_limit) +# define set_fs(val) (current_thread_info()->addr_limit = (val)) + +# define segment_eq(a, b) ((a).seg == (b).seg) + + #define __clear_user(addr, n) (memset((void *)(addr), 0, (n)), 0) #ifndef CONFIG_MMU diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 812f1bf06c9..35efb2f42d5 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c @@ -15,6 +15,7 @@ #include #include #include +#include /* for USER_DS macros */ #include void show_regs(struct pt_regs *regs) From 357bc3c9284b2fb201786176e8187d2273323bc1 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 5 Mar 2010 15:37:57 +0100 Subject: [PATCH 445/478] microblaze: Move exception_table_entry upward Just sort to be able remove whole block. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 31 +++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index a8f794d03c5..e2adad33950 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -55,6 +55,21 @@ # define segment_eq(a, b) ((a).seg == (b).seg) +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ +struct exception_table_entry { + unsigned long insn, fixup; +}; #define __clear_user(addr, n) (memset((void *)(addr), 0, (n)), 0) @@ -333,22 +348,6 @@ extern int __strnlen_user(const char __user *sstr, int len); extern unsigned long __copy_tofrom_user(void __user *to, const void __user *from, unsigned long size); -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ -struct exception_table_entry { - unsigned long insn, fixup; -}; - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ From 60a729f7bb936a9ab82b430de70a1952f560adf3 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 5 Mar 2010 15:49:53 +0100 Subject: [PATCH 446/478] microblaze: move noMMU __range_ok function to uaccess.h The same noMMU and MMU functions should be placed in one file. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 7 ++++++- arch/microblaze/mm/init.c | 8 -------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index e2adad33950..ce5defb259a 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -75,7 +75,12 @@ struct exception_table_entry { #ifndef CONFIG_MMU -extern int ___range_ok(unsigned long addr, unsigned long size); +/* Check against bounds of physical memory */ +static inline int ___range_ok(unsigned long addr, unsigned long size) +{ + return ((addr < memory_start) || + ((addr + size) > memory_end)); +} #define __range_ok(addr, size) \ ___range_ok((unsigned long)(addr), (unsigned long)(size)) diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c index 45b4bce606b..40bc10ede09 100644 --- a/arch/microblaze/mm/init.c +++ b/arch/microblaze/mm/init.c @@ -207,14 +207,6 @@ void __init mem_init(void) } #ifndef CONFIG_MMU -/* Check against bounds of physical memory */ -int ___range_ok(unsigned long addr, unsigned long size) -{ - return ((addr < memory_start) || - ((addr + size) > memory_end)); -} -EXPORT_SYMBOL(___range_ok); - int page_is_ram(unsigned long pfn) { return __range_ok(pfn, 0); From 40b1156db09ab2df48aa4970ddf4a27a17246f1f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 5 Mar 2010 16:50:01 +0100 Subject: [PATCH 447/478] microblaze: uaccess: fix clean user macro This is the first patch which does uaccess unification. I choosed to do several patches to be able to use bisect in future if any fault happens. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 89 +++++++++++++++++---------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index ce5defb259a..fdb1c1cf51a 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -71,8 +71,6 @@ struct exception_table_entry { unsigned long insn, fixup; }; -#define __clear_user(addr, n) (memset((void *)(addr), 0, (n)), 0) - #ifndef CONFIG_MMU /* Check against bounds of physical memory */ @@ -86,7 +84,31 @@ static inline int ___range_ok(unsigned long addr, unsigned long size) ___range_ok((unsigned long)(addr), (unsigned long)(size)) #define access_ok(type, addr, size) (__range_ok((addr), (size)) == 0) -#define __access_ok(add, size) (__range_ok((addr), (size)) == 0) + +#else + +/* + * Address is valid if: + * - "addr", "addr + size" and "size" are all below the limit + */ +#define access_ok(type, addr, size) \ + (get_fs().seg > (((unsigned long)(addr)) | \ + (size) | ((unsigned long)(addr) + (size)))) + +/* || printk("access_ok failed for %s at 0x%08lx (size %d), seg 0x%08x\n", + type?"WRITE":"READ",addr,size,get_fs().seg)) */ + +#endif + +#ifdef CONFIG_MMU +# define __FIXUP_SECTION ".section .fixup,\"ax\"\n" +# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" +#else +# define __FIXUP_SECTION ".section .discard,\"ax\"\n" +# define __EX_TABLE_SECTION ".section .discard,\"a\"\n" +#endif + +#ifndef CONFIG_MMU /* Undefined function to trigger linker error */ extern int bad_user_access_length(void); @@ -151,6 +173,9 @@ extern int bad_user_access_length(void); #define __copy_from_user_inatomic(to, from, n) \ (__copy_from_user((to), (from), (n))) +#define __clear_user(addr, n) (memset((void *)(addr), 0, (n)), 0) + +/* stejne s MMU */ static inline unsigned long clear_user(void *addr, unsigned long size) { if (access_ok(VERIFY_WRITE, addr, size)) @@ -166,17 +191,6 @@ extern long strnlen_user(const char *src, long count); #else /* CONFIG_MMU */ -/* - * Address is valid if: - * - "addr", "addr + size" and "size" are all below the limit - */ -#define access_ok(type, addr, size) \ - (get_fs().seg > (((unsigned long)(addr)) | \ - (size) | ((unsigned long)(addr) + (size)))) - -/* || printk("access_ok failed for %s at 0x%08lx (size %d), seg 0x%08x\n", - type?"WRITE":"READ",addr,size,get_fs().seg)) */ - /* * All the __XXX versions macros/functions below do not perform * access checking. It is assumed that the necessary checks have been @@ -297,27 +311,34 @@ __asm__ __volatile__ (" lwi %0, %1, 0; \ ); \ }) -/* - * Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. - */ -static inline int clear_user(char *to, int size) +/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ +static inline unsigned long __must_check __clear_user(void __user *to, + unsigned long n) { - if (size && access_ok(VERIFY_WRITE, to, size)) { - __asm__ __volatile__ (" \ - 1: \ - sb r0, %2, r0; \ - addik %0, %0, -1; \ - bneid %0, 1b; \ - addik %2, %2, 1; \ - 2: \ - .section __ex_table,\"a\"; \ - .word 1b,2b; \ - .section .text;" \ - : "=r"(size) \ - : "0"(size), "r"(to) - ); - } - return size; + /* normal memset with two words to __ex_table */ + __asm__ __volatile__ ( \ + "1: sb r0, %2, r0;" \ + " addik %0, %0, -1;" \ + " bneid %0, 1b;" \ + " addik %2, %2, 1;" \ + "2: " \ + __EX_TABLE_SECTION \ + ".word 1b,2b;" \ + ".previous;" \ + : "=r"(n) \ + : "0"(n), "r"(to) + ); + return n; +} + +static inline unsigned long __must_check clear_user(void __user *to, + unsigned long n) +{ + might_sleep(); + if (unlikely(!access_ok(VERIFY_WRITE, to, n))) + return n; + + return __clear_user(to, n); } #define __copy_from_user(to, from, n) copy_from_user((to), (from), (n)) From c77a9c4bb7b6e26400853c92d74ccc697c5e2f7e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 5 Mar 2010 18:03:53 +0100 Subject: [PATCH 448/478] microblaze: uaccess: fix __get_user_asm macro It is used __FIXUP_SECTION and __EX_TABLE_SECTION macros. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 33 ++++++++++++++------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index fdb1c1cf51a..531172e1d1f 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -231,24 +231,25 @@ extern long strnlen_user(const char *src, long count); __gu_err; \ }) -#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ -({ \ - __asm__ __volatile__ ( \ - "1:" insn " %1, %2, r0; \ - addk %0, r0, r0; \ - 2: \ - .section .fixup,\"ax\"; \ - 3: brid 2b; \ - addik %0, r0, %3; \ - .previous; \ - .section __ex_table,\"a\"; \ - .word 1b,3b; \ - .previous;" \ - : "=r"(__gu_err), "=r"(__gu_val) \ - : "r"(__gu_ptr), "i"(-EFAULT) \ - ); \ +#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ ( \ + "1:" insn " %1, %2, r0;" \ + " addk %0, r0, r0;" \ + "2: " \ + __FIXUP_SECTION \ + "3: brid 2b; " \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,3b;" \ + ".previous;" \ + : "=&r"(__gu_err), "=r"(__gu_val) \ + : "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ }) + #define __put_user(x, ptr) \ ({ \ __typeof__(*(ptr)) volatile __gu_val = (x); \ From 8b651aa4a7c047b848f3a7bdf0aba9449e6dc3d3 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 15:25:12 +0100 Subject: [PATCH 449/478] microblaze: uaccess: fix put_user and get_user macros Use FIXUP macros and resort them. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 100 +++++++++++++------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 531172e1d1f..1e8fa4b7611 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -197,16 +197,22 @@ extern long strnlen_user(const char *src, long count); * already performed before the finction (macro) is called. */ -#define get_user(x, ptr) \ -({ \ - access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) \ - ? __get_user((x), (ptr)) : -EFAULT; \ -}) - -#define put_user(x, ptr) \ -({ \ - access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) \ - ? __put_user((x), (ptr)) : -EFAULT; \ +#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ ( \ + "1:" insn " %1, %2, r0;" \ + " addk %0, r0, r0;" \ + "2: " \ + __FIXUP_SECTION \ + "3: brid 2b; " \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,3b;" \ + ".previous;" \ + : "=&r"(__gu_err), "=r"(__gu_val) \ + : "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ }) #define __get_user(x, ptr) \ @@ -231,24 +237,49 @@ extern long strnlen_user(const char *src, long count); __gu_err; \ }) -#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ +#define get_user(x, ptr) \ +({ \ + access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) \ + ? __get_user((x), (ptr)) : -EFAULT; \ +}) + +#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ ({ \ __asm__ __volatile__ ( \ "1:" insn " %1, %2, r0;" \ " addk %0, r0, r0;" \ "2: " \ __FIXUP_SECTION \ - "3: brid 2b; " \ + "3: brid 2b;" \ " addik %0, r0, %3;" \ ".previous;" \ __EX_TABLE_SECTION \ ".word 1b,3b;" \ ".previous;" \ - : "=&r"(__gu_err), "=r"(__gu_val) \ - : "r"(__gu_ptr), "i"(-EFAULT) \ + : "=&r"(__gu_err) \ + : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ ); \ }) +#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ (" lwi %0, %1, 0;" \ + "1: swi %0, %2, 0;" \ + " lwi %0, %1, 4;" \ + "2: swi %0, %2, 4;" \ + " addk %0, r0, r0;" \ + "3: " \ + __FIXUP_SECTION \ + "4: brid 3b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,4b,2b,4b;" \ + ".previous;" \ + : "=&r"(__gu_err) \ + : "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ +}) #define __put_user(x, ptr) \ ({ \ @@ -273,43 +304,10 @@ extern long strnlen_user(const char *src, long count); __gu_err; \ }) -#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \ -({ \ -__asm__ __volatile__ (" lwi %0, %1, 0; \ - 1: swi %0, %2, 0; \ - lwi %0, %1, 4; \ - 2: swi %0, %2, 4; \ - addk %0,r0,r0; \ - 3: \ - .section .fixup,\"ax\"; \ - 4: brid 3b; \ - addik %0, r0, %3; \ - .previous; \ - .section __ex_table,\"a\"; \ - .word 1b,4b,2b,4b; \ - .previous;" \ - : "=&r"(__gu_err) \ - : "r"(&__gu_val), \ - "r"(__gu_ptr), "i"(-EFAULT) \ - ); \ -}) - -#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ -({ \ - __asm__ __volatile__ ( \ - "1:" insn " %1, %2, r0; \ - addk %0, r0, r0; \ - 2: \ - .section .fixup,\"ax\"; \ - 3: brid 2b; \ - addik %0, r0, %3; \ - .previous; \ - .section __ex_table,\"a\"; \ - .word 1b,3b; \ - .previous;" \ - : "=r"(__gu_err) \ - : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ - ); \ +#define put_user(x, ptr) \ +({ \ + access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) \ + ? __put_user((x), (ptr)) : -EFAULT; \ }) /* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ From 0dcb409de73edeb221aed38d9ff8640cf41ff0de Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 15:46:56 +0100 Subject: [PATCH 450/478] microblaze: uaccess: sync put/get/clear_user macros Add macro description and resort. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 106 +++++++++++++++++--------- 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 1e8fa4b7611..6bb9b8fb665 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -191,11 +191,38 @@ extern long strnlen_user(const char *src, long count); #else /* CONFIG_MMU */ -/* - * All the __XXX versions macros/functions below do not perform - * access checking. It is assumed that the necessary checks have been - * already performed before the finction (macro) is called. - */ +/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ +static inline unsigned long __must_check __clear_user(void __user *to, + unsigned long n) +{ + /* normal memset with two words to __ex_table */ + __asm__ __volatile__ ( \ + "1: sb r0, %2, r0;" \ + " addik %0, %0, -1;" \ + " bneid %0, 1b;" \ + " addik %2, %2, 1;" \ + "2: " \ + __EX_TABLE_SECTION \ + ".word 1b,2b;" \ + ".previous;" \ + : "=r"(n) \ + : "0"(n), "r"(to) + ); + return n; +} + +static inline unsigned long __must_check clear_user(void __user *to, + unsigned long n) +{ + might_sleep(); + if (unlikely(!access_ok(VERIFY_WRITE, to, n))) + return n; + return __clear_user(to, n); +} + +/* put_user and get_user macros */ + +extern long __user_bad(void); #define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ ({ \ @@ -231,18 +258,53 @@ extern long strnlen_user(const char *src, long count); __get_user_asm("lw", (ptr), __gu_val, __gu_err); \ break; \ default: \ - __gu_val = 0; __gu_err = -EINVAL; \ + /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\ } \ x = (__typeof__(*(ptr))) __gu_val; \ __gu_err; \ }) +/** + * get_user: - Get a simple variable from user space. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ + #define get_user(x, ptr) \ ({ \ access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) \ ? __get_user((x), (ptr)) : -EFAULT; \ }) +/** + * put_user: - Write a simple value into user space. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Returns zero on success, or -EFAULT on error. + */ + #define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ ({ \ __asm__ __volatile__ ( \ @@ -299,7 +361,7 @@ extern long strnlen_user(const char *src, long count); __put_user_asm_8((ptr), __gu_val, __gu_err); \ break; \ default: \ - __gu_err = -EINVAL; \ + /*__gu_err = -EINVAL;*/ __gu_err = __user_bad(); \ } \ __gu_err; \ }) @@ -310,36 +372,6 @@ extern long strnlen_user(const char *src, long count); ? __put_user((x), (ptr)) : -EFAULT; \ }) -/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ -static inline unsigned long __must_check __clear_user(void __user *to, - unsigned long n) -{ - /* normal memset with two words to __ex_table */ - __asm__ __volatile__ ( \ - "1: sb r0, %2, r0;" \ - " addik %0, %0, -1;" \ - " bneid %0, 1b;" \ - " addik %2, %2, 1;" \ - "2: " \ - __EX_TABLE_SECTION \ - ".word 1b,2b;" \ - ".previous;" \ - : "=r"(n) \ - : "0"(n), "r"(to) - ); - return n; -} - -static inline unsigned long __must_check clear_user(void __user *to, - unsigned long n) -{ - might_sleep(); - if (unlikely(!access_ok(VERIFY_WRITE, to, n))) - return n; - - return __clear_user(to, n); -} - #define __copy_from_user(to, from, n) copy_from_user((to), (from), (n)) #define __copy_from_user_inatomic(to, from, n) \ copy_from_user((to), (from), (n)) From cc5a428b7ae9c2d6233b5bf6b3e6fbb24ddd1ed5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 15:52:53 +0100 Subject: [PATCH 451/478] microblaze: uaccess: copy_to_user unification noMMU and MMU kernel will use copy copy_tofrom_user asm implementation. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 6bb9b8fb665..125e4cf4105 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -372,19 +372,28 @@ extern long __user_bad(void); ? __put_user((x), (ptr)) : -EFAULT; \ }) +extern unsigned long __copy_tofrom_user(void __user *to, + const void __user *from, unsigned long size); + #define __copy_from_user(to, from, n) copy_from_user((to), (from), (n)) #define __copy_from_user_inatomic(to, from, n) \ copy_from_user((to), (from), (n)) -#define copy_to_user(to, from, n) \ - (access_ok(VERIFY_WRITE, (to), (n)) ? \ - __copy_tofrom_user((void __user *)(to), \ - (__force const void __user *)(from), (n)) \ - : -EFAULT) - -#define __copy_to_user(to, from, n) copy_to_user((to), (from), (n)) +#define __copy_to_user(to, from, n) \ + __copy_tofrom_user((void __user *)(to), \ + (__force const void __user *)(from), (n)) #define __copy_to_user_inatomic(to, from, n) copy_to_user((to), (from), (n)) +static inline long copy_to_user(void __user *to, + const void *from, unsigned long n) +{ + might_sleep(); + if (access_ok(VERIFY_WRITE, to, n)) + return __copy_to_user(to, from, n); + else + return n; +} + #define copy_from_user(to, from, n) \ (access_ok(VERIFY_READ, (from), (n)) ? \ __copy_tofrom_user((__force void __user *)(to), \ @@ -402,8 +411,6 @@ extern int __strnlen_user(const char __user *sstr, int len); #endif /* CONFIG_MMU */ -extern unsigned long __copy_tofrom_user(void __user *to, - const void __user *from, unsigned long size); #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ From 4270690bd4b1420a8d634ea31953a1c4def2a44a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 15:56:32 +0100 Subject: [PATCH 452/478] microblaze: uaccess: fix copy_from_user macro copy_from_user macro also use copy_tofrom_user function Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 125e4cf4105..b56d8ae9b17 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -375,12 +375,24 @@ extern long __user_bad(void); extern unsigned long __copy_tofrom_user(void __user *to, const void __user *from, unsigned long size); -#define __copy_from_user(to, from, n) copy_from_user((to), (from), (n)) +#define __copy_from_user(to, from, n) \ + __copy_tofrom_user((__force void __user *)(to), \ + (void __user *)(from), (n)) #define __copy_from_user_inatomic(to, from, n) \ copy_from_user((to), (from), (n)) +static inline long copy_from_user(void *to, + const void __user *from, unsigned long n) +{ + might_sleep(); + if (access_ok(VERIFY_READ, from, n)) + return __copy_from_user(to, from, n); + else + return n; +} + #define __copy_to_user(to, from, n) \ - __copy_tofrom_user((void __user *)(to), \ + __copy_tofrom_user((void __user *)(to), \ (__force const void __user *)(from), (n)) #define __copy_to_user_inatomic(to, from, n) copy_to_user((to), (from), (n)) @@ -394,12 +406,6 @@ static inline long copy_to_user(void __user *to, return n; } -#define copy_from_user(to, from, n) \ - (access_ok(VERIFY_READ, (from), (n)) ? \ - __copy_tofrom_user((__force void __user *)(to), \ - (void __user *)(from), (n)) \ - : -EFAULT) - extern int __strncpy_user(char *to, const char __user *from, int len); extern int __strnlen_user(const char __user *sstr, int len); @@ -411,7 +417,6 @@ extern int __strnlen_user(const char __user *sstr, int len); #endif /* CONFIG_MMU */ - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ From 40e11e3380d4bd14bb3d85c7e7b863075a6a8d86 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 8 Mar 2010 09:38:02 +0100 Subject: [PATCH 453/478] microblaze: uaccess: Fix strncpy_from_user function Generic implementation for noMMU and MMU version Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index b56d8ae9b17..fe954b394fd 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -407,11 +407,19 @@ static inline long copy_to_user(void __user *to, } extern int __strncpy_user(char *to, const char __user *from, int len); + +#define __strncpy_from_user __strncpy_user + +static inline long +strncpy_from_user(char *dst, const char __user *src, long count) +{ + if (!access_ok(VERIFY_READ, src, 1)) + return -EFAULT; + return __strncpy_from_user(dst, src, count); +} + extern int __strnlen_user(const char __user *sstr, int len); -#define strncpy_from_user(to, from, len) \ - (access_ok(VERIFY_READ, from, 1) ? \ - __strncpy_user(to, from, len) : -EFAULT) #define strnlen_user(str, len) \ (access_ok(VERIFY_READ, str, 1) ? __strnlen_user(str, len) : 0) From 527bdb52d50ddbc8dd64369e464d7a08bc7eb83c Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 16:02:59 +0100 Subject: [PATCH 454/478] microblaze: uaccess: fix clear_user for noMMU kernel Previous patches fixed only MMU version and this is the first patch for noMMU kernel Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 81 ++++++++++++--------------- 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index fe954b394fd..1af92025fff 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -71,6 +71,9 @@ struct exception_table_entry { unsigned long insn, fixup; }; +/* Returns 0 if exception not found and fixup otherwise. */ +extern unsigned long search_exception_table(unsigned long); + #ifndef CONFIG_MMU /* Check against bounds of physical memory */ @@ -108,6 +111,39 @@ static inline int ___range_ok(unsigned long addr, unsigned long size) # define __EX_TABLE_SECTION ".section .discard,\"a\"\n" #endif +extern unsigned long __copy_tofrom_user(void __user *to, + const void __user *from, unsigned long size); + +/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ +static inline unsigned long __must_check __clear_user(void __user *to, + unsigned long n) +{ + /* normal memset with two words to __ex_table */ + __asm__ __volatile__ ( \ + "1: sb r0, %2, r0;" \ + " addik %0, %0, -1;" \ + " bneid %0, 1b;" \ + " addik %2, %2, 1;" \ + "2: " \ + __EX_TABLE_SECTION \ + ".word 1b,2b;" \ + ".previous;" \ + : "=r"(n) \ + : "0"(n), "r"(to) + ); + return n; +} + +static inline unsigned long __must_check clear_user(void __user *to, + unsigned long n) +{ + might_sleep(); + if (unlikely(!access_ok(VERIFY_WRITE, to, n))) + return n; + + return __clear_user(to, n); +} + #ifndef CONFIG_MMU /* Undefined function to trigger linker error */ @@ -173,53 +209,11 @@ extern int bad_user_access_length(void); #define __copy_from_user_inatomic(to, from, n) \ (__copy_from_user((to), (from), (n))) -#define __clear_user(addr, n) (memset((void *)(addr), 0, (n)), 0) - -/* stejne s MMU */ -static inline unsigned long clear_user(void *addr, unsigned long size) -{ - if (access_ok(VERIFY_WRITE, addr, size)) - size = __clear_user(addr, size); - return size; -} - -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); - extern long strncpy_from_user(char *dst, const char *src, long count); extern long strnlen_user(const char *src, long count); #else /* CONFIG_MMU */ -/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ -static inline unsigned long __must_check __clear_user(void __user *to, - unsigned long n) -{ - /* normal memset with two words to __ex_table */ - __asm__ __volatile__ ( \ - "1: sb r0, %2, r0;" \ - " addik %0, %0, -1;" \ - " bneid %0, 1b;" \ - " addik %2, %2, 1;" \ - "2: " \ - __EX_TABLE_SECTION \ - ".word 1b,2b;" \ - ".previous;" \ - : "=r"(n) \ - : "0"(n), "r"(to) - ); - return n; -} - -static inline unsigned long __must_check clear_user(void __user *to, - unsigned long n) -{ - might_sleep(); - if (unlikely(!access_ok(VERIFY_WRITE, to, n))) - return n; - return __clear_user(to, n); -} - /* put_user and get_user macros */ extern long __user_bad(void); @@ -372,9 +366,6 @@ extern long __user_bad(void); ? __put_user((x), (ptr)) : -EFAULT; \ }) -extern unsigned long __copy_tofrom_user(void __user *to, - const void __user *from, unsigned long size); - #define __copy_from_user(to, from, n) \ __copy_tofrom_user((__force void __user *)(to), \ (void __user *)(from), (n)) From 3a6d77245efe062993284fd1c2f7510d9a90efe1 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 8 Mar 2010 10:52:24 +0100 Subject: [PATCH 455/478] microblaze: uaccess: Fix get_user macro for noMMU Use unified version. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 89 ++++++++++++++++++++------- 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 1af92025fff..b079ac31a67 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -146,31 +146,75 @@ static inline unsigned long __must_check clear_user(void __user *to, #ifndef CONFIG_MMU -/* Undefined function to trigger linker error */ -extern int bad_user_access_length(void); +extern long __user_bad(void); -/* FIXME this is function for optimalization -> memcpy */ -#define __get_user(var, ptr) \ -({ \ - int __gu_err = 0; \ - switch (sizeof(*(ptr))) { \ - case 1: \ - case 2: \ - case 4: \ - (var) = *(ptr); \ - break; \ - case 8: \ - memcpy((void *) &(var), (ptr), 8); \ - break; \ - default: \ - (var) = 0; \ - __gu_err = __get_user_bad(); \ - break; \ - } \ - __gu_err; \ +#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ ( \ + "1:" insn " %1, %2, r0;" \ + " addk %0, r0, r0;" \ + "2: " \ + __FIXUP_SECTION \ + "3: brid 2b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,3b;" \ + ".previous;" \ + : "=&r"(__gu_err), "=r"(__gu_val) \ + : "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ }) -#define __get_user_bad() (bad_user_access_length(), (-EFAULT)) +/** + * get_user: - Get a simple variable from user space. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ + +#define __get_user(x, ptr) \ +({ \ + unsigned long __gu_val; \ + /*unsigned long __gu_ptr = (unsigned long)(ptr);*/ \ + long __gu_err; \ + switch (sizeof(*(ptr))) { \ + case 1: \ + __get_user_asm("lbu", (ptr), __gu_val, __gu_err); \ + break; \ + case 2: \ + __get_user_asm("lhu", (ptr), __gu_val, __gu_err); \ + break; \ + case 4: \ + __get_user_asm("lw", (ptr), __gu_val, __gu_err); \ + break; \ + default: \ + /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\ + } \ + x = (__typeof__(*(ptr))) __gu_val; \ + __gu_err; \ +}) + + +#define get_user(x, ptr) \ +({ \ + access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) \ + ? __get_user((x), (ptr)) : -EFAULT; \ +}) + +/* Undefined function to trigger linker error */ +extern int bad_user_access_length(void); /* FIXME is not there defined __pu_val */ #define __put_user(var, ptr) \ @@ -197,7 +241,6 @@ extern int bad_user_access_length(void); #define __put_user_bad() (bad_user_access_length(), (-EFAULT)) #define put_user(x, ptr) __put_user((x), (ptr)) -#define get_user(x, ptr) __get_user((x), (ptr)) #define copy_to_user(to, from, n) (memcpy((to), (from), (n)), 0) #define copy_from_user(to, from, n) (memcpy((to), (from), (n)), 0) From ef4e277b5d86e56db650137de0b1cd16ded32498 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 16:22:41 +0100 Subject: [PATCH 456/478] microblaze: uaccess: Fix put_user for noMMU Here is small regression on dhrystone tests and I think that on all benchmarking tests. It is due to better checking mechanism in put_user macro Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 80 +++++++++++++++++++-------- 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index b079ac31a67..4f17950d0a0 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -213,32 +213,66 @@ extern long __user_bad(void); ? __get_user((x), (ptr)) : -EFAULT; \ }) -/* Undefined function to trigger linker error */ -extern int bad_user_access_length(void); - -/* FIXME is not there defined __pu_val */ -#define __put_user(var, ptr) \ +#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ ({ \ - int __pu_err = 0; \ - switch (sizeof(*(ptr))) { \ - case 1: \ - case 2: \ - case 4: \ - *(ptr) = (var); \ - break; \ - case 8: { \ - typeof(*(ptr)) __pu_val = (var); \ - memcpy(ptr, &__pu_val, sizeof(__pu_val)); \ - } \ - break; \ - default: \ - __pu_err = __put_user_bad(); \ - break; \ - } \ - __pu_err; \ + __asm__ __volatile__ ( \ + "1:" insn " %1, %2, r0;" \ + " addk %0, r0, r0;" \ + "2: " \ + __FIXUP_SECTION \ + "3: brid 2b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,3b;" \ + ".previous;" \ + : "=&r"(__gu_err) \ + : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ }) -#define __put_user_bad() (bad_user_access_length(), (-EFAULT)) +#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ (" lwi %0, %1, 0;" \ + "1: swi %0, %2, 0;" \ + " lwi %0, %1, 4;" \ + "2: swi %0, %2, 4;" \ + " addk %0, r0, r0;" \ + "3: " \ + __FIXUP_SECTION \ + "4: brid 3b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,4b,2b,4b;" \ + ".previous;" \ + : "=&r"(__gu_err) \ + : "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ +}) + +#define __put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) volatile __gu_val = (x); \ + long __gu_err = 0; \ + switch (sizeof(__gu_val)) { \ + case 1: \ + __put_user_asm("sb", (ptr), __gu_val, __gu_err); \ + break; \ + case 2: \ + __put_user_asm("sh", (ptr), __gu_val, __gu_err); \ + break; \ + case 4: \ + __put_user_asm("sw", (ptr), __gu_val, __gu_err); \ + break; \ + case 8: \ + __put_user_asm_8((ptr), __gu_val, __gu_err); \ + break; \ + default: \ + /*__gu_err = -EINVAL;*/ __gu_err = __user_bad(); \ + } \ + __gu_err; \ +}) #define put_user(x, ptr) __put_user((x), (ptr)) From cca79120c253451220e589a104bdeb57e4901871 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 18:23:45 +0100 Subject: [PATCH 457/478] microblaze: uaccess: Move functions to generic location noMMU and MMU use them. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 214 ++++++++------------------ arch/microblaze/lib/Makefile | 1 - arch/microblaze/lib/uaccess.c | 48 ------ 3 files changed, 62 insertions(+), 201 deletions(-) delete mode 100644 arch/microblaze/lib/uaccess.c diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 4f17950d0a0..34b79feb1ff 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -111,9 +111,6 @@ static inline int ___range_ok(unsigned long addr, unsigned long size) # define __EX_TABLE_SECTION ".section .discard,\"a\"\n" #endif -extern unsigned long __copy_tofrom_user(void __user *to, - const void __user *from, unsigned long size); - /* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ static inline unsigned long __must_check __clear_user(void __user *to, unsigned long n) @@ -144,8 +141,7 @@ static inline unsigned long __must_check clear_user(void __user *to, return __clear_user(to, n); } -#ifndef CONFIG_MMU - +/* put_user and get_user macros */ extern long __user_bad(void); #define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ @@ -251,114 +247,6 @@ extern long __user_bad(void); ); \ }) -#define __put_user(x, ptr) \ -({ \ - __typeof__(*(ptr)) volatile __gu_val = (x); \ - long __gu_err = 0; \ - switch (sizeof(__gu_val)) { \ - case 1: \ - __put_user_asm("sb", (ptr), __gu_val, __gu_err); \ - break; \ - case 2: \ - __put_user_asm("sh", (ptr), __gu_val, __gu_err); \ - break; \ - case 4: \ - __put_user_asm("sw", (ptr), __gu_val, __gu_err); \ - break; \ - case 8: \ - __put_user_asm_8((ptr), __gu_val, __gu_err); \ - break; \ - default: \ - /*__gu_err = -EINVAL;*/ __gu_err = __user_bad(); \ - } \ - __gu_err; \ -}) - -#define put_user(x, ptr) __put_user((x), (ptr)) - -#define copy_to_user(to, from, n) (memcpy((to), (from), (n)), 0) -#define copy_from_user(to, from, n) (memcpy((to), (from), (n)), 0) - -#define __copy_to_user(to, from, n) (copy_to_user((to), (from), (n))) -#define __copy_from_user(to, from, n) (copy_from_user((to), (from), (n))) -#define __copy_to_user_inatomic(to, from, n) \ - (__copy_to_user((to), (from), (n))) -#define __copy_from_user_inatomic(to, from, n) \ - (__copy_from_user((to), (from), (n))) - -extern long strncpy_from_user(char *dst, const char *src, long count); -extern long strnlen_user(const char *src, long count); - -#else /* CONFIG_MMU */ - -/* put_user and get_user macros */ - -extern long __user_bad(void); - -#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ -({ \ - __asm__ __volatile__ ( \ - "1:" insn " %1, %2, r0;" \ - " addk %0, r0, r0;" \ - "2: " \ - __FIXUP_SECTION \ - "3: brid 2b; " \ - " addik %0, r0, %3;" \ - ".previous;" \ - __EX_TABLE_SECTION \ - ".word 1b,3b;" \ - ".previous;" \ - : "=&r"(__gu_err), "=r"(__gu_val) \ - : "r"(__gu_ptr), "i"(-EFAULT) \ - ); \ -}) - -#define __get_user(x, ptr) \ -({ \ - unsigned long __gu_val; \ - /*unsigned long __gu_ptr = (unsigned long)(ptr);*/ \ - long __gu_err; \ - switch (sizeof(*(ptr))) { \ - case 1: \ - __get_user_asm("lbu", (ptr), __gu_val, __gu_err); \ - break; \ - case 2: \ - __get_user_asm("lhu", (ptr), __gu_val, __gu_err); \ - break; \ - case 4: \ - __get_user_asm("lw", (ptr), __gu_val, __gu_err); \ - break; \ - default: \ - /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\ - } \ - x = (__typeof__(*(ptr))) __gu_val; \ - __gu_err; \ -}) - -/** - * get_user: - Get a simple variable from user space. - * @x: Variable to store result. - * @ptr: Source address, in user space. - * - * Context: User context only. This function may sleep. - * - * This macro copies a single simple variable from user space to kernel - * space. It supports simple types like char and int, but not larger - * data types like structures or arrays. - * - * @ptr must have pointer-to-simple-variable type, and the result of - * dereferencing @ptr must be assignable to @x without a cast. - * - * Returns zero on success, or -EFAULT on error. - * On error, the variable @x is set to zero. - */ - -#define get_user(x, ptr) \ -({ \ - access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) \ - ? __get_user((x), (ptr)) : -EFAULT; \ -}) - /** * put_user: - Write a simple value into user space. * @x: Value to copy to user space. @@ -376,44 +264,6 @@ extern long __user_bad(void); * Returns zero on success, or -EFAULT on error. */ -#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ -({ \ - __asm__ __volatile__ ( \ - "1:" insn " %1, %2, r0;" \ - " addk %0, r0, r0;" \ - "2: " \ - __FIXUP_SECTION \ - "3: brid 2b;" \ - " addik %0, r0, %3;" \ - ".previous;" \ - __EX_TABLE_SECTION \ - ".word 1b,3b;" \ - ".previous;" \ - : "=&r"(__gu_err) \ - : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ - ); \ -}) - -#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \ -({ \ - __asm__ __volatile__ (" lwi %0, %1, 0;" \ - "1: swi %0, %2, 0;" \ - " lwi %0, %1, 4;" \ - "2: swi %0, %2, 4;" \ - " addk %0, r0, r0;" \ - "3: " \ - __FIXUP_SECTION \ - "4: brid 3b;" \ - " addik %0, r0, %3;" \ - ".previous;" \ - __EX_TABLE_SECTION \ - ".word 1b,4b,2b,4b;" \ - ".previous;" \ - : "=&r"(__gu_err) \ - : "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ - ); \ -}) - #define __put_user(x, ptr) \ ({ \ __typeof__(*(ptr)) volatile __gu_val = (x); \ @@ -422,7 +272,7 @@ extern long __user_bad(void); case 1: \ __put_user_asm("sb", (ptr), __gu_val, __gu_err); \ break; \ - case 2: \ + case 2: \ __put_user_asm("sh", (ptr), __gu_val, __gu_err); \ break; \ case 4: \ @@ -437,12 +287,72 @@ extern long __user_bad(void); __gu_err; \ }) +#ifndef CONFIG_MMU + +#define put_user(x, ptr) __put_user((x), (ptr)) + +static inline long strnlen_user(const char __user *src, long count) +{ + return strlen(src) + 1; +} + +#define __do_strncpy_from_user(dst, src, count, res) \ + do { \ + char *tmp; \ + strncpy(dst, src, count); \ + for (tmp = dst; *tmp && count > 0; tmp++, count--) \ + ; \ + res = (tmp - dst); \ + } while (0) + +static inline long __strncpy_from_user(char *dst, + const char __user *src, long count) +{ + long res; + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +static inline long strncpy_from_user(char *dst, + const char __user *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 1)) + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +static inline unsigned long __copy_tofrom_user(void __user *to, + const void __user *from, unsigned long size) +{ + memcpy(to, from, size); + return 0; +} + +#define copy_to_user(to, from, n) (memcpy((to), (from), (n)), 0) +#define copy_from_user(to, from, n) (memcpy((to), (from), (n)), 0) + +#define __copy_to_user(to, from, n) (copy_to_user((to), (from), (n))) +#define __copy_from_user(to, from, n) (copy_from_user((to), (from), (n))) +#define __copy_to_user_inatomic(to, from, n) \ + (__copy_to_user((to), (from), (n))) +#define __copy_from_user_inatomic(to, from, n) \ + (__copy_from_user((to), (from), (n))) + +extern long strncpy_from_user(char *dst, const char *src, long count); +extern long strnlen_user(const char *src, long count); + +#else /* CONFIG_MMU */ + #define put_user(x, ptr) \ ({ \ access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) \ ? __put_user((x), (ptr)) : -EFAULT; \ }) +extern unsigned long __copy_tofrom_user(void __user *to, + const void __user *from, unsigned long size); + #define __copy_from_user(to, from, n) \ __copy_tofrom_user((__force void __user *)(to), \ (void __user *)(from), (n)) diff --git a/arch/microblaze/lib/Makefile b/arch/microblaze/lib/Makefile index b579db068c0..59322a2717a 100644 --- a/arch/microblaze/lib/Makefile +++ b/arch/microblaze/lib/Makefile @@ -10,5 +10,4 @@ else lib-y += memcpy.o memmove.o endif -lib-$(CONFIG_NO_MMU) += uaccess.o lib-$(CONFIG_MMU) += uaccess_old.o diff --git a/arch/microblaze/lib/uaccess.c b/arch/microblaze/lib/uaccess.c deleted file mode 100644 index a853fe089c4..00000000000 --- a/arch/microblaze/lib/uaccess.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2006 Atmark Techno, Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include -#include - -#include - -long strnlen_user(const char __user *src, long count) -{ - return strlen(src) + 1; -} - -#define __do_strncpy_from_user(dst, src, count, res) \ - do { \ - char *tmp; \ - strncpy(dst, src, count); \ - for (tmp = dst; *tmp && count > 0; tmp++, count--) \ - ; \ - res = (tmp - dst); \ - } while (0) - -long __strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res; - __do_strncpy_from_user(dst, src, count, res); - return res; -} - -long strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res = -EFAULT; - if (access_ok(VERIFY_READ, src, 1)) - __do_strncpy_from_user(dst, src, count, res); - return res; -} - -unsigned long __copy_tofrom_user(void __user *to, - const void __user *from, unsigned long size) -{ - memcpy(to, from, size); - return 0; -} From 94804a9b3d0e62096a52fb62afcea32b899380c5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 18:39:20 +0100 Subject: [PATCH 458/478] microblaze: uaccess: Unify __copy_tofrom_user Move to generic location. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 59 ++++++++++----------------- arch/microblaze/lib/Makefile | 2 +- 2 files changed, 22 insertions(+), 39 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 34b79feb1ff..b33ab659781 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -111,6 +111,9 @@ static inline int ___range_ok(unsigned long addr, unsigned long size) # define __EX_TABLE_SECTION ".section .discard,\"a\"\n" #endif +extern unsigned long __copy_tofrom_user(void __user *to, + const void __user *from, unsigned long size); + /* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ static inline unsigned long __must_check __clear_user(void __user *to, unsigned long n) @@ -322,23 +325,6 @@ static inline long strncpy_from_user(char *dst, return res; } -static inline unsigned long __copy_tofrom_user(void __user *to, - const void __user *from, unsigned long size) -{ - memcpy(to, from, size); - return 0; -} - -#define copy_to_user(to, from, n) (memcpy((to), (from), (n)), 0) -#define copy_from_user(to, from, n) (memcpy((to), (from), (n)), 0) - -#define __copy_to_user(to, from, n) (copy_to_user((to), (from), (n))) -#define __copy_from_user(to, from, n) (copy_from_user((to), (from), (n))) -#define __copy_to_user_inatomic(to, from, n) \ - (__copy_to_user((to), (from), (n))) -#define __copy_from_user_inatomic(to, from, n) \ - (__copy_from_user((to), (from), (n))) - extern long strncpy_from_user(char *dst, const char *src, long count); extern long strnlen_user(const char *src, long count); @@ -350,8 +336,24 @@ extern long strnlen_user(const char *src, long count); ? __put_user((x), (ptr)) : -EFAULT; \ }) -extern unsigned long __copy_tofrom_user(void __user *to, - const void __user *from, unsigned long size); +extern int __strncpy_user(char *to, const char __user *from, int len); + +#define __strncpy_from_user __strncpy_user + +static inline long +strncpy_from_user(char *dst, const char __user *src, long count) +{ + if (!access_ok(VERIFY_READ, src, 1)) + return -EFAULT; + return __strncpy_from_user(dst, src, count); +} + +extern int __strnlen_user(const char __user *sstr, int len); + +#define strnlen_user(str, len) \ + (access_ok(VERIFY_READ, str, 1) ? __strnlen_user(str, len) : 0) + +#endif /* CONFIG_MMU */ #define __copy_from_user(to, from, n) \ __copy_tofrom_user((__force void __user *)(to), \ @@ -384,25 +386,6 @@ static inline long copy_to_user(void __user *to, return n; } -extern int __strncpy_user(char *to, const char __user *from, int len); - -#define __strncpy_from_user __strncpy_user - -static inline long -strncpy_from_user(char *dst, const char __user *src, long count) -{ - if (!access_ok(VERIFY_READ, src, 1)) - return -EFAULT; - return __strncpy_from_user(dst, src, count); -} - -extern int __strnlen_user(const char __user *sstr, int len); - -#define strnlen_user(str, len) \ - (access_ok(VERIFY_READ, str, 1) ? __strnlen_user(str, len) : 0) - -#endif /* CONFIG_MMU */ - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/microblaze/lib/Makefile b/arch/microblaze/lib/Makefile index 59322a2717a..4dfe47d3cd9 100644 --- a/arch/microblaze/lib/Makefile +++ b/arch/microblaze/lib/Makefile @@ -10,4 +10,4 @@ else lib-y += memcpy.o memmove.o endif -lib-$(CONFIG_MMU) += uaccess_old.o +lib-y += uaccess_old.o From 89ae9753aef160c2f7bcecec21a7c4a6bc4c9b9b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 18:49:45 +0100 Subject: [PATCH 459/478] microblaze: uaccess: Sync strlen, strnlen, copy_to/from_user Last sync. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 88 ++++++++++----------------- 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index b33ab659781..446bec29b14 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -294,40 +294,6 @@ extern long __user_bad(void); #define put_user(x, ptr) __put_user((x), (ptr)) -static inline long strnlen_user(const char __user *src, long count) -{ - return strlen(src) + 1; -} - -#define __do_strncpy_from_user(dst, src, count, res) \ - do { \ - char *tmp; \ - strncpy(dst, src, count); \ - for (tmp = dst; *tmp && count > 0; tmp++, count--) \ - ; \ - res = (tmp - dst); \ - } while (0) - -static inline long __strncpy_from_user(char *dst, - const char __user *src, long count) -{ - long res; - __do_strncpy_from_user(dst, src, count, res); - return res; -} - -static inline long strncpy_from_user(char *dst, - const char __user *src, long count) -{ - long res = -EFAULT; - if (access_ok(VERIFY_READ, src, 1)) - __do_strncpy_from_user(dst, src, count, res); - return res; -} - -extern long strncpy_from_user(char *dst, const char *src, long count); -extern long strnlen_user(const char *src, long count); - #else /* CONFIG_MMU */ #define put_user(x, ptr) \ @@ -335,26 +301,9 @@ extern long strnlen_user(const char *src, long count); access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) \ ? __put_user((x), (ptr)) : -EFAULT; \ }) - -extern int __strncpy_user(char *to, const char __user *from, int len); - -#define __strncpy_from_user __strncpy_user - -static inline long -strncpy_from_user(char *dst, const char __user *src, long count) -{ - if (!access_ok(VERIFY_READ, src, 1)) - return -EFAULT; - return __strncpy_from_user(dst, src, count); -} - -extern int __strnlen_user(const char __user *sstr, int len); - -#define strnlen_user(str, len) \ - (access_ok(VERIFY_READ, str, 1) ? __strnlen_user(str, len) : 0) - #endif /* CONFIG_MMU */ +/* copy_to_from_user */ #define __copy_from_user(to, from, n) \ __copy_tofrom_user((__force void __user *)(to), \ (void __user *)(from), (n)) @@ -367,8 +316,7 @@ static inline long copy_from_user(void *to, might_sleep(); if (access_ok(VERIFY_READ, from, n)) return __copy_from_user(to, from, n); - else - return n; + return n; } #define __copy_to_user(to, from, n) \ @@ -382,8 +330,36 @@ static inline long copy_to_user(void __user *to, might_sleep(); if (access_ok(VERIFY_WRITE, to, n)) return __copy_to_user(to, from, n); - else - return n; + return n; +} + +/* + * Copy a null terminated string from userspace. + */ +extern int __strncpy_user(char *to, const char __user *from, int len); + +#define __strncpy_from_user __strncpy_user + +static inline long +strncpy_from_user(char *dst, const char __user *src, long count) +{ + if (!access_ok(VERIFY_READ, src, 1)) + return -EFAULT; + return __strncpy_from_user(dst, src, count); +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ +extern int __strnlen_user(const char __user *sstr, int len); + +static inline long strnlen_user(const char __user *src, long n) +{ + if (!access_ok(VERIFY_READ, src, 1)) + return 0; + return __strnlen_user(src, n); } #endif /* __ASSEMBLY__ */ From ee68f1745e7734a55c8bf680f6f464205f1f15da Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 15 Mar 2010 08:48:27 +0100 Subject: [PATCH 460/478] microblaze: Support systems without lmb bram When the system has no lmb bram, main memory should be start from zero because of microblaze vectors. DTS fragment could look like: DDR2_SDRAM: memory@0 { device_type = "memory"; reg = < 0x0 0x10000000 >; } ; Then you have to setup CONFIG_KERNEL_BASE_ADDR=0 which caused that kernel physical start address will be zero. On reset vector place will be jump to 0x100 and on 0x100 starts kernel text. You have to solve how to load the kernel before cpu starts. Tested with XMD. Signed-off-by: Michal Simek --- arch/microblaze/kernel/head.S | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index cb7815cfe5a..e397d5d5257 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S @@ -51,6 +51,12 @@ swapper_pg_dir: .text ENTRY(_start) +#if CONFIG_KERNEL_BASE_ADDR == 0 + brai TOPHYS(real_start) + .org 0x100 +real_start: +#endif + mfs r1, rmsr andi r1, r1, ~2 mts rmsr, r1 From 708e7153d6fc4d2e5fe15c6ccc5d2907fe8a9c8d Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 18 Mar 2010 07:23:04 +0100 Subject: [PATCH 461/478] microblaze: Add DEBUG option Disable debug option in asm code. Signed-off-by: Michal Simek --- arch/microblaze/kernel/hw_exception_handler.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index 2b86c03aa84..6651bb437db 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -334,6 +334,7 @@ not_in_delay_slot: addk r6, r5, r5; /* << 1 */ addk r6, r6, r6; /* << 2 */ +#ifdef DEBUG /* counting which exception happen */ lwi r5, r0, 0x200 + TOPHYS(r0_ram) addi r5, r5, 1 @@ -341,6 +342,7 @@ not_in_delay_slot: lwi r5, r6, 0x200 + TOPHYS(r0_ram) addi r5, r5, 1 swi r5, r6, 0x200 + TOPHYS(r0_ram) +#endif /* end */ /* Load the HW Exception vector */ lwi r6, r6, TOPHYS(_MB_HW_ExceptionVectorTable) From 7a6bbdc9304b45cc759e03623cbe63d81aff7337 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 20:37:23 +0100 Subject: [PATCH 462/478] microblaze: Prepare work for optimization in exception code Any sync branch must follow mts instructions not mfs. Signed-off-by: Michal Simek --- arch/microblaze/kernel/hw_exception_handler.S | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index 6651bb437db..ad6dbf029e6 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -562,7 +562,6 @@ ex_handler_done: */ mfs r11, rpid nop - bri 4 mfs r3, rear /* Get faulting address */ nop /* If we are faulting a kernel address, we have to use the @@ -679,18 +678,17 @@ ex_handler_done: */ handle_data_tlb_miss_exception: /* Working registers already saved: R3, R4, R5, R6 - * R3 = ESR + * R3 = EAR, R4 = ESR */ mfs r11, rpid nop - bri 4 mfs r3, rear /* Get faulting address */ nop /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - ori r4, r0, CONFIG_KERNEL_START - cmpu r4, r3, r4 + ori r6, r0, CONFIG_KERNEL_START + cmpu r4, r3, r6 bgti r4, ex5 ori r4, r0, swapper_pg_dir mts rpid, r0 /* TLB will have 0 TID */ @@ -756,7 +754,6 @@ ex_handler_done: */ mfs r11, rpid nop - bri 4 mfs r3, rear /* Get faulting address */ nop From b175bcfe31cba846d8bfa35a3a4820667f7af383 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 19 Mar 2010 12:44:40 +0100 Subject: [PATCH 463/478] microblaze: Change register usage for ESR and EAR This change synchronize register usage in code. ESR = R4 EAR = R3 Signed-off-by: Michal Simek --- arch/microblaze/kernel/hw_exception_handler.S | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index ad6dbf029e6..a652addb932 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -313,13 +313,13 @@ _hw_exception_handler: mfs r5, rmsr; nop swi r5, r1, 0; - mfs r3, resr + mfs r4, resr nop - mfs r4, rear; + mfs r3, rear; nop #ifndef CONFIG_MMU - andi r5, r3, 0x1000; /* Check ESR[DS] */ + andi r5, r4, 0x1000; /* Check ESR[DS] */ beqi r5, not_in_delay_slot; /* Branch if ESR[DS] not set */ mfs r17, rbtr; /* ESR[DS] set - return address in BTR */ nop @@ -327,7 +327,7 @@ not_in_delay_slot: swi r17, r1, PT_R17 #endif - andi r5, r3, 0x1F; /* Extract ESR[EXC] */ + andi r5, r4, 0x1F; /* Extract ESR[EXC] */ #ifdef CONFIG_MMU /* Calculate exception vector offset = r5 << 2 */ @@ -378,7 +378,7 @@ handle_other_ex: /* Handle Other exceptions here */ swi r18, r1, PT_R18 or r5, r1, r0 - andi r6, r3, 0x1F; /* Load ESR[EC] */ + andi r6, r4, 0x1F; /* Load ESR[EC] */ lwi r7, r0, PER_CPU(KM) /* MS: saving current kernel mode to regs */ swi r7, r1, PT_MODE mfs r7, rfsr @@ -428,11 +428,11 @@ handle_other_ex: /* Handle Other exceptions here */ */ handle_unaligned_ex: /* Working registers already saved: R3, R4, R5, R6 - * R3 = ESR - * R4 = EAR + * R4 = ESR + * R3 = EAR */ #ifdef CONFIG_MMU - andi r6, r3, 0x1000 /* Check ESR[DS] */ + andi r6, r4, 0x1000 /* Check ESR[DS] */ beqi r6, _no_delayslot /* Branch if ESR[DS] not set */ mfs r17, rbtr; /* ESR[DS] set - return address in BTR */ nop @@ -441,7 +441,7 @@ _no_delayslot: RESTORE_STATE; bri unaligned_data_trap #endif - andi r6, r3, 0x3E0; /* Mask and extract the register operand */ + andi r6, r4, 0x3E0; /* Mask and extract the register operand */ srl r6, r6; /* r6 >> 5 */ srl r6, r6; srl r6, r6; @@ -450,33 +450,33 @@ _no_delayslot: /* Store the register operand in a temporary location */ sbi r6, r0, TOPHYS(ex_reg_op); - andi r6, r3, 0x400; /* Extract ESR[S] */ + andi r6, r4, 0x400; /* Extract ESR[S] */ bnei r6, ex_sw; ex_lw: - andi r6, r3, 0x800; /* Extract ESR[W] */ + andi r6, r4, 0x800; /* Extract ESR[W] */ beqi r6, ex_lhw; - lbui r5, r4, 0; /* Exception address in r4 */ + lbui r5, r3, 0; /* Exception address in r3 */ /* Load a word, byte-by-byte from destination address and save it in tmp space */ sbi r5, r0, TOPHYS(ex_tmp_data_loc_0); - lbui r5, r4, 1; + lbui r5, r3, 1; sbi r5, r0, TOPHYS(ex_tmp_data_loc_1); - lbui r5, r4, 2; + lbui r5, r3, 2; sbi r5, r0, TOPHYS(ex_tmp_data_loc_2); - lbui r5, r4, 3; + lbui r5, r3, 3; sbi r5, r0, TOPHYS(ex_tmp_data_loc_3); - /* Get the destination register value into r3 */ - lwi r3, r0, TOPHYS(ex_tmp_data_loc_0); + /* Get the destination register value into r4 */ + lwi r4, r0, TOPHYS(ex_tmp_data_loc_0); bri ex_lw_tail; ex_lhw: - lbui r5, r4, 0; /* Exception address in r4 */ + lbui r5, r3, 0; /* Exception address in r3 */ /* Load a half-word, byte-by-byte from destination address and save it in tmp space */ sbi r5, r0, TOPHYS(ex_tmp_data_loc_0); - lbui r5, r4, 1; + lbui r5, r3, 1; sbi r5, r0, TOPHYS(ex_tmp_data_loc_1); - /* Get the destination register value into r3 */ - lhui r3, r0, TOPHYS(ex_tmp_data_loc_0); + /* Get the destination register value into r4 */ + lhui r4, r0, TOPHYS(ex_tmp_data_loc_0); ex_lw_tail: /* Get the destination register number into r5 */ lbui r5, r0, TOPHYS(ex_reg_op); @@ -504,25 +504,25 @@ ex_sw_tail: andi r6, r6, 0x800; /* Extract ESR[W] */ beqi r6, ex_shw; /* Get the word - delay slot */ - swi r3, r0, TOPHYS(ex_tmp_data_loc_0); + swi r4, r0, TOPHYS(ex_tmp_data_loc_0); /* Store the word, byte-by-byte into destination address */ - lbui r3, r0, TOPHYS(ex_tmp_data_loc_0); - sbi r3, r4, 0; - lbui r3, r0, TOPHYS(ex_tmp_data_loc_1); - sbi r3, r4, 1; - lbui r3, r0, TOPHYS(ex_tmp_data_loc_2); - sbi r3, r4, 2; - lbui r3, r0, TOPHYS(ex_tmp_data_loc_3); - sbi r3, r4, 3; + lbui r4, r0, TOPHYS(ex_tmp_data_loc_0); + sbi r4, r3, 0; + lbui r4, r0, TOPHYS(ex_tmp_data_loc_1); + sbi r4, r3, 1; + lbui r4, r0, TOPHYS(ex_tmp_data_loc_2); + sbi r4, r3, 2; + lbui r4, r0, TOPHYS(ex_tmp_data_loc_3); + sbi r4, r3, 3; bri ex_handler_done; ex_shw: /* Store the lower half-word, byte-by-byte into destination address */ - swi r3, r0, TOPHYS(ex_tmp_data_loc_0); - lbui r3, r0, TOPHYS(ex_tmp_data_loc_2); - sbi r3, r4, 0; - lbui r3, r0, TOPHYS(ex_tmp_data_loc_3); - sbi r3, r4, 1; + swi r4, r0, TOPHYS(ex_tmp_data_loc_0); + lbui r4, r0, TOPHYS(ex_tmp_data_loc_2); + sbi r4, r3, 0; + lbui r4, r0, TOPHYS(ex_tmp_data_loc_3); + sbi r4, r3, 1; ex_sw_end: /* Exception handling of store word, ends. */ ex_handler_done: From bd1637d63e82aaf732ffbe907ba887fa12e82df4 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 19 Mar 2010 12:50:35 +0100 Subject: [PATCH 464/478] microblaze: Remove additional resr and rear loading RESR and REAR uses the same regs in whole file. Signed-off-by: Michal Simek --- arch/microblaze/kernel/hw_exception_handler.S | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index a652addb932..5d8c3de58b0 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -562,20 +562,16 @@ ex_handler_done: */ mfs r11, rpid nop - mfs r3, rear /* Get faulting address */ - nop /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - ori r4, r0, CONFIG_KERNEL_START - cmpu r4, r3, r4 - bgti r4, ex3 + ori r5, r0, CONFIG_KERNEL_START + cmpu r5, r3, r5 + bgti r5, ex3 /* First, check if it was a zone fault (which means a user * tried to access a kernel or read-protected page - always * a SEGV). All other faults here must be stores, so no * need to check ESR_S as well. */ - mfs r4, resr - nop andi r4, r4, 0x800 /* ESR_Z - zone protection */ bnei r4, ex2 @@ -590,8 +586,6 @@ ex_handler_done: * tried to access a kernel or read-protected page - always * a SEGV). All other faults here must be stores, so no * need to check ESR_S as well. */ - mfs r4, resr - nop andi r4, r4, 0x800 /* ESR_Z */ bnei r4, ex2 /* get current task address */ @@ -666,8 +660,6 @@ ex_handler_done: * R3 = ESR */ - mfs r3, rear /* Get faulting address */ - nop RESTORE_STATE; bri page_fault_instr_trap @@ -682,8 +674,6 @@ ex_handler_done: */ mfs r11, rpid nop - mfs r3, rear /* Get faulting address */ - nop /* If we are faulting a kernel address, we have to use the * kernel page tables. */ @@ -754,8 +744,6 @@ ex_handler_done: */ mfs r11, rpid nop - mfs r3, rear /* Get faulting address */ - nop /* If we are faulting a kernel address, we have to use the * kernel page tables. From 3765d6958dfff34a15588e23c5d1274e1f6ba200 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 20:43:27 +0100 Subject: [PATCH 465/478] microblaze: Use instruction with delay slot Sync labels. Signed-off-by: Michal Simek --- arch/microblaze/kernel/hw_exception_handler.S | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index 5d8c3de58b0..995a2123635 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -721,9 +721,8 @@ ex_handler_done: * Many of these bits are software only. Bits we don't set * here we (properly should) assume have the appropriate value. */ + brid finish_tlb_load andni r4, r4, 0x0ce2 /* Make sure 20, 21 are zero */ - - bri finish_tlb_load ex7: /* The bailout. Restore registers to pre-exception conditions * and call the heavyweights to help us out. @@ -779,7 +778,7 @@ ex_handler_done: lwi r4, r5, 0 /* Get Linux PTE */ andi r6, r4, _PAGE_PRESENT - beqi r6, ex7 + beqi r6, ex10 ori r4, r4, _PAGE_ACCESSED swi r4, r5, 0 @@ -792,9 +791,8 @@ ex_handler_done: * Many of these bits are software only. Bits we don't set * here we (properly should) assume have the appropriate value. */ + brid finish_tlb_load andni r4, r4, 0x0ce2 /* Make sure 20, 21 are zero */ - - bri finish_tlb_load ex10: /* The bailout. Restore registers to pre-exception conditions * and call the heavyweights to help us out. @@ -824,9 +822,9 @@ ex_handler_done: andi r5, r5, (MICROBLAZE_TLB_SIZE-1) ori r6, r0, 1 cmp r31, r5, r6 - blti r31, sem + blti r31, ex12 addik r5, r6, 1 - sem: + ex12: /* MS: save back current TLB index */ swi r5, r0, TOPHYS(tlb_index) @@ -846,7 +844,6 @@ ex_handler_done: nop /* Done...restore registers and get out of here. */ - ex12: mts rpid, r11 nop bri 4 From e84452dd9ff517bd3028f6444d000727cd39e783 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 14:54:35 +0100 Subject: [PATCH 466/478] microblaze: Fix TLB macros To be able to do trace TLB operations. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/tlbflush.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/microblaze/include/asm/tlbflush.h b/arch/microblaze/include/asm/tlbflush.h index bcb8b41d55a..2e1353c2d18 100644 --- a/arch/microblaze/include/asm/tlbflush.h +++ b/arch/microblaze/include/asm/tlbflush.h @@ -24,6 +24,7 @@ extern void _tlbie(unsigned long address); extern void _tlbia(void); #define __tlbia() { preempt_disable(); _tlbia(); preempt_enable(); } +#define __tlbie(x) { _tlbie(x); } static inline void local_flush_tlb_all(void) { __tlbia(); } @@ -31,7 +32,7 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) { __tlbia(); } static inline void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) - { _tlbie(vmaddr); } + { __tlbie(vmaddr); } static inline void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { __tlbia(); } From 13851966da54be8e37863aa93ee2c8f3d3a3186a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 23 Mar 2010 08:09:32 +0100 Subject: [PATCH 467/478] microblaze: Add .type and .size to ASM functions Cachegrind analysis need this fix to be able to log asm functions. Signed-off-by: Michal Simek --- arch/microblaze/kernel/misc.S | 11 +++++++++++ arch/microblaze/lib/fastcopy.S | 6 +++++- arch/microblaze/lib/uaccess_old.S | 6 ++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S index df16c6287a8..18681eed5ec 100644 --- a/arch/microblaze/kernel/misc.S +++ b/arch/microblaze/kernel/misc.S @@ -26,6 +26,7 @@ * We avoid flushing the pinned 0, 1 and possibly 2 entries. */ .globl _tlbia; +.type _tlbia, @function .align 4; _tlbia: addik r12, r0, 63 /* flush all entries (63 - 3) */ @@ -41,11 +42,13 @@ _tlbia_1: /* sync */ rtsd r15, 8 nop + .size _tlbia, . - _tlbia /* * Flush MMU TLB for a particular address (in r5) */ .globl _tlbie; +.type _tlbie, @function .align 4; _tlbie: mts rtlbsx, r5 /* look up the address in TLB */ @@ -59,10 +62,13 @@ _tlbie_1: rtsd r15, 8 nop + .size _tlbie, . - _tlbie + /* * Allocate TLB entry for early console */ .globl early_console_reg_tlb_alloc; +.type early_console_reg_tlb_alloc, @function .align 4; early_console_reg_tlb_alloc: /* @@ -86,6 +92,8 @@ early_console_reg_tlb_alloc: rtsd r15, 8 nop + .size early_console_reg_tlb_alloc, . - early_console_reg_tlb_alloc + /* * Copy a whole page (4096 bytes). */ @@ -104,6 +112,7 @@ early_console_reg_tlb_alloc: #define DCACHE_LINE_BYTES (4 * 4) .globl copy_page; +.type copy_page, @function .align 4; copy_page: ori r11, r0, (PAGE_SIZE/DCACHE_LINE_BYTES) - 1 @@ -118,3 +127,5 @@ _copy_page_loop: addik r11, r11, -1 rtsd r15, 8 nop + + .size copy_page, . - copy_page diff --git a/arch/microblaze/lib/fastcopy.S b/arch/microblaze/lib/fastcopy.S index 02e3ab4eddf..fdc48bb065d 100644 --- a/arch/microblaze/lib/fastcopy.S +++ b/arch/microblaze/lib/fastcopy.S @@ -30,8 +30,9 @@ */ #include - + .text .globl memcpy + .type memcpy, @function .ent memcpy memcpy: @@ -345,9 +346,11 @@ a_done: rtsd r15, 8 nop +.size memcpy, . - memcpy .end memcpy /*----------------------------------------------------------------------------*/ .globl memmove + .type memmove, @function .ent memmove memmove: @@ -659,4 +662,5 @@ d_done: rtsd r15, 8 nop +.size memmove, . - memmove .end memmove diff --git a/arch/microblaze/lib/uaccess_old.S b/arch/microblaze/lib/uaccess_old.S index 67f991c14b8..b327524a803 100644 --- a/arch/microblaze/lib/uaccess_old.S +++ b/arch/microblaze/lib/uaccess_old.S @@ -22,6 +22,7 @@ .text .globl __strncpy_user; +.type __strncpy_user, @function .align 4; __strncpy_user: @@ -50,6 +51,7 @@ __strncpy_user: 3: rtsd r15,8 nop + .size __strncpy_user, . - __strncpy_user .section .fixup, "ax" @@ -72,6 +74,7 @@ __strncpy_user: .text .globl __strnlen_user; +.type __strnlen_user, @function .align 4; __strnlen_user: addik r3,r6,0 @@ -90,6 +93,7 @@ __strnlen_user: 3: rtsd r15,8 nop + .size __strnlen_user, . - __strnlen_user .section .fixup,"ax" @@ -108,6 +112,7 @@ __strnlen_user: */ .text .globl __copy_tofrom_user; +.type __copy_tofrom_user, @function .align 4; __copy_tofrom_user: /* @@ -129,6 +134,7 @@ __copy_tofrom_user: 3: rtsd r15,8 nop + .size __copy_tofrom_user, . - __copy_tofrom_user .section __ex_table,"a" From 78ebfa884bcef125464399f8d1cb05937bfeb6e1 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 23 Mar 2010 15:37:02 +0100 Subject: [PATCH 468/478] microblaze: Adding likely macros On the base on GCOV analytics is helpful to add likely/unlikely macros. Signed-off-by: Michal Simek --- arch/microblaze/kernel/dma.c | 2 +- arch/microblaze/kernel/process.c | 9 +++++---- arch/microblaze/lib/memcpy.c | 2 +- arch/microblaze/lib/memset.c | 15 ++++++++------- arch/microblaze/mm/fault.c | 24 ++++++++++++------------ arch/microblaze/mm/pgtable.c | 2 +- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c index b1084974fcc..4d5b0311601 100644 --- a/arch/microblaze/kernel/dma.c +++ b/arch/microblaze/kernel/dma.c @@ -37,7 +37,7 @@ static inline void __dma_sync_page(unsigned long paddr, unsigned long offset, static unsigned long get_dma_direct_offset(struct device *dev) { - if (dev) + if (likely(dev)) return (unsigned long)dev->archdata.dma_data; return PCI_DRAM_OFFSET; /* FIXME Not sure if is correct */ diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 35efb2f42d5..09bed44dfcd 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c @@ -75,7 +75,10 @@ __setup("hlt", hlt_setup); void default_idle(void) { - if (!hlt_counter) { + if (likely(hlt_counter)) { + while (!need_resched()) + cpu_relax(); + } else { clear_thread_flag(TIF_POLLING_NRFLAG); smp_mb__after_clear_bit(); local_irq_disable(); @@ -83,9 +86,7 @@ void default_idle(void) cpu_sleep(); local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); - } else - while (!need_resched()) - cpu_relax(); + } } void cpu_idle(void) diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c index cc2108b6b26..014bac92bdf 100644 --- a/arch/microblaze/lib/memcpy.c +++ b/arch/microblaze/lib/memcpy.c @@ -53,7 +53,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) const uint32_t *i_src; uint32_t *i_dst; - if (c >= 4) { + if (likely(c >= 4)) { unsigned value, buf_hold; /* Align the dstination to a word boundry. */ diff --git a/arch/microblaze/lib/memset.c b/arch/microblaze/lib/memset.c index 4df851d41a2..ecfb663e1fc 100644 --- a/arch/microblaze/lib/memset.c +++ b/arch/microblaze/lib/memset.c @@ -33,22 +33,23 @@ #ifdef __HAVE_ARCH_MEMSET void *memset(void *v_src, int c, __kernel_size_t n) { - char *src = v_src; #ifdef CONFIG_OPT_LIB_FUNCTION uint32_t *i_src; - uint32_t w32; + uint32_t w32 = 0; #endif /* Truncate c to 8 bits */ c = (c & 0xFF); #ifdef CONFIG_OPT_LIB_FUNCTION - /* Make a repeating word out of it */ - w32 = c; - w32 |= w32 << 8; - w32 |= w32 << 16; + if (unlikely(c)) { + /* Make a repeating word out of it */ + w32 = c; + w32 |= w32 << 8; + w32 |= w32 << 16; + } - if (n >= 4) { + if (likely(n >= 4)) { /* Align the destination to a word boundary */ /* This is done in an endian independant manner */ switch ((unsigned) src & 3) { diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c index d9d249a66ff..7af87f4b2c2 100644 --- a/arch/microblaze/mm/fault.c +++ b/arch/microblaze/mm/fault.c @@ -106,7 +106,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, regs->esr = error_code; /* On a kernel SLB miss we can only check for a valid exception entry */ - if (kernel_mode(regs) && (address >= TASK_SIZE)) { + if (unlikely(kernel_mode(regs) && (address >= TASK_SIZE))) { printk(KERN_WARNING "kernel task_size exceed"); _exception(SIGSEGV, regs, code, address); } @@ -122,7 +122,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, } #endif /* CONFIG_KGDB */ - if (in_atomic() || !mm) { + if (unlikely(in_atomic() || !mm)) { if (kernel_mode(regs)) goto bad_area_nosemaphore; @@ -150,7 +150,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, * source. If this is invalid we can skip the address space check, * thus avoiding the deadlock. */ - if (!down_read_trylock(&mm->mmap_sem)) { + if (unlikely(!down_read_trylock(&mm->mmap_sem))) { if (kernel_mode(regs) && !search_exception_tables(regs->pc)) goto bad_area_nosemaphore; @@ -158,16 +158,16 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, } vma = find_vma(mm, address); - if (!vma) + if (unlikely(!vma)) goto bad_area; if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) + if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) goto bad_area; - if (!is_write) + if (unlikely(!is_write)) goto bad_area; /* @@ -179,7 +179,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, * before setting the user r1. Thus we allow the stack to * expand to 1MB without further checks. */ - if (address + 0x100000 < vma->vm_end) { + if (unlikely(address + 0x100000 < vma->vm_end)) { /* get user regs even if this fault is in kernel mode */ struct pt_regs *uregs = current->thread.regs; @@ -209,15 +209,15 @@ good_area: code = SEGV_ACCERR; /* a write */ - if (is_write) { - if (!(vma->vm_flags & VM_WRITE)) + if (unlikely(is_write)) { + if (unlikely(!(vma->vm_flags & VM_WRITE))) goto bad_area; /* a read */ } else { /* protection fault */ - if (error_code & 0x08000000) + if (unlikely(error_code & 0x08000000)) goto bad_area; - if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + if (unlikely(!(vma->vm_flags & (VM_READ | VM_EXEC)))) goto bad_area; } @@ -235,7 +235,7 @@ survive: goto do_sigbus; BUG(); } - if (fault & VM_FAULT_MAJOR) + if (unlikely(fault & VM_FAULT_MAJOR)) current->maj_flt++; else current->min_flt++; diff --git a/arch/microblaze/mm/pgtable.c b/arch/microblaze/mm/pgtable.c index 63a6fd07c48..d31312cde6e 100644 --- a/arch/microblaze/mm/pgtable.c +++ b/arch/microblaze/mm/pgtable.c @@ -154,7 +154,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) err = 0; set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); - if (mem_init_done) + if (unlikely(mem_init_done)) flush_HPTE(0, va, pmd_val(*pd)); /* flush_HPTE(0, va, pg); */ } From 9373dd6ab140f1e6f2e62a9f0bf473987a0b62dc Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 23 Mar 2010 15:46:10 +0100 Subject: [PATCH 469/478] microblaze: Kconfig Fix - pci I forget to remove pci Kconfig option. Signed-off-by: Michal Simek --- arch/microblaze/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 203ec61c6d4..76818f92653 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -75,9 +75,6 @@ config LOCKDEP_SUPPORT config HAVE_LATENCYTOP_SUPPORT def_bool y -config PCI - def_bool n - config DTC def_bool y From 0691c97d74cbdfd49333ef01939ecaef158ebe1b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 24 Mar 2010 10:09:17 +0100 Subject: [PATCH 470/478] microblaze: Use MICROBLAZE_TLB_SIZE in asm code TLB size was hardcoded in asm code. This patch brings ability to change TLB size only in one place. (mmu.h). Signed-off-by: Michal Simek --- arch/microblaze/kernel/head.S | 2 +- arch/microblaze/kernel/misc.S | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index e397d5d5257..ba2c0333c6b 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S @@ -134,7 +134,7 @@ _copy_bram: * virtual to physical. */ nop - addik r3, r0, 63 /* Invalidate all TLB entries */ + addik r3, r0, MICROBLAZE_TLB_SIZE -1 /* Invalidate all TLB entries */ _invalidate: mts rtlbx, r3 mts rtlbhi, r0 /* flush: ensure V is clear */ diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S index 18681eed5ec..7cf86498326 100644 --- a/arch/microblaze/kernel/misc.S +++ b/arch/microblaze/kernel/misc.S @@ -29,7 +29,7 @@ .type _tlbia, @function .align 4; _tlbia: - addik r12, r0, 63 /* flush all entries (63 - 3) */ + addik r12, r0, MICROBLAZE_TLB_SIZE - 1 /* flush all entries (63 - 3) */ /* isync */ _tlbia_1: mts rtlbx, r12 @@ -75,7 +75,7 @@ early_console_reg_tlb_alloc: * Load a TLB entry for the UART, so that microblaze_progress() can use * the UARTs nice and early. We use a 4k real==virtual mapping. */ - ori r4, r0, 63 + ori r4, r0, MICROBLAZE_TLB_SIZE - 1 mts rtlbx, r4 /* TLB slot 2 */ or r4,r5,r0 From 3f2189358666b6fa09d41f527be07b3cc8026050 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 24 Mar 2010 11:06:23 +0100 Subject: [PATCH 471/478] microblaze: head.S typo fix I forget to change register name in comments. Signed-off-by: Michal Simek --- arch/microblaze/kernel/head.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index ba2c0333c6b..da6a5f5dc76 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S @@ -105,8 +105,8 @@ no_fdt_arg: tophys(r4,r4) /* convert to phys address */ ori r3, r0, COMMAND_LINE_SIZE - 1 /* number of loops */ _copy_command_line: - lbu r2, r5, r6 /* r7=r5+r6 - r5 contain pointer to command line */ - sb r2, r4, r6 /* addr[r4+r6]= r7*/ + lbu r2, r5, r6 /* r2=r5+r6 - r5 contain pointer to command line */ + sb r2, r4, r6 /* addr[r4+r6]= r2*/ addik r6, r6, 1 /* increment counting */ bgtid r3, _copy_command_line /* loop for all entries */ addik r3, r3, -1 /* descrement loop */ From 6059b3cbeb27a38e3ca9ac9d2827f7b5be32e2ba Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 24 Mar 2010 11:07:10 +0100 Subject: [PATCH 472/478] microblaze: Print early printk information to log buffer If early printk console is not enabled then all messages are written to log buffer. Signed-off-by: Michal Simek --- arch/microblaze/kernel/setup.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index f974ec7aa35..17c98dbcec8 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -92,6 +92,12 @@ inline unsigned get_romfs_len(unsigned *addr) } #endif /* CONFIG_MTD_UCLINUX_EBSS */ +#if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_SERIAL_UARTLITE_CONSOLE) +#define eprintk early_printk +#else +#define eprintk printk +#endif + void __init machine_early_init(const char *cmdline, unsigned int ram, unsigned int fdt, unsigned int msr) { @@ -139,32 +145,32 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, setup_early_printk(NULL); #endif - early_printk("Ramdisk addr 0x%08x, ", ram); + eprintk("Ramdisk addr 0x%08x, ", ram); if (fdt) - early_printk("FDT at 0x%08x\n", fdt); + eprintk("FDT at 0x%08x\n", fdt); else - early_printk("Compiled-in FDT at 0x%08x\n", + eprintk("Compiled-in FDT at 0x%08x\n", (unsigned int)_fdt_start); #ifdef CONFIG_MTD_UCLINUX - early_printk("Found romfs @ 0x%08x (0x%08x)\n", + eprintk("Found romfs @ 0x%08x (0x%08x)\n", romfs_base, romfs_size); - early_printk("#### klimit %p ####\n", old_klimit); + eprintk("#### klimit %p ####\n", old_klimit); BUG_ON(romfs_size < 0); /* What else can we do? */ - early_printk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n", + eprintk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n", romfs_size, romfs_base, (unsigned)&_ebss); - early_printk("New klimit: 0x%08x\n", (unsigned)klimit); + eprintk("New klimit: 0x%08x\n", (unsigned)klimit); #endif #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR if (msr) - early_printk("!!!Your kernel has setup MSR instruction but " + eprintk("!!!Your kernel has setup MSR instruction but " "CPU don't have it %d\n", msr); #else if (!msr) - early_printk("!!!Your kernel not setup MSR instruction but " + eprintk("!!!Your kernel not setup MSR instruction but " "CPU have it %d\n", msr); #endif From ca3865bae5ff86f5670edc9beebbd1f58c29de85 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 22 Mar 2010 20:31:26 +0100 Subject: [PATCH 473/478] microblaze: Support word copying in copy_tofrom_user Word copying is used only for aligned addresses. Here is space for improving to use any better copying technique. Look at memcpy implementation. Signed-off-by: Michal Simek --- arch/microblaze/lib/uaccess_old.S | 39 ++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/arch/microblaze/lib/uaccess_old.S b/arch/microblaze/lib/uaccess_old.S index b327524a803..5810cec54a7 100644 --- a/arch/microblaze/lib/uaccess_old.S +++ b/arch/microblaze/lib/uaccess_old.S @@ -53,7 +53,6 @@ __strncpy_user: nop .size __strncpy_user, . - __strncpy_user - .section .fixup, "ax" .align 2 4: @@ -95,7 +94,6 @@ __strnlen_user: nop .size __strnlen_user, . - __strnlen_user - .section .fixup,"ax" 4: brid 3b @@ -121,21 +119,34 @@ __copy_tofrom_user: * r7, r3 - count * r4 - tempval */ - addik r3,r7,0 - beqi r3,3f -1: - lbu r4,r6,r0 - addik r6,r6,1 -2: - sb r4,r5,r0 - addik r3,r3,-1 - bneid r3,1b - addik r5,r5,1 /* delay slot */ + beqid r7, 3f /* zero size is not likely */ + andi r3, r7, 0x3 /* filter add count */ + bneid r3, 4f /* if is odd value then byte copying */ + or r3, r5, r6 /* find if is any to/from unaligned */ + andi r3, r3, 0x3 /* mask unaligned */ + bneid r3, 1f /* it is unaligned -> then jump */ + or r3, r0, r0 + +/* at least one 4 byte copy */ +5: lw r4, r6, r3 +6: sw r4, r5, r3 + addik r7, r7, -4 + bneid r7, 5b + addik r3, r3, 4 + addik r3, r7, 0 + rtsd r15, 8 + nop +4: or r3, r0, r0 +1: lbu r4,r6,r3 +2: sb r4,r5,r3 + addik r7,r7,-1 + bneid r7,1b + addik r3,r3,1 /* delay slot */ 3: + addik r3,r7,0 rtsd r15,8 nop .size __copy_tofrom_user, . - __copy_tofrom_user - .section __ex_table,"a" - .word 1b,3b,2b,3b + .word 1b,3b,2b,3b,5b,3b,6b,3b From b95c35e76b29ba812e5dabdd91592e25ec640e93 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Thu, 1 Apr 2010 15:13:57 +0200 Subject: [PATCH 474/478] oom: fix the unsafe usage of badness() in proc_oom_score() proc_oom_score(task) has a reference to task_struct, but that is all. If this task was already released before we take tasklist_lock - we can't use task->group_leader, it points to nowhere - it is not safe to call badness() even if this task is ->group_leader, has_intersects_mems_allowed() assumes it is safe to iterate over ->thread_group list. - even worse, badness() can hit ->signal == NULL Add the pid_alive() check to ensure __unhash_process() was not called. Also, use "task" instead of task->group_leader. badness() should return the same result for any sub-thread. Currently this is not true, but this should be changed anyway. Signed-off-by: Oleg Nesterov Cc: stable@kernel.org Signed-off-by: Linus Torvalds --- fs/proc/base.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index a7310841c83..b1f6e62773d 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -442,12 +442,13 @@ static const struct file_operations proc_lstats_operations = { unsigned long badness(struct task_struct *p, unsigned long uptime); static int proc_oom_score(struct task_struct *task, char *buffer) { - unsigned long points; + unsigned long points = 0; struct timespec uptime; do_posix_clock_monotonic_gettime(&uptime); read_lock(&tasklist_lock); - points = badness(task->group_leader, uptime.tv_sec); + if (pid_alive(task)) + points = badness(task, uptime.tv_sec); read_unlock(&tasklist_lock); return sprintf(buffer, "%lu\n", points); } From 85257024096a96fc5c00ce59d685f62bbed3ad95 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 23 Mar 2010 19:30:52 +0100 Subject: [PATCH 475/478] x86: Move notify_cpu_starting() callback to a later stage Because we need to have cpu identification things done by the time we run CPU_STARTING notifiers. ( This init ordering will be relied on by the next fix. ) Signed-off-by: Peter Zijlstra LKML-Reference: <1269353485.5109.48.camel@twins> Signed-off-by: Ingo Molnar --- arch/x86/kernel/smpboot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 06d98ae5a80..6808b934d6c 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -242,8 +242,6 @@ static void __cpuinit smp_callin(void) end_local_APIC_setup(); map_cpu_to_logical_apicid(); - notify_cpu_starting(cpuid); - /* * Need to setup vector mappings before we enable interrupts. */ @@ -264,6 +262,8 @@ static void __cpuinit smp_callin(void) */ smp_store_cpu_info(cpuid); + notify_cpu_starting(cpuid); + /* * Allow the master to continue. */ From b38b24ead33417146e051453d04bf60b8d2d7e25 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 23 Mar 2010 19:31:15 +0100 Subject: [PATCH 476/478] perf, x86: Fix AMD hotplug & constraint initialization Commit 3f6da39 ("perf: Rework and fix the arch CPU-hotplug hooks") moved the amd northbridge allocation from CPUS_ONLINE to CPUS_PREPARE_UP however amd_nb_id() doesn't work yet on prepare so it would simply bail basically reverting to a state where we do not properly track node wide constraints - causing weird perf results. Fix up the AMD NorthBridge initialization code by allocating from CPU_UP_PREPARE and installing it from CPU_STARTING once we have the proper nb_id. It also properly deals with the allocation failing. Signed-off-by: Peter Zijlstra [ robustify using amd_has_nb() ] Signed-off-by: Stephane Eranian LKML-Reference: <1269353485.5109.48.camel@twins> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 8 +-- arch/x86/kernel/cpu/perf_event_amd.c | 80 ++++++++++++++++------------ 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 5fb490c6ee5..bd28cf9d8a8 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -158,7 +158,7 @@ struct x86_pmu { struct perf_event *event); struct event_constraint *event_constraints; - void (*cpu_prepare)(int cpu); + int (*cpu_prepare)(int cpu); void (*cpu_starting)(int cpu); void (*cpu_dying)(int cpu); void (*cpu_dead)(int cpu); @@ -1333,11 +1333,12 @@ static int __cpuinit x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu) { unsigned int cpu = (long)hcpu; + int ret = NOTIFY_OK; switch (action & ~CPU_TASKS_FROZEN) { case CPU_UP_PREPARE: if (x86_pmu.cpu_prepare) - x86_pmu.cpu_prepare(cpu); + ret = x86_pmu.cpu_prepare(cpu); break; case CPU_STARTING: @@ -1350,6 +1351,7 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu) x86_pmu.cpu_dying(cpu); break; + case CPU_UP_CANCELED: case CPU_DEAD: if (x86_pmu.cpu_dead) x86_pmu.cpu_dead(cpu); @@ -1359,7 +1361,7 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu) break; } - return NOTIFY_OK; + return ret; } static void __init pmu_check_apic(void) diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index b87e0b6970c..db6f7d4056e 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c @@ -137,6 +137,13 @@ static inline int amd_is_nb_event(struct hw_perf_event *hwc) return (hwc->config & 0xe0) == 0xe0; } +static inline int amd_has_nb(struct cpu_hw_events *cpuc) +{ + struct amd_nb *nb = cpuc->amd_nb; + + return nb && nb->nb_id != -1; +} + static void amd_put_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) { @@ -147,7 +154,7 @@ static void amd_put_event_constraints(struct cpu_hw_events *cpuc, /* * only care about NB events */ - if (!(nb && amd_is_nb_event(hwc))) + if (!(amd_has_nb(cpuc) && amd_is_nb_event(hwc))) return; /* @@ -214,7 +221,7 @@ amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) /* * if not NB event or no NB, then no constraints */ - if (!(nb && amd_is_nb_event(hwc))) + if (!(amd_has_nb(cpuc) && amd_is_nb_event(hwc))) return &unconstrained; /* @@ -293,51 +300,55 @@ static struct amd_nb *amd_alloc_nb(int cpu, int nb_id) return nb; } -static void amd_pmu_cpu_online(int cpu) +static int amd_pmu_cpu_prepare(int cpu) { - struct cpu_hw_events *cpu1, *cpu2; - struct amd_nb *nb = NULL; + struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); + + WARN_ON_ONCE(cpuc->amd_nb); + + if (boot_cpu_data.x86_max_cores < 2) + return NOTIFY_OK; + + cpuc->amd_nb = amd_alloc_nb(cpu, -1); + if (!cpuc->amd_nb) + return NOTIFY_BAD; + + return NOTIFY_OK; +} + +static void amd_pmu_cpu_starting(int cpu) +{ + struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); + struct amd_nb *nb; int i, nb_id; if (boot_cpu_data.x86_max_cores < 2) return; - /* - * function may be called too early in the - * boot process, in which case nb_id is bogus - */ nb_id = amd_get_nb_id(cpu); - if (nb_id == BAD_APICID) - return; - - cpu1 = &per_cpu(cpu_hw_events, cpu); - cpu1->amd_nb = NULL; + WARN_ON_ONCE(nb_id == BAD_APICID); raw_spin_lock(&amd_nb_lock); for_each_online_cpu(i) { - cpu2 = &per_cpu(cpu_hw_events, i); - nb = cpu2->amd_nb; - if (!nb) + nb = per_cpu(cpu_hw_events, i).amd_nb; + if (WARN_ON_ONCE(!nb)) continue; - if (nb->nb_id == nb_id) - goto found; + + if (nb->nb_id == nb_id) { + kfree(cpuc->amd_nb); + cpuc->amd_nb = nb; + break; + } } - nb = amd_alloc_nb(cpu, nb_id); - if (!nb) { - pr_err("perf_events: failed NB allocation for CPU%d\n", cpu); - raw_spin_unlock(&amd_nb_lock); - return; - } -found: - nb->refcnt++; - cpu1->amd_nb = nb; + cpuc->amd_nb->nb_id = nb_id; + cpuc->amd_nb->refcnt++; raw_spin_unlock(&amd_nb_lock); } -static void amd_pmu_cpu_offline(int cpu) +static void amd_pmu_cpu_dead(int cpu) { struct cpu_hw_events *cpuhw; @@ -349,8 +360,10 @@ static void amd_pmu_cpu_offline(int cpu) raw_spin_lock(&amd_nb_lock); if (cpuhw->amd_nb) { - if (--cpuhw->amd_nb->refcnt == 0) - kfree(cpuhw->amd_nb); + struct amd_nb *nb = cpuhw->amd_nb; + + if (nb->nb_id == -1 || --nb->refcnt == 0) + kfree(nb); cpuhw->amd_nb = NULL; } @@ -379,8 +392,9 @@ static __initconst struct x86_pmu amd_pmu = { .get_event_constraints = amd_get_event_constraints, .put_event_constraints = amd_put_event_constraints, - .cpu_prepare = amd_pmu_cpu_online, - .cpu_dead = amd_pmu_cpu_offline, + .cpu_prepare = amd_pmu_cpu_prepare, + .cpu_starting = amd_pmu_cpu_starting, + .cpu_dead = amd_pmu_cpu_dead, }; static __init int amd_pmu_init(void) From 257ef9d21f1b008a6c7425544b36641c4325a922 Mon Sep 17 00:00:00 2001 From: Torok Edwin Date: Wed, 17 Mar 2010 12:07:16 +0200 Subject: [PATCH 477/478] perf, x86: Fix callgraphs of 32-bit processes on 64-bit kernels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When profiling a 32-bit process on a 64-bit kernel, callgraph tracing stopped after the first function, because it has seen a garbage memory address (tried to interpret the frame pointer, and return address as a 64-bit pointer). Fix this by using a struct stack_frame with 32-bit pointers when the TIF_IA32 flag is set. Note that TIF_IA32 flag must be used, and not is_compat_task(), because the latter is only set when the 32-bit process is executing a syscall, which may not always be the case (when tracing page fault events for example). Signed-off-by: Török Edwin Signed-off-by: Peter Zijlstra Acked-by: Frederic Weisbecker Cc: "H. Peter Anvin" Cc: Paul Mackerras Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org LKML-Reference: <1268820436-13145-1-git-send-email-edwintorok@gmail.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 44 ++++++++++++++++++++++++++++---- arch/x86/kernel/dumpstack.h | 5 ++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index bd28cf9d8a8..53ea4cf1a87 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -28,6 +28,7 @@ #include #include #include +#include static u64 perf_event_mask __read_mostly; @@ -1630,14 +1631,42 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n) return len; } -static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) +#ifdef CONFIG_COMPAT +static inline int +perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry) { - unsigned long bytes; + /* 32-bit process in 64-bit kernel. */ + struct stack_frame_ia32 frame; + const void __user *fp; - bytes = copy_from_user_nmi(frame, fp, sizeof(*frame)); + if (!test_thread_flag(TIF_IA32)) + return 0; - return bytes == sizeof(*frame); + fp = compat_ptr(regs->bp); + while (entry->nr < PERF_MAX_STACK_DEPTH) { + unsigned long bytes; + frame.next_frame = 0; + frame.return_address = 0; + + bytes = copy_from_user_nmi(&frame, fp, sizeof(frame)); + if (bytes != sizeof(frame)) + break; + + if (fp < compat_ptr(regs->sp)) + break; + + callchain_store(entry, frame.return_address); + fp = compat_ptr(frame.next_frame); + } + return 1; } +#else +static inline int +perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry) +{ + return 0; +} +#endif static void perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry) @@ -1653,11 +1682,16 @@ perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry) callchain_store(entry, PERF_CONTEXT_USER); callchain_store(entry, regs->ip); + if (perf_callchain_user32(regs, entry)) + return; + while (entry->nr < PERF_MAX_STACK_DEPTH) { + unsigned long bytes; frame.next_frame = NULL; frame.return_address = 0; - if (!copy_stack_frame(fp, &frame)) + bytes = copy_from_user_nmi(&frame, fp, sizeof(frame)); + if (bytes != sizeof(frame)) break; if ((unsigned long)fp < regs->sp) diff --git a/arch/x86/kernel/dumpstack.h b/arch/x86/kernel/dumpstack.h index 29e5f7c845b..e39e77168a3 100644 --- a/arch/x86/kernel/dumpstack.h +++ b/arch/x86/kernel/dumpstack.h @@ -30,6 +30,11 @@ struct stack_frame { unsigned long return_address; }; +struct stack_frame_ia32 { + u32 next_frame; + u32 return_address; +}; + static inline unsigned long rewind_frame_pointer(int n) { struct stack_frame *frame; From 8bb39f9aa068262732fe44b965d7a6eb5a5a7d67 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Fri, 26 Mar 2010 11:11:33 +0100 Subject: [PATCH 478/478] perf: Fix 'perf sched record' deadlock perf sched record can deadlock a box should the holder of handle->data->lock take an interrupt, and then attempt to acquire an rq lock held by a CPU trying to acquire the same lock. Disable interrupts. CPU0 CPU1 sched event with rq->lock held grab handle->data->lock spin on handle->data->lock interrupt try to grab rq->lock Reported-by: Li Zefan Signed-off-by: Mike Galbraith Tested-by: Li Zefan Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <1269598293.6174.8.camel@marge.simson.net> Signed-off-by: Ingo Molnar --- kernel/perf_event.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index b0feb4795af..96aae13c796 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -3376,15 +3376,23 @@ static void perf_event_task_output(struct perf_event *event, struct perf_task_event *task_event) { struct perf_output_handle handle; - int size; struct task_struct *task = task_event->task; - int ret; + unsigned long flags; + int size, ret; + + /* + * If this CPU attempts to acquire an rq lock held by a CPU spinning + * in perf_output_lock() from interrupt context, it's game over. + */ + local_irq_save(flags); size = task_event->event_id.header.size; ret = perf_output_begin(&handle, event, size, 0, 0); - if (ret) + if (ret) { + local_irq_restore(flags); return; + } task_event->event_id.pid = perf_event_pid(event, task); task_event->event_id.ppid = perf_event_pid(event, current); @@ -3395,6 +3403,7 @@ static void perf_event_task_output(struct perf_event *event, perf_output_put(&handle, task_event->event_id); perf_output_end(&handle); + local_irq_restore(flags); } static int perf_event_task_match(struct perf_event *event)