From: Greg Kroah-Hartman Date: Fri, 30 Mar 2007 20:16:29 +0000 (-0700) Subject: new 2.6.20 patches X-Git-Tag: v2.6.20.5~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=eea64fd91ef1f25cd6a87942e761524276d23076;p=thirdparty%2Fkernel%2Fstable-queue.git new 2.6.20 patches --- diff --git a/queue-2.6.20/dccp-fix-exploitable-hole-in-dccp-socket-options.patch b/queue-2.6.20/dccp-fix-exploitable-hole-in-dccp-socket-options.patch new file mode 100644 index 00000000000..fb624a8b056 --- /dev/null +++ b/queue-2.6.20/dccp-fix-exploitable-hole-in-dccp-socket-options.patch @@ -0,0 +1,51 @@ +From stable-bounces@linux.kernel.org Thu Mar 29 11:59:00 2007 +From: David Miller +Date: Thu, 29 Mar 2007 11:57:36 -0700 (PDT) +Subject: DCCP: Fix exploitable hole in DCCP socket options +To: stable@kernel.org +Cc: bunk@stusta.de +Message-ID: <20070329.115736.39158322.davem@davemloft.net> + + +From: Arnaldo Carvalho de Melo + +[DCCP] getsockopt: Fix DCCP_SOCKOPT_[SEND,RECV]_CSCOV + +We were only checking if there was enough space to put the int, but +left len as specified by the (malicious) user, sigh, fix it by setting +len to sizeof(val) and transfering just one int worth of data, the one +asked for. + +Also check for negative len values. + +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/dccp/proto.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/net/dccp/proto.c ++++ b/net/dccp/proto.c +@@ -575,7 +575,7 @@ static int do_dccp_getsockopt(struct soc + if (get_user(len, optlen)) + return -EFAULT; + +- if (len < sizeof(int)) ++ if (len < (int)sizeof(int)) + return -EINVAL; + + dp = dccp_sk(sk); +@@ -589,9 +589,11 @@ static int do_dccp_getsockopt(struct soc + (__be32 __user *)optval, optlen); + case DCCP_SOCKOPT_SEND_CSCOV: + val = dp->dccps_pcslen; ++ len = sizeof(val); + break; + case DCCP_SOCKOPT_RECV_CSCOV: + val = dp->dccps_pcrlen; ++ len = sizeof(val); + break; + case 128 ... 191: + return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, diff --git a/queue-2.6.20/fix-decnet-endianness.patch b/queue-2.6.20/fix-decnet-endianness.patch new file mode 100644 index 00000000000..e5ba83dc475 --- /dev/null +++ b/queue-2.6.20/fix-decnet-endianness.patch @@ -0,0 +1,61 @@ +From stable-bounces@linux.kernel.org Thu Mar 29 12:34:12 2007 +From: Al Viro +Date: Thu, 29 Mar 2007 12:32:48 -0700 (PDT) +Subject: Fix decnet endianness +To: stable@kernel.org +Cc: bunk@stusta.de +Message-ID: <20070329.123248.62343482.davem@davemloft.net> + + +From: Al Viro + +[PATCH] FRA_{DST,SRC} are le16 for decnet + +Signed-off-by: Al Viro +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + net/decnet/dn_rules.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/net/decnet/dn_rules.c ++++ b/net/decnet/dn_rules.c +@@ -151,10 +151,10 @@ static int dn_fib_rule_configure(struct + } + + if (tb[FRA_SRC]) +- r->src = nla_get_u16(tb[FRA_SRC]); ++ r->src = nla_get_le16(tb[FRA_SRC]); + + if (tb[FRA_DST]) +- r->dst = nla_get_u16(tb[FRA_DST]); ++ r->dst = nla_get_le16(tb[FRA_DST]); + + r->src_len = frh->src_len; + r->srcmask = dnet_make_mask(r->src_len); +@@ -176,10 +176,10 @@ static int dn_fib_rule_compare(struct fi + if (frh->dst_len && (r->dst_len != frh->dst_len)) + return 0; + +- if (tb[FRA_SRC] && (r->src != nla_get_u16(tb[FRA_SRC]))) ++ if (tb[FRA_SRC] && (r->src != nla_get_le16(tb[FRA_SRC]))) + return 0; + +- if (tb[FRA_DST] && (r->dst != nla_get_u16(tb[FRA_DST]))) ++ if (tb[FRA_DST] && (r->dst != nla_get_le16(tb[FRA_DST]))) + return 0; + + return 1; +@@ -214,9 +214,9 @@ static int dn_fib_rule_fill(struct fib_r + frh->tos = 0; + + if (r->dst_len) +- NLA_PUT_U16(skb, FRA_DST, r->dst); ++ NLA_PUT_LE16(skb, FRA_DST, r->dst); + if (r->src_len) +- NLA_PUT_U16(skb, FRA_SRC, r->src); ++ NLA_PUT_LE16(skb, FRA_SRC, r->src); + + return 0; + diff --git a/queue-2.6.20/ide-clear-bmdma-status-in-ide_intr-for-ichx-controllers.patch b/queue-2.6.20/ide-clear-bmdma-status-in-ide_intr-for-ichx-controllers.patch new file mode 100644 index 00000000000..f79b75ef5c3 --- /dev/null +++ b/queue-2.6.20/ide-clear-bmdma-status-in-ide_intr-for-ichx-controllers.patch @@ -0,0 +1,196 @@ +From stable-bounces@linux.kernel.org Wed Mar 21 13:09:37 2007 +Message-ID: <460190A8.8020507@redhat.com> +Date: Wed, 21 Mar 2007 16:08:08 -0400 +From: Albert Lee +To: linux-stable +Subject: ide: clear bmdma status in ide_intr() for ICHx controllers (revised #4) + +From: Albert Lee + +ide: clear bmdma status in ide_intr() for ICHx controllers (revised #4) + +patch 1/2 (revised): +- Fix drive->waiting_for_dma to work with CDB-intr devices. +- Do the dma status clearing in ide_intr() and add a new + hwif->ide_dma_clear_irq for Intel ICHx controllers. + +Revised per Alan, Sergei and Bart's advice. + +Patch against 2.6.20-rc6. Tested ok on my ICH4 and pdc20275 adapters. +Please review/apply, thanks. + +Signed-off-by: Albert Lee +Cc: Sergei Shtylyov +Cc: Alan Cox +Cc: Adam Hawks +Cc: Chuck Ebbert +Signed-off-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/ide/ide-cd.c | 8 ++++++ + drivers/ide/ide-io.c | 11 ++++++++ + drivers/ide/ide.c | 1 + drivers/ide/pci/piix.c | 63 +++++++++++++++++++++++++++++++++++++------------ + include/linux/ide.h | 1 + 5 files changed, 69 insertions(+), 15 deletions(-) + +--- a/drivers/ide/ide-cd.c ++++ b/drivers/ide/ide-cd.c +@@ -930,6 +930,10 @@ static ide_startstop_t cdrom_start_packe + HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); + + if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { ++ /* waiting for CDB interrupt, not DMA yet. */ ++ if (info->dma) ++ drive->waiting_for_dma = 0; ++ + /* packet command */ + ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry); + return ide_started; +@@ -972,6 +976,10 @@ static ide_startstop_t cdrom_transfer_pa + /* Check for errors. */ + if (cdrom_decode_status(drive, DRQ_STAT, NULL)) + return ide_stopped; ++ ++ /* Ok, next interrupt will be DMA interrupt. */ ++ if (info->dma) ++ drive->waiting_for_dma = 1; + } else { + /* Otherwise, we must wait for DRQ to get set. */ + if (ide_wait_stat(&startstop, drive, DRQ_STAT, +--- a/drivers/ide/ide-io.c ++++ b/drivers/ide/ide-io.c +@@ -1646,6 +1646,17 @@ irqreturn_t ide_intr (int irq, void *dev + del_timer(&hwgroup->timer); + spin_unlock(&ide_lock); + ++ /* Some controllers might set DMA INTR no matter DMA or PIO; ++ * bmdma status might need to be cleared even for ++ * PIO interrupts to prevent spurious/lost irq. ++ */ ++ if (hwif->ide_dma_clear_irq && !(drive->waiting_for_dma)) ++ /* ide_dma_end() needs bmdma status for error checking. ++ * So, skip clearing bmdma status here and leave it ++ * to ide_dma_end() if this is dma interrupt. ++ */ ++ hwif->ide_dma_clear_irq(drive); ++ + if (drive->unmask) + local_irq_enable_in_hardirq(); + /* service this interrupt, may set handler for next interrupt */ +--- a/drivers/ide/ide.c ++++ b/drivers/ide/ide.c +@@ -503,6 +503,7 @@ static void ide_hwif_restore(ide_hwif_t + hwif->ide_dma_on = tmp_hwif->ide_dma_on; + hwif->ide_dma_off_quietly = tmp_hwif->ide_dma_off_quietly; + hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq; ++ hwif->ide_dma_clear_irq = tmp_hwif->ide_dma_clear_irq; + hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on; + hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off; + hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq; +--- a/drivers/ide/pci/piix.c ++++ b/drivers/ide/pci/piix.c +@@ -411,17 +411,14 @@ fast_ata_pio: + } + + /** +- * init_chipset_piix - set up the PIIX chipset +- * @dev: PCI device to set up +- * @name: Name of the device ++ * piix_is_ichx - check if ICHx ++ * @dev: PCI device to check + * +- * Initialize the PCI device as required. For the PIIX this turns +- * out to be nice and simple ++ * returns 1 if ICHx, 0 otherwise. + */ +- +-static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) ++static int piix_is_ichx(struct pci_dev *dev) + { +- switch(dev->device) { ++ switch (dev->device) { + case PCI_DEVICE_ID_INTEL_82801EB_1: + case PCI_DEVICE_ID_INTEL_82801AA_1: + case PCI_DEVICE_ID_INTEL_82801AB_1: +@@ -439,19 +436,51 @@ static unsigned int __devinit init_chips + case PCI_DEVICE_ID_INTEL_ICH7_21: + case PCI_DEVICE_ID_INTEL_ESB2_18: + case PCI_DEVICE_ID_INTEL_ICH8_6: +- { +- unsigned int extra = 0; +- pci_read_config_dword(dev, 0x54, &extra); +- pci_write_config_dword(dev, 0x54, extra|0x400); +- } +- default: +- break; ++ return 1; + } + + return 0; + } + + /** ++ * init_chipset_piix - set up the PIIX chipset ++ * @dev: PCI device to set up ++ * @name: Name of the device ++ * ++ * Initialize the PCI device as required. For the PIIX this turns ++ * out to be nice and simple ++ */ ++ ++static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) ++{ ++ if (piix_is_ichx(dev)) { ++ unsigned int extra = 0; ++ pci_read_config_dword(dev, 0x54, &extra); ++ pci_write_config_dword(dev, 0x54, extra|0x400); ++ } ++ ++ return 0; ++} ++ ++/** ++ * piix_dma_clear_irq - clear BMDMA status ++ * @drive: IDE drive to clear ++ * ++ * Called from ide_intr() for PIO interrupts ++ * to clear BMDMA status as needed by ICHx ++ */ ++static void piix_dma_clear_irq(ide_drive_t *drive) ++{ ++ ide_hwif_t *hwif = HWIF(drive); ++ u8 dma_stat; ++ ++ /* clear the INTR & ERROR bits */ ++ dma_stat = hwif->INB(hwif->dma_status); ++ /* Should we force the bit as well ? */ ++ hwif->OUTB(dma_stat, hwif->dma_status); ++} ++ ++/** + * init_hwif_piix - fill in the hwif for the PIIX + * @hwif: IDE interface + * +@@ -487,6 +516,10 @@ static void __devinit init_hwif_piix(ide + if (!hwif->dma_base) + return; + ++ /* ICHx need to clear the bmdma status for all interrupts */ ++ if (piix_is_ichx(hwif->pci_dev)) ++ hwif->ide_dma_clear_irq = &piix_dma_clear_irq; ++ + hwif->atapi_dma = 1; + hwif->ultra_mask = 0x3f; + hwif->mwdma_mask = 0x06; +--- a/include/linux/ide.h ++++ b/include/linux/ide.h +@@ -727,6 +727,7 @@ typedef struct hwif_s { + int (*ide_dma_on)(ide_drive_t *drive); + int (*ide_dma_off_quietly)(ide_drive_t *drive); + int (*ide_dma_test_irq)(ide_drive_t *drive); ++ void (*ide_dma_clear_irq)(ide_drive_t *drive); + int (*ide_dma_host_on)(ide_drive_t *drive); + int (*ide_dma_host_off)(ide_drive_t *drive); + int (*ide_dma_lostirq)(ide_drive_t *drive); diff --git a/queue-2.6.20/ide-remove-clearing-bmdma-status-from-cdrom_decode_status.patch b/queue-2.6.20/ide-remove-clearing-bmdma-status-from-cdrom_decode_status.patch new file mode 100644 index 00000000000..fc9440f86ae --- /dev/null +++ b/queue-2.6.20/ide-remove-clearing-bmdma-status-from-cdrom_decode_status.patch @@ -0,0 +1,72 @@ +From stable-bounces@linux.kernel.org Wed Mar 21 13:10:10 2007 +From: Albert Lee +Date: Wed, 21 Mar 2007 16:08:49 -0400 +Subject: ide: remove clearing bmdma status from cdrom_decode_status() (rev #4) +To: linux-stable +Message-ID: <460190D1.2080305@redhat.com> + +From: Albert Lee + +ide: remove clearing bmdma status from cdrom_decode_status() (rev #4) + +patch 2/2: + Remove clearing bmdma status from cdrom_decode_status() since ATA devices + might need it as well. + + (http://lkml.org/lkml/2006/12/4/201 and http://lkml.org/lkml/2006/11/15/94) + +Signed-off-by: Albert Lee +Cc: Sergei Shtylyov +Cc: Alan Cox +Cc: "Adam W. Hawks" +Cc: Chuck Ebbert +Signed-off-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/ide/ide-cd.c | 7 ------- + drivers/ide/pci/piix.c | 4 ---- + include/linux/ide.h | 1 - + 3 files changed, 12 deletions(-) + +--- a/drivers/ide/ide-cd.c ++++ b/drivers/ide/ide-cd.c +@@ -687,15 +687,8 @@ static void ide_dump_status_no_sense(ide + static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) + { + struct request *rq = HWGROUP(drive)->rq; +- ide_hwif_t *hwif = HWIF(drive); + int stat, err, sense_key; + +- /* We may have bogus DMA interrupts in PIO state here */ +- if (HWIF(drive)->dma_status && hwif->atapi_irq_bogon) { +- stat = hwif->INB(hwif->dma_status); +- /* Should we force the bit as well ? */ +- hwif->OUTB(stat, hwif->dma_status); +- } + /* Check for errors. */ + stat = HWIF(drive)->INB(IDE_STATUS_REG); + if (stat_ret) +--- a/drivers/ide/pci/piix.c ++++ b/drivers/ide/pci/piix.c +@@ -502,10 +502,6 @@ static void __devinit init_hwif_piix(ide + /* This is a painful system best to let it self tune for now */ + return; + } +- /* ESB2 appears to generate spurious DMA interrupts in PIO mode +- when in native mode */ +- if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_ESB2_18) +- hwif->atapi_irq_bogon = 1; + + hwif->autodma = 0; + hwif->tuneproc = &piix_tune_drive; +--- a/include/linux/ide.h ++++ b/include/linux/ide.h +@@ -797,7 +797,6 @@ typedef struct hwif_s { + unsigned sg_mapped : 1; /* sg_table and sg_nents are ready */ + unsigned no_io_32bit : 1; /* 1 = can not do 32-bit IO ops */ + unsigned err_stops_fifo : 1; /* 1=data FIFO is cleared by an error */ +- unsigned atapi_irq_bogon : 1; /* Generates spurious DMA interrupts in PIO mode */ + + struct device gendev; + struct completion gendev_rel_comp; /* To deal with device release() */ diff --git a/queue-2.6.20/ieee1394-dv1394-fix-cardbus-card-ejection.patch b/queue-2.6.20/ieee1394-dv1394-fix-cardbus-card-ejection.patch new file mode 100644 index 00000000000..065ea650af6 --- /dev/null +++ b/queue-2.6.20/ieee1394-dv1394-fix-cardbus-card-ejection.patch @@ -0,0 +1,57 @@ +From stable-bounces@linux.kernel.org Sun Mar 25 12:25:57 2007 +From: Stefan Richter +Date: Sun, 25 Mar 2007 21:24:43 +0200 (CEST) +Subject: ieee1394: dv1394: fix CardBus card ejection +To: stable@kernel.org +Cc: linux-kernel@vger.kernel.org +Message-ID: +Content-Disposition: INLINE + +From: Stefan Richter + +Fix NULL pointer dereference on hot ejection of a FireWire card while +dv1394 was loaded. http://bugzilla.kernel.org/show_bug.cgi?id=7121 +I did not test card ejection with open /dev/dv1394 files yet. + +Signed-off-by: Stefan Richter +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/ieee1394/dv1394.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/drivers/ieee1394/dv1394.c ++++ b/drivers/ieee1394/dv1394.c +@@ -2267,11 +2267,7 @@ static void dv1394_remove_host (struct h + { + struct video_card *video; + unsigned long flags; +- int id = host->id; +- +- /* We only work with the OHCI-1394 driver */ +- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) +- return; ++ int id = host->id, found_ohci_card = 0; + + /* find the corresponding video_cards */ + do { +@@ -2284,6 +2280,7 @@ static void dv1394_remove_host (struct h + if ((tmp_vid->id >> 2) == id) { + list_del(&tmp_vid->list); + video = tmp_vid; ++ found_ohci_card = 1; + break; + } + } +@@ -2293,8 +2290,9 @@ static void dv1394_remove_host (struct h + dv1394_un_init(video); + } while (video != NULL); + +- class_device_destroy(hpsb_protocol_class, +- MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2))); ++ if (found_ohci_card) ++ class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR, ++ IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id << 2))); + } + + static void dv1394_add_host (struct hpsb_host *host) diff --git a/queue-2.6.20/ipv6-fix-ipv6-round-robin-locking.patch b/queue-2.6.20/ipv6-fix-ipv6-round-robin-locking.patch new file mode 100644 index 00000000000..38475747036 --- /dev/null +++ b/queue-2.6.20/ipv6-fix-ipv6-round-robin-locking.patch @@ -0,0 +1,232 @@ +From stable-bounces@linux.kernel.org Mon Mar 26 18:58:25 2007 +From: David Miller +Date: Mon, 26 Mar 2007 18:56:59 -0700 (PDT) +Subject: IPV6: Fix ipv6 round-robin locking. +To: stable@kernel.org +Cc: bunk@stusta.de +Message-ID: <20070326.185659.08322864.davem@davemloft.net> + +From: David Miller + +[IPV6]: Fix routing round-robin locking. + +As per RFC2461, section 6.3.6, item #2, when no routers on the +matching list are known to be reachable or probably reachable we +do round robin on those available routes so that we make sure +to probe as many of them as possible to detect when one becomes +reachable faster. + +Each routing table has a rwlock protecting the tree and the linked +list of routes at each leaf. The round robin code executes during +lookup and thus with the rwlock taken as a reader. A small local +spinlock tries to provide protection but this does not work at all +for two reasons: + +1) The round-robin list manipulation, as coded, goes like this (with + read lock held): + + walk routes finding head and tail + + spin_lock(); + rotate list using head and tail + spin_unlock(); + + While one thread is rotating the list, another thread can + end up with stale values of head and tail and then proceed + to corrupt the list when it gets the lock. This ends up causing + the OOPS in fib6_add() later onthat many people have been hitting. + +2) All the other code paths that run with the rwlock held as + a reader do not expect the list to change on them, they + expect it to remain completely fixed while they hold the + lock in that way. + +So, simply stated, it is impossible to implement this correctly using +a manipulation of the list without violating the rwlock locking +semantics. + +Reimplement using a per-fib6_node round-robin pointer. This way we +don't need to manipulate the list at all, and since the round-robin +pointer can only ever point to real existing entries we don't need +to perform any locking on the changing of the round-robin pointer +itself. We only need to reset the round-robin pointer to NULL when +the entry it is pointing to is removed. + +The idea is from Thomas Graf and it is very similar to how this +was implemented before the advanced router selection code when in. + +Signed-off-by: David S. Miller + +--- + include/net/ip6_fib.h | 1 + net/ipv6/ip6_fib.c | 8 ++++ + net/ipv6/route.c | 97 ++++++++++++++++++++++++++++++-------------------- + 3 files changed, 68 insertions(+), 38 deletions(-) + +--- a/include/net/ip6_fib.h ++++ b/include/net/ip6_fib.h +@@ -58,6 +58,7 @@ struct fib6_node + __u16 fn_bit; /* bit key */ + __u16 fn_flags; + __u32 fn_sernum; ++ struct rt6_info *rr_ptr; + }; + + #ifndef CONFIG_IPV6_SUBTREES +--- a/net/ipv6/ip6_fib.c ++++ b/net/ipv6/ip6_fib.c +@@ -659,6 +659,10 @@ static int fib6_add_rt2node(struct fib6_ + ins = &iter->u.next; + } + ++ /* Reset round-robin state, if necessary */ ++ if (ins == &fn->leaf) ++ fn->rr_ptr = NULL; ++ + /* + * insert node + */ +@@ -1110,6 +1114,10 @@ static void fib6_del_route(struct fib6_n + rt6_stats.fib_rt_entries--; + rt6_stats.fib_discarded_routes++; + ++ /* Reset round-robin state, if necessary */ ++ if (fn->rr_ptr == rt) ++ fn->rr_ptr = NULL; ++ + /* Adjust walkers */ + read_lock(&fib6_walker_lock); + FOR_WALKERS(w) { +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -354,55 +354,76 @@ static int rt6_score_route(struct rt6_in + return m; + } + +-static struct rt6_info *rt6_select(struct rt6_info **head, int oif, +- int strict) ++static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, ++ int *mpri, struct rt6_info *match) + { +- struct rt6_info *match = NULL, *last = NULL; +- struct rt6_info *rt, *rt0 = *head; +- u32 metric; ++ int m; ++ ++ if (rt6_check_expired(rt)) ++ goto out; ++ ++ m = rt6_score_route(rt, oif, strict); ++ if (m < 0) ++ goto out; ++ ++ if (m > *mpri) { ++ if (strict & RT6_LOOKUP_F_REACHABLE) ++ rt6_probe(match); ++ *mpri = m; ++ match = rt; ++ } else if (strict & RT6_LOOKUP_F_REACHABLE) { ++ rt6_probe(rt); ++ } ++ ++out: ++ return match; ++} ++ ++static struct rt6_info *find_rr_leaf(struct fib6_node *fn, ++ struct rt6_info *rr_head, ++ u32 metric, int oif, int strict) ++{ ++ struct rt6_info *rt, *match; + int mpri = -1; + +- RT6_TRACE("%s(head=%p(*head=%p), oif=%d)\n", +- __FUNCTION__, head, head ? *head : NULL, oif); ++ match = NULL; ++ for (rt = rr_head; rt && rt->rt6i_metric == metric; ++ rt = rt->u.next) ++ match = find_match(rt, oif, strict, &mpri, match); ++ for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric; ++ rt = rt->u.next) ++ match = find_match(rt, oif, strict, &mpri, match); + +- for (rt = rt0, metric = rt0->rt6i_metric; +- rt && rt->rt6i_metric == metric && (!last || rt != rt0); +- rt = rt->u.next) { +- int m; ++ return match; ++} + +- if (rt6_check_expired(rt)) +- continue; ++static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) ++{ ++ struct rt6_info *match, *rt0; + +- last = rt; ++ RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n", ++ __FUNCTION__, fn->leaf, oif); + +- m = rt6_score_route(rt, oif, strict); +- if (m < 0) +- continue; ++ rt0 = fn->rr_ptr; ++ if (!rt0) ++ fn->rr_ptr = rt0 = fn->leaf; + +- if (m > mpri) { +- if (strict & RT6_LOOKUP_F_REACHABLE) +- rt6_probe(match); +- match = rt; +- mpri = m; +- } else if (strict & RT6_LOOKUP_F_REACHABLE) { +- rt6_probe(rt); +- } +- } ++ match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict); + + if (!match && +- (strict & RT6_LOOKUP_F_REACHABLE) && +- last && last != rt0) { ++ (strict & RT6_LOOKUP_F_REACHABLE)) { ++ struct rt6_info *next = rt0->u.next; ++ + /* no entries matched; do round-robin */ +- static DEFINE_SPINLOCK(lock); +- spin_lock(&lock); +- *head = rt0->u.next; +- rt0->u.next = last->u.next; +- last->u.next = rt0; +- spin_unlock(&lock); ++ if (!next || next->rt6i_metric != rt0->rt6i_metric) ++ next = fn->leaf; ++ ++ if (next != rt0) ++ fn->rr_ptr = next; + } + +- RT6_TRACE("%s() => %p, score=%d\n", +- __FUNCTION__, match, mpri); ++ RT6_TRACE("%s() => %p\n", ++ __FUNCTION__, match); + + return (match ? match : &ip6_null_entry); + } +@@ -648,7 +669,7 @@ restart_2: + fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); + + restart: +- rt = rt6_select(&fn->leaf, fl->iif, strict | reachable); ++ rt = rt6_select(fn, fl->iif, strict | reachable); + BACKTRACK(&fl->fl6_src); + if (rt == &ip6_null_entry || + rt->rt6i_flags & RTF_CACHE) +@@ -743,7 +764,7 @@ restart_2: + fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); + + restart: +- rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); ++ rt = rt6_select(fn, fl->oif, strict | reachable); + BACKTRACK(&fl->fl6_src); + if (rt == &ip6_null_entry || + rt->rt6i_flags & RTF_CACHE) diff --git a/queue-2.6.20/net-fix-fib-rules-compatability.patch b/queue-2.6.20/net-fix-fib-rules-compatability.patch new file mode 100644 index 00000000000..182ebe9a6c5 --- /dev/null +++ b/queue-2.6.20/net-fix-fib-rules-compatability.patch @@ -0,0 +1,271 @@ +From stable-bounces@linux.kernel.org Thu Mar 29 12:35:35 2007 +From: Thomas Graf +Date: Thu, 29 Mar 2007 12:34:13 -0700 (PDT) +Subject: NET: Fix FIB rules compatability +To: stable@kernel.org +Cc: bunk@stusta.de +Message-ID: <20070329.123413.31642189.davem@davemloft.net> + + +From: Thomas Graf + +[NET]: Fix fib_rules compatibility breakage + +Based upon a patch from Patrick McHardy. + +The fib_rules netlink attribute policy introduced in 2.6.19 broke +userspace compatibilty. When specifying a rule with "from all" +or "to all", iproute adds a zero byte long netlink attribute, +but the policy requires all addresses to have a size equal to +sizeof(struct in_addr)/sizeof(struct in6_addr), resulting in a +validation error. + +Check attribute length of FRA_SRC/FRA_DST in the generic framework +by letting the family specific rules implementation provide the +length of an address. Report an error if address length is non +zero but no address attribute is provided. Fix actual bug by +checking address length for non-zero instead of relying on +availability of attribute. + +Signed-off-by: Thomas Graf +Signed-off-by: Patrick McHardy +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + include/net/fib_rules.h | 1 + + net/core/fib_rules.c | 30 ++++++++++++++++++++++++++++++ + net/decnet/dn_rules.c | 13 ++++++------- + net/ipv4/fib_rules.c | 14 ++++++-------- + net/ipv6/fib6_rules.c | 14 +++++--------- + 5 files changed, 48 insertions(+), 24 deletions(-) + +--- a/include/net/fib_rules.h ++++ b/include/net/fib_rules.h +@@ -34,6 +34,7 @@ struct fib_rules_ops + int family; + struct list_head list; + int rule_size; ++ int addr_size; + + int (*action)(struct fib_rule *, + struct flowi *, int, +--- a/net/core/fib_rules.c ++++ b/net/core/fib_rules.c +@@ -152,6 +152,28 @@ out: + + EXPORT_SYMBOL_GPL(fib_rules_lookup); + ++static int validate_rulemsg(struct fib_rule_hdr *frh, struct nlattr **tb, ++ struct fib_rules_ops *ops) ++{ ++ int err = -EINVAL; ++ ++ if (frh->src_len) ++ if (tb[FRA_SRC] == NULL || ++ frh->src_len > (ops->addr_size * 8) || ++ nla_len(tb[FRA_SRC]) != ops->addr_size) ++ goto errout; ++ ++ if (frh->dst_len) ++ if (tb[FRA_DST] == NULL || ++ frh->dst_len > (ops->addr_size * 8) || ++ nla_len(tb[FRA_DST]) != ops->addr_size) ++ goto errout; ++ ++ err = 0; ++errout: ++ return err; ++} ++ + int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) + { + struct fib_rule_hdr *frh = nlmsg_data(nlh); +@@ -173,6 +195,10 @@ int fib_nl_newrule(struct sk_buff *skb, + if (err < 0) + goto errout; + ++ err = validate_rulemsg(frh, tb, ops); ++ if (err < 0) ++ goto errout; ++ + rule = kzalloc(ops->rule_size, GFP_KERNEL); + if (rule == NULL) { + err = -ENOMEM; +@@ -260,6 +286,10 @@ int fib_nl_delrule(struct sk_buff *skb, + if (err < 0) + goto errout; + ++ err = validate_rulemsg(frh, tb, ops); ++ if (err < 0) ++ goto errout; ++ + list_for_each_entry(rule, ops->rules_list, list) { + if (frh->action && (frh->action != rule->action)) + continue; +--- a/net/decnet/dn_rules.c ++++ b/net/decnet/dn_rules.c +@@ -109,8 +109,6 @@ errout: + + static struct nla_policy dn_fib_rule_policy[FRA_MAX+1] __read_mostly = { + FRA_GENERIC_POLICY, +- [FRA_SRC] = { .type = NLA_U16 }, +- [FRA_DST] = { .type = NLA_U16 }, + }; + + static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) +@@ -133,7 +131,7 @@ static int dn_fib_rule_configure(struct + int err = -EINVAL; + struct dn_fib_rule *r = (struct dn_fib_rule *)rule; + +- if (frh->src_len > 16 || frh->dst_len > 16 || frh->tos) ++ if (frh->tos) + goto errout; + + if (rule->table == RT_TABLE_UNSPEC) { +@@ -150,10 +148,10 @@ static int dn_fib_rule_configure(struct + } + } + +- if (tb[FRA_SRC]) ++ if (frh->src_len) + r->src = nla_get_le16(tb[FRA_SRC]); + +- if (tb[FRA_DST]) ++ if (frh->dst_len) + r->dst = nla_get_le16(tb[FRA_DST]); + + r->src_len = frh->src_len; +@@ -176,10 +174,10 @@ static int dn_fib_rule_compare(struct fi + if (frh->dst_len && (r->dst_len != frh->dst_len)) + return 0; + +- if (tb[FRA_SRC] && (r->src != nla_get_le16(tb[FRA_SRC]))) ++ if (frh->src_len && (r->src != nla_get_le16(tb[FRA_SRC]))) + return 0; + +- if (tb[FRA_DST] && (r->dst != nla_get_le16(tb[FRA_DST]))) ++ if (frh->dst_len && (r->dst != nla_get_le16(tb[FRA_DST]))) + return 0; + + return 1; +@@ -249,6 +247,7 @@ int dn_fib_dump_rules(struct sk_buff *sk + static struct fib_rules_ops dn_fib_rules_ops = { + .family = AF_DECnet, + .rule_size = sizeof(struct dn_fib_rule), ++ .addr_size = sizeof(u16), + .action = dn_fib_rule_action, + .match = dn_fib_rule_match, + .configure = dn_fib_rule_configure, +--- a/net/ipv4/fib_rules.c ++++ b/net/ipv4/fib_rules.c +@@ -171,8 +171,6 @@ static struct fib_table *fib_empty_table + + static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = { + FRA_GENERIC_POLICY, +- [FRA_SRC] = { .type = NLA_U32 }, +- [FRA_DST] = { .type = NLA_U32 }, + [FRA_FLOW] = { .type = NLA_U32 }, + }; + +@@ -183,8 +181,7 @@ static int fib4_rule_configure(struct fi + int err = -EINVAL; + struct fib4_rule *rule4 = (struct fib4_rule *) rule; + +- if (frh->src_len > 32 || frh->dst_len > 32 || +- (frh->tos & ~IPTOS_TOS_MASK)) ++ if (frh->tos & ~IPTOS_TOS_MASK) + goto errout; + + if (rule->table == RT_TABLE_UNSPEC) { +@@ -201,10 +198,10 @@ static int fib4_rule_configure(struct fi + } + } + +- if (tb[FRA_SRC]) ++ if (frh->src_len) + rule4->src = nla_get_be32(tb[FRA_SRC]); + +- if (tb[FRA_DST]) ++ if (frh->dst_len) + rule4->dst = nla_get_be32(tb[FRA_DST]); + + #ifdef CONFIG_NET_CLS_ROUTE +@@ -242,10 +239,10 @@ static int fib4_rule_compare(struct fib_ + return 0; + #endif + +- if (tb[FRA_SRC] && (rule4->src != nla_get_be32(tb[FRA_SRC]))) ++ if (frh->src_len && (rule4->src != nla_get_be32(tb[FRA_SRC]))) + return 0; + +- if (tb[FRA_DST] && (rule4->dst != nla_get_be32(tb[FRA_DST]))) ++ if (frh->dst_len && (rule4->dst != nla_get_be32(tb[FRA_DST]))) + return 0; + + return 1; +@@ -309,6 +306,7 @@ static size_t fib4_rule_nlmsg_payload(st + static struct fib_rules_ops fib4_rules_ops = { + .family = AF_INET, + .rule_size = sizeof(struct fib4_rule), ++ .addr_size = sizeof(u32), + .action = fib4_rule_action, + .match = fib4_rule_match, + .configure = fib4_rule_configure, +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -131,8 +131,6 @@ static int fib6_rule_match(struct fib_ru + + static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = { + FRA_GENERIC_POLICY, +- [FRA_SRC] = { .len = sizeof(struct in6_addr) }, +- [FRA_DST] = { .len = sizeof(struct in6_addr) }, + }; + + static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, +@@ -142,9 +140,6 @@ static int fib6_rule_configure(struct fi + int err = -EINVAL; + struct fib6_rule *rule6 = (struct fib6_rule *) rule; + +- if (frh->src_len > 128 || frh->dst_len > 128) +- goto errout; +- + if (rule->action == FR_ACT_TO_TBL) { + if (rule->table == RT6_TABLE_UNSPEC) + goto errout; +@@ -155,11 +150,11 @@ static int fib6_rule_configure(struct fi + } + } + +- if (tb[FRA_SRC]) ++ if (frh->src_len) + nla_memcpy(&rule6->src.addr, tb[FRA_SRC], + sizeof(struct in6_addr)); + +- if (tb[FRA_DST]) ++ if (frh->dst_len) + nla_memcpy(&rule6->dst.addr, tb[FRA_DST], + sizeof(struct in6_addr)); + +@@ -186,11 +181,11 @@ static int fib6_rule_compare(struct fib_ + if (frh->tos && (rule6->tclass != frh->tos)) + return 0; + +- if (tb[FRA_SRC] && ++ if (frh->src_len && + nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr))) + return 0; + +- if (tb[FRA_DST] && ++ if (frh->dst_len && + nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr))) + return 0; + +@@ -240,6 +235,7 @@ static size_t fib6_rule_nlmsg_payload(st + static struct fib_rules_ops fib6_rules_ops = { + .family = AF_INET6, + .rule_size = sizeof(struct fib6_rule), ++ .addr_size = sizeof(struct in6_addr), + .action = fib6_rule_action, + .match = fib6_rule_match, + .configure = fib6_rule_configure, diff --git a/queue-2.6.20/net-fix-packet-classidier-null-pointer-oops.patch b/queue-2.6.20/net-fix-packet-classidier-null-pointer-oops.patch new file mode 100644 index 00000000000..a87a910bd77 --- /dev/null +++ b/queue-2.6.20/net-fix-packet-classidier-null-pointer-oops.patch @@ -0,0 +1,59 @@ +From stable-bounces@linux.kernel.org Mon Mar 26 18:15:09 2007 +From: Patrick McHardy +Date: Mon, 26 Mar 2007 18:13:51 -0700 (PDT) +Subject: NET: Fix packet classidier NULL pointer OOPS +To: stable@kernel.org +Cc: bunk@stusta.de +Message-ID: <20070326.181351.72710253.davem@davemloft.net> + +From: Patrick McHardy + +[NET_SCHED]: cls_basic: fix NULL pointer dereference + +cls_basic doesn't allocate tp->root before it is linked into the +active classifier list, resulting in a NULL pointer dereference +when packets hit the classifier before its ->change function is +called. + +Reported by Chris Madden + +Signed-off-by: Patrick McHardy +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/sched/cls_basic.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +--- a/net/sched/cls_basic.c ++++ b/net/sched/cls_basic.c +@@ -82,6 +82,13 @@ static void basic_put(struct tcf_proto * + + static int basic_init(struct tcf_proto *tp) + { ++ struct basic_head *head; ++ ++ head = kzalloc(sizeof(*head), GFP_KERNEL); ++ if (head == NULL) ++ return -ENOBUFS; ++ INIT_LIST_HEAD(&head->flist); ++ tp->root = head; + return 0; + } + +@@ -177,15 +184,6 @@ static int basic_change(struct tcf_proto + } + + err = -ENOBUFS; +- if (head == NULL) { +- head = kzalloc(sizeof(*head), GFP_KERNEL); +- if (head == NULL) +- goto errout; +- +- INIT_LIST_HEAD(&head->flist); +- tp->root = head; +- } +- + f = kzalloc(sizeof(*f), GFP_KERNEL); + if (f == NULL) + goto errout; diff --git a/queue-2.6.20/net-fix-sock_attach_fd-failure-in-sys_accept.patch b/queue-2.6.20/net-fix-sock_attach_fd-failure-in-sys_accept.patch new file mode 100644 index 00000000000..25999b3be2f --- /dev/null +++ b/queue-2.6.20/net-fix-sock_attach_fd-failure-in-sys_accept.patch @@ -0,0 +1,48 @@ +From stable-bounces@linux.kernel.org Thu Mar 29 12:24:08 2007 +From: Alexey Dobriyan +Date: Thu, 29 Mar 2007 12:22:40 -0700 (PDT) +Subject: NET: Fix sock_attach_fd() failure in sys_accept() +To: stable@kernel.org +Cc: bunk@stusta.de +Message-ID: <20070329.122240.08322946.davem@davemloft.net> + + +From: Alexey Dobriyan + +[NET]: Correct accept(2) recovery after sock_attach_fd() + +* d_alloc() in sock_attach_fd() fails leaving ->f_dentry of new file NULL +* bail out to out_fd label, doing fput()/__fput() on new file +* but __fput() assumes valid ->f_dentry and dereferences it + +Signed-off-by: Alexey Dobriyan +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/socket.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/net/socket.c ++++ b/net/socket.c +@@ -1368,7 +1368,7 @@ asmlinkage long sys_accept(int fd, struc + + err = sock_attach_fd(newsock, newfile); + if (err < 0) +- goto out_fd; ++ goto out_fd_simple; + + err = security_socket_accept(sock, newsock); + if (err) +@@ -1401,6 +1401,11 @@ out_put: + fput_light(sock->file, fput_needed); + out: + return err; ++out_fd_simple: ++ sock_release(newsock); ++ put_filp(newfile); ++ put_unused_fd(newfd); ++ goto out_put; + out_fd: + fput(newfile); + put_unused_fd(newfd); diff --git a/queue-2.6.20/net_sched-fix-ingress-qdisc-locking.patch b/queue-2.6.20/net_sched-fix-ingress-qdisc-locking.patch new file mode 100644 index 00000000000..eced975047a --- /dev/null +++ b/queue-2.6.20/net_sched-fix-ingress-qdisc-locking.patch @@ -0,0 +1,38 @@ +From stable-bounces@linux.kernel.org Mon Mar 26 18:16:55 2007 +From: Patrick McHardy +Date: Mon, 26 Mar 2007 18:15:37 -0700 (PDT) +Subject: NET_SCHED: Fix ingress qdisc locking. +To: stable@kernel.org +Cc: bunk@stusta.de +Message-ID: <20070326.181537.59655672.davem@davemloft.net> + +From: Patrick McHardy + +[NET_SCHED]: Fix ingress locking + +Ingress queueing uses a seperate lock for serializing enqueue operations, +but fails to properly protect itself against concurrent changes to the +qdisc tree. Use queue_lock for now since the real fix it quite intrusive. + +Signed-off-by: Patrick McHardy +Signed-off-by: David S. Miller + +--- + net/core/dev.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -1750,10 +1750,10 @@ static int ing_filter(struct sk_buff *sk + + skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS); + +- spin_lock(&dev->ingress_lock); ++ spin_lock(&dev->queue_lock); + if ((q = dev->qdisc_ingress) != NULL) + result = q->enqueue(skb, q); +- spin_unlock(&dev->ingress_lock); ++ spin_unlock(&dev->queue_lock); + + } + diff --git a/queue-2.6.20/ppp-fix-ppp-skb-leak.patch b/queue-2.6.20/ppp-fix-ppp-skb-leak.patch new file mode 100644 index 00000000000..83d8452e282 --- /dev/null +++ b/queue-2.6.20/ppp-fix-ppp-skb-leak.patch @@ -0,0 +1,33 @@ +From stable-bounces@linux.kernel.org Mon Mar 26 19:08:55 2007 +From: G. Liakhovetski +Date: Mon, 26 Mar 2007 19:07:40 -0700 (PDT) +Subject: PPP: Fix PPP skb leak +To: stable@kernel.org +Cc: bunk@stusta.de +Message-ID: <20070326.190740.21927260.davem@davemloft.net> + +From: G. Liakhovetski + +[PPP]: Don't leak an sk_buff on interface destruction. + +Signed-off-by: G. Liakhovetski +Acked-by: Paul Mackerras +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/ppp_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/ppp_generic.c ++++ b/drivers/net/ppp_generic.c +@@ -2544,6 +2544,9 @@ static void ppp_destroy_interface(struct + ppp->active_filter = NULL; + #endif /* CONFIG_PPP_FILTER */ + ++ if (ppp->xmit_pending) ++ kfree_skb(ppp->xmit_pending); ++ + kfree(ppp); + } + diff --git a/queue-2.6.20/sata_nv-delay-on-switching-between-ncq-and-non-ncq-commands.patch b/queue-2.6.20/sata_nv-delay-on-switching-between-ncq-and-non-ncq-commands.patch new file mode 100644 index 00000000000..99dc59f0b5c --- /dev/null +++ b/queue-2.6.20/sata_nv-delay-on-switching-between-ncq-and-non-ncq-commands.patch @@ -0,0 +1,63 @@ +From stable-bounces@linux.kernel.org Thu Mar 22 09:47:58 2007 +Date: Thu, 22 Mar 2007 12:39:04 -0400 +Cc: Robert Hancock +Subject: sata_nv: delay on switching between NCQ and non-NCQ commands +To: linux-stable +Cc: Robert Hancock +Message-ID: <4602B128.6090000@redhat.com> + + +From: Robert Hancock + +sata_nv: delay on switching between NCQ and non-NCQ commands + +This patch appears to solve some problems with commands timing out in +cases where an NCQ command is immediately followed by a non-NCQ command +(or possibly vice versa). This is a rather ugly solution, but until we +know more about why this is needed, this is about all we can do. + +[backport to 2.6.20 by Chuck Ebbert ] + +Signed-off-by: Robert Hancock +Cc: Chuck Ebbert +Signed-off-by: Jeff Garzik +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/ata/sata_nv.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/ata/sata_nv.c ++++ b/drivers/ata/sata_nv.c +@@ -214,6 +214,7 @@ struct nv_adma_port_priv { + struct nv_adma_prd *aprd; + dma_addr_t aprd_dma; + u8 flags; ++ int last_issue_ncq; + }; + + #define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT))))) +@@ -1151,6 +1152,7 @@ static unsigned int nv_adma_qc_issue(str + { + struct nv_adma_port_priv *pp = qc->ap->private_data; + void __iomem *mmio = nv_adma_ctl_block(qc->ap); ++ int curr_ncq = (qc->tf.protocol == ATA_PROT_NCQ); + + VPRINTK("ENTER\n"); + +@@ -1166,6 +1168,14 @@ static unsigned int nv_adma_qc_issue(str + /* write append register, command tag in lower 8 bits + and (number of cpbs to append -1) in top 8 bits */ + wmb(); ++ ++ if(curr_ncq != pp->last_issue_ncq) { ++ /* Seems to need some delay before switching between NCQ and non-NCQ ++ commands, else we get command timeouts and such. */ ++ udelay(20); ++ pp->last_issue_ncq = curr_ncq; ++ } ++ + writew(qc->tag, mmio + NV_ADMA_APPEND); + + DPRINTK("Issued tag %u\n",qc->tag); diff --git a/queue-2.6.20/series b/queue-2.6.20/series new file mode 100644 index 00000000000..eb1398c4a57 --- /dev/null +++ b/queue-2.6.20/series @@ -0,0 +1,19 @@ +ide-clear-bmdma-status-in-ide_intr-for-ichx-controllers.patch +ide-remove-clearing-bmdma-status-from-cdrom_decode_status.patch +sata_nv-delay-on-switching-between-ncq-and-non-ncq-commands.patch +uml-fix-epoll.patch +uml-host-vdso-fix.patch +uml-fix-static-linking.patch +uml-use-correct-register-file-size-everywhere.patch +uml-fix-unreasonably-long-udelay.patch +ieee1394-dv1394-fix-cardbus-card-ejection.patch +net-fix-packet-classidier-null-pointer-oops.patch +net_sched-fix-ingress-qdisc-locking.patch +ipv6-fix-ipv6-round-robin-locking.patch +ppp-fix-ppp-skb-leak.patch +dccp-fix-exploitable-hole-in-dccp-socket-options.patch +video-fix-ffb-dac-revision-probing.patch +net-fix-sock_attach_fd-failure-in-sys_accept.patch +sparc-fix-sparc-builds-with-gcc-4.2.x.patch +fix-decnet-endianness.patch +net-fix-fib-rules-compatability.patch diff --git a/queue-2.6.20/sparc-fix-sparc-builds-with-gcc-4.2.x.patch b/queue-2.6.20/sparc-fix-sparc-builds-with-gcc-4.2.x.patch new file mode 100644 index 00000000000..362ce321512 --- /dev/null +++ b/queue-2.6.20/sparc-fix-sparc-builds-with-gcc-4.2.x.patch @@ -0,0 +1,59 @@ +From stable-bounces@linux.kernel.org Thu Mar 29 12:27:04 2007 +From: Mikael Pettersson +Date: Thu, 29 Mar 2007 12:25:38 -0700 (PDT) +Subject: SPARC: Fix sparc builds with gcc-4.2.x +To: stable@kernel.org +Cc: bunk@stusta.de +Message-ID: <20070329.122538.21928111.davem@davemloft.net> + +From: Mikael Pettersson + +[SPARC]: sparc64 gcc-4.2.0 20070317 -Werror failure + +Compiling 2.6.21-rc5 with gcc-4.2.0 20070317 (prerelease) +for sparc64 fails as follows: + + gcc -Wp,-MD,arch/sparc64/kernel/.time.o.d -nostdinc -isystem /home/mikpe/pkgs/linux-sparc64/gcc-4.2.0/lib/gcc/sparc64-unknown-linux-gnu/4.2.0/include -D__KERNEL__ -Iinclude -include include/linux/autoconf.h -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Os -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare -Wa,--undeclared-regs -fomit-frame-pointer -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -Werror -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(time)" -D"KBUILD_MODNAME=KBUILD_STR(time)" -c -o arch/sparc64/kernel/time.o arch/sparc64/kernel/time.c +cc1: warnings being treated as errors +arch/sparc64/kernel/time.c: In function 'kick_start_clock': +arch/sparc64/kernel/time.c:559: warning: overflow in implicit constant conversion +make[1]: *** [arch/sparc64/kernel/time.o] Error 1 +make: *** [arch/sparc64/kernel] Error 2 + +gcc gets unhappy when the MSTK_SET macro's u8 __val variable +is updated with &= ~0xff (MSTK_YEAR_MASK). Making the constant +unsigned fixes the problem. + +[ I fixed up the sparc32 side as well -DaveM ] + +Signed-off-by: Mikael Pettersson +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + include/asm-sparc/mostek.h | 2 +- + include/asm-sparc64/mostek.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/include/asm-sparc/mostek.h ++++ b/include/asm-sparc/mostek.h +@@ -87,7 +87,7 @@ extern void __iomem *mstk48t02_regs; + #define MSTK_DOW_MASK 0x07 + #define MSTK_DOM_MASK 0x3f + #define MSTK_MONTH_MASK 0x1f +-#define MSTK_YEAR_MASK 0xff ++#define MSTK_YEAR_MASK 0xffU + + /* Binary coded decimal conversion macros. */ + #define MSTK_REGVAL_TO_DECIMAL(x) (((x) & 0x0F) + 0x0A * ((x) >> 0x04)) +--- a/include/asm-sparc64/mostek.h ++++ b/include/asm-sparc64/mostek.h +@@ -89,7 +89,7 @@ extern void __iomem *mstk48t02_regs; + #define MSTK_DOW_MASK 0x07 + #define MSTK_DOM_MASK 0x3f + #define MSTK_MONTH_MASK 0x1f +-#define MSTK_YEAR_MASK 0xff ++#define MSTK_YEAR_MASK 0xffU + + /* Binary coded decimal conversion macros. */ + #define MSTK_REGVAL_TO_DECIMAL(x) (((x) & 0x0F) + 0x0A * ((x) >> 0x04)) diff --git a/queue-2.6.20/uml-fix-epoll.patch b/queue-2.6.20/uml-fix-epoll.patch new file mode 100644 index 00000000000..d698689c00b --- /dev/null +++ b/queue-2.6.20/uml-fix-epoll.patch @@ -0,0 +1,42 @@ +From stable-bounces@linux.kernel.org Fri Mar 23 11:22:17 2007 +From: Jeff Dike +Date: Fri, 23 Mar 2007 14:18:17 -0400 +Subject: UML - fix epoll +To: Andrew Morton , stable@kernel.org +Cc: uml-devel +Message-ID: <20070323181817.GA8694@c2.user-mode-linux.org> +Content-Disposition: inline + +From: Jeff Dike + +UML/x86_64 needs the same packing of struct epoll_event as x86_64. + +Signed-off-by: Jeff Dike +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/eventpoll.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/include/linux/eventpoll.h ++++ b/include/linux/eventpoll.h +@@ -31,12 +31,19 @@ + /* + * On x86-64 make the 64bit structure have the same alignment as the + * 32bit structure. This makes 32bit emulation easier. ++ * ++ * UML/x86_64 needs the same packing as x86_64 - UML + UML_X86 + ++ * 64_BIT adds up to UML/x86_64. + */ + #ifdef __x86_64__ + #define EPOLL_PACKED __attribute__((packed)) + #else ++#if defined(CONFIG_UML) && defined(CONFIG_UML_X86) && defined(CONFIG_64BIT) ++#define EPOLL_PACKED __attribute__((packed)) ++#else + #define EPOLL_PACKED + #endif ++#endif + + struct epoll_event { + __u32 events; diff --git a/queue-2.6.20/uml-fix-static-linking.patch b/queue-2.6.20/uml-fix-static-linking.patch new file mode 100644 index 00000000000..f02b4736c22 --- /dev/null +++ b/queue-2.6.20/uml-fix-static-linking.patch @@ -0,0 +1,35 @@ +From stable-bounces@linux.kernel.org Sun Mar 25 09:58:58 2007 +From: Jeff Dike +Date: Sun, 25 Mar 2007 12:54:32 -0400 +Subject: UML - Fix static linking +To: Andrew Morton , stable@kernel.org +Cc: , uml-devel +Message-ID: <20070325165432.GA6232@c2.user-mode-linux.org> +Content-Disposition: inline + +From: Jeff Dike + +During a static link, ld has started putting a .note section in the +.uml.setup.init section. This has the result that the UML setups +begin with 32 bytes of garbage and UML crashes immediately on boot. + +This patch creates a specific .note section for ld to drop this stuff +into. + +Signed-off-by: Jeff Dike +Signed-off-by: Greg Kroah-Hartman + +--- + include/asm-um/common.lds.S | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/asm-um/common.lds.S ++++ b/include/asm-um/common.lds.S +@@ -15,6 +15,7 @@ + PROVIDE (_unprotected_end = .); + + . = ALIGN(4096); ++ .note : { *(note.*) } + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; diff --git a/queue-2.6.20/uml-fix-unreasonably-long-udelay.patch b/queue-2.6.20/uml-fix-unreasonably-long-udelay.patch new file mode 100644 index 00000000000..7b1b8071f11 --- /dev/null +++ b/queue-2.6.20/uml-fix-unreasonably-long-udelay.patch @@ -0,0 +1,92 @@ +From stable-bounces@linux.kernel.org Wed Mar 28 16:28:40 2007 +From: "Paolo 'Blaisorblade' Giarrusso" +Date: Thu, 29 Mar 2007 01:26:11 +0200 +Subject: uml: fix unreasonably long udelay +To: Andrew Morton , stable@kernel.org +Cc: Jeff Dike +Message-ID: <20070328232558.28719.96929.stgit@americanbeauty.home.lan> + +From: "Paolo 'Blaisorblade' Giarrusso" + +Currently we have a confused udelay implementation. + +* __const_udelay does not accept usecs but xloops in i386 and x86_64 +* our implementation requires usecs as arg +* it gets a xloops count when called by asm/arch/delay.h + +Bugs related to this (extremely long shutdown times) where reported by some +x86_64 users, especially using Device Mapper. + +To hit this bug, a compile-time constant time parameter must be passed - that's +why UML seems to work most times. +Fix this with a simple udelay implementation. + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Signed-off-by: Greg Kroah-Hartman + +--- + arch/um/sys-i386/delay.c | 11 ----------- + arch/um/sys-x86_64/delay.c | 11 ----------- + include/asm-um/delay.h | 17 ++++++++++++++--- + 3 files changed, 14 insertions(+), 25 deletions(-) + +--- a/arch/um/sys-i386/delay.c ++++ b/arch/um/sys-i386/delay.c +@@ -27,14 +27,3 @@ void __udelay(unsigned long usecs) + } + + EXPORT_SYMBOL(__udelay); +- +-void __const_udelay(unsigned long usecs) +-{ +- int i, n; +- +- n = (loops_per_jiffy * HZ * usecs) / MILLION; +- for(i=0;i 20000) ? \ ++ __bad_udelay() : __udelay(n)) ++ ++/* It appears that ndelay is not used at all for UML, and has never been ++ * implemented. */ ++extern void __unimplemented_ndelay(void); ++#define ndelay(n) __unimplemented_ndelay() ++ + #endif diff --git a/queue-2.6.20/uml-host-vdso-fix.patch b/queue-2.6.20/uml-host-vdso-fix.patch new file mode 100644 index 00000000000..fa79f4f6396 --- /dev/null +++ b/queue-2.6.20/uml-host-vdso-fix.patch @@ -0,0 +1,43 @@ +From stable-bounces@linux.kernel.org Fri Mar 23 12:41:21 2007 +From: Jeff Dike +Date: Fri, 23 Mar 2007 15:37:30 -0400 +Subject: UML - host VDSO fix +To: stable@kernel.org +Cc: uml-devel +Message-ID: <20070323193730.GA9519@c2.user-mode-linux.org> +Content-Disposition: inline + +From: Jeff Dike + +This fixes a problem seen by a number of people running UML on newer host +kernels. init would hang with an infinite segfault loop. + +It turns out that the host kernel was providing a AT_SYSINFO_EHDR of +0xffffe000, which faked UML into believing that the host VDSO page could be +reused. However, AT_SYSINFO pointed into the middle of the address space, and +was unmapped as a result. Because UML was providing AT_SYSINFO_EHDR and +AT_SYSINFO to its own processes, these would branch to nowhere when trying to +use the VDSO. + +The fix is to also check the location of AT_SYSINFO when deciding whether to +use the host's VDSO. + +Signed-off-by: Jeff Dike +Signed-off-by: Greg Kroah-Hartman + +--- + arch/um/os-Linux/elf_aux.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/arch/um/os-Linux/elf_aux.c ++++ b/arch/um/os-Linux/elf_aux.c +@@ -40,6 +40,9 @@ __init void scan_elf_aux( char **envp) + switch ( auxv->a_type ) { + case AT_SYSINFO: + __kernel_vsyscall = auxv->a_un.a_val; ++ /* See if the page is under TASK_SIZE */ ++ if (__kernel_vsyscall < (unsigned long) envp) ++ __kernel_vsyscall = 0; + break; + case AT_SYSINFO_EHDR: + vsyscall_ehdr = auxv->a_un.a_val; diff --git a/queue-2.6.20/uml-use-correct-register-file-size-everywhere.patch b/queue-2.6.20/uml-use-correct-register-file-size-everywhere.patch new file mode 100644 index 00000000000..0983b0a23c0 --- /dev/null +++ b/queue-2.6.20/uml-use-correct-register-file-size-everywhere.patch @@ -0,0 +1,150 @@ +From stable-bounces@linux.kernel.org Sun Mar 25 10:06:00 2007 +From: Jeff Dike +Date: Sun, 25 Mar 2007 13:01:44 -0400 +Subject: UML - use correct register file size everywhere +To: Andrew Morton , stable@kernel.org +Cc: Davide Brini , uml-devel +Message-ID: <20070325170144.GB6232@c2.user-mode-linux.org> +Content-Disposition: inline + +From: Jeff Dike + +This patch uses MAX_REG_NR consistently to refer to the register file +size. FRAME_SIZE isn't sufficient because on x86_64, it is smaller +than the ptrace register file size. MAX_REG_NR was introduced as a +consistent way to get the number of registers, but wasn't used +everywhere it should be. + +When this causes a problem, it makes PTRACE_SETREGS fail on x86_64 +because of a corrupted segment register value in the known-good +register file. The patch also adds a register dump at that point in +case there are any future problems here. + +Signed-off-by: Jeff Dike +Signed-off-by: Greg Kroah-Hartman + +--- + arch/um/include/sysdep-x86_64/ptrace.h | 4 ---- + arch/um/os-Linux/skas/mem.c | 10 +++++++--- + arch/um/os-Linux/skas/process.c | 6 +++--- + arch/um/os-Linux/sys-i386/registers.c | 5 +++-- + arch/um/os-Linux/sys-x86_64/registers.c | 4 ++-- + 5 files changed, 15 insertions(+), 14 deletions(-) + +--- a/arch/um/include/sysdep-x86_64/ptrace.h ++++ b/arch/um/include/sysdep-x86_64/ptrace.h +@@ -104,10 +104,6 @@ union uml_pt_regs { + #endif + #ifdef UML_CONFIG_MODE_SKAS + struct skas_regs { +- /* x86_64 ptrace uses sizeof(user_regs_struct) as its register +- * file size, while i386 uses FRAME_SIZE. Therefore, we need +- * to use UM_FRAME_SIZE here instead of HOST_FRAME_SIZE. +- */ + unsigned long regs[MAX_REG_NR]; + unsigned long fp[HOST_FP_SIZE]; + struct faultinfo faultinfo; +--- a/arch/um/os-Linux/skas/mem.c ++++ b/arch/um/os-Linux/skas/mem.c +@@ -48,7 +48,7 @@ int multi_op_count = 0; + static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) + { + unsigned long regs[MAX_REG_NR]; +- int n; ++ int n, i; + long ret, offset; + unsigned long * data; + unsigned long * syscall; +@@ -66,9 +66,13 @@ static inline long do_syscall_stub(struc + (unsigned long) &__syscall_stub_start); + + n = ptrace_setregs(pid, regs); +- if(n < 0) ++ if(n < 0){ ++ printk("Registers - \n"); ++ for(i = 0; i < MAX_REG_NR; i++) ++ printk("\t%d\t0x%lx\n", i, regs[i]); + panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", +- n); ++ -n); ++ } + + wait_stub_done(pid, 0, "do_syscall_stub"); + +--- a/arch/um/os-Linux/skas/process.c ++++ b/arch/um/os-Linux/skas/process.c +@@ -67,7 +67,7 @@ void wait_stub_done(int pid, int sig, ch + + if((n < 0) || !WIFSTOPPED(status) || + (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){ +- unsigned long regs[HOST_FRAME_SIZE]; ++ unsigned long regs[MAX_REG_NR]; + + if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) + printk("Failed to get registers from stub, " +@@ -76,7 +76,7 @@ void wait_stub_done(int pid, int sig, ch + int i; + + printk("Stub registers -\n"); +- for(i = 0; i < HOST_FRAME_SIZE; i++) ++ for(i = 0; i < ARRAY_SIZE(regs); i++) + printk("\t%d - %lx\n", i, regs[i]); + } + panic("%s : failed to wait for SIGUSR1/SIGTRAP, " +@@ -328,7 +328,7 @@ void userspace(union uml_pt_regs *regs) + int copy_context_skas0(unsigned long new_stack, int pid) + { + int err; +- unsigned long regs[HOST_FRAME_SIZE]; ++ unsigned long regs[MAX_REG_NR]; + unsigned long fp_regs[HOST_FP_SIZE]; + unsigned long current_stack = current_stub_stack(); + struct stub_data *data = (struct stub_data *) current_stack; +--- a/arch/um/os-Linux/sys-i386/registers.c ++++ b/arch/um/os-Linux/sys-i386/registers.c +@@ -15,7 +15,7 @@ + + /* These are set once at boot time and not changed thereafter */ + +-static unsigned long exec_regs[HOST_FRAME_SIZE]; ++static unsigned long exec_regs[MAX_REG_NR]; + static unsigned long exec_fp_regs[HOST_FP_SIZE]; + static unsigned long exec_fpx_regs[HOST_XFP_SIZE]; + static int have_fpx_regs = 1; +@@ -101,6 +101,7 @@ void init_registers(int pid) + { + int err; + ++ memset(exec_regs, 0, sizeof(exec_regs)); + err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs); + if(err) + panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", +@@ -124,7 +125,7 @@ void init_registers(int pid) + + void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) + { +- memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long)); ++ memcpy(regs, exec_regs, sizeof(exec_regs)); + if(fp_regs != NULL) + memcpy(fp_regs, exec_fp_regs, + HOST_FP_SIZE * sizeof(unsigned long)); +--- a/arch/um/os-Linux/sys-x86_64/registers.c ++++ b/arch/um/os-Linux/sys-x86_64/registers.c +@@ -14,7 +14,7 @@ + + /* These are set once at boot time and not changed thereafter */ + +-static unsigned long exec_regs[HOST_FRAME_SIZE]; ++static unsigned long exec_regs[MAX_REG_NR]; + static unsigned long exec_fp_regs[HOST_FP_SIZE]; + + void init_thread_registers(union uml_pt_regs *to) +@@ -72,7 +72,7 @@ void init_registers(int pid) + + void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) + { +- memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long)); ++ memcpy(regs, exec_regs, sizeof(exec_regs)); + if(fp_regs != NULL) + memcpy(fp_regs, exec_fp_regs, + HOST_FP_SIZE * sizeof(unsigned long)); diff --git a/queue-2.6.20/video-fix-ffb-dac-revision-probing.patch b/queue-2.6.20/video-fix-ffb-dac-revision-probing.patch new file mode 100644 index 00000000000..84099bac397 --- /dev/null +++ b/queue-2.6.20/video-fix-ffb-dac-revision-probing.patch @@ -0,0 +1,195 @@ +From stable-bounces@linux.kernel.org Thu Mar 29 12:17:46 2007 +From: David Miller +Date: Thu, 29 Mar 2007 12:16:27 -0700 (PDT) +Subject: VIDEO: Fix FFB DAC revision probing +To: stable@kernel.org +Cc: bunk@stusta.de +Message-ID: <20070329.121627.59655905.davem@davemloft.net> + +From: David Miller + +[VIDEO] ffb: Fix two DAC handling bugs. + +The determination of whether the DAC has inverted cursor logic is +broken, import the version checks the X.org driver uses to fix this. + +Next, when we change the timing generator, borrow code from X.org that +does 10 NOP reads of the timing generator register afterwards to make +sure the video-enable transition occurs cleanly. + +Finally, use macros for the DAC registers and fields in order to +provide documentation for the next person who reads this code. + +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/video/ffb.c | 84 +++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 60 insertions(+), 24 deletions(-) + +--- a/drivers/video/ffb.c ++++ b/drivers/video/ffb.c +@@ -336,14 +336,30 @@ struct ffb_dac { + u32 value2; + }; + ++#define FFB_DAC_UCTRL 0x1001 /* User Control */ ++#define FFB_DAC_UCTRL_MANREV 0x00000f00 /* 4-bit Manufacturing Revision */ ++#define FFB_DAC_UCTRL_MANREV_SHIFT 8 ++#define FFB_DAC_TGEN 0x6000 /* Timing Generator */ ++#define FFB_DAC_TGEN_VIDE 0x00000001 /* Video Enable */ ++#define FFB_DAC_DID 0x8000 /* Device Identification */ ++#define FFB_DAC_DID_PNUM 0x0ffff000 /* Device Part Number */ ++#define FFB_DAC_DID_PNUM_SHIFT 12 ++#define FFB_DAC_DID_REV 0xf0000000 /* Device Revision */ ++#define FFB_DAC_DID_REV_SHIFT 28 ++ ++#define FFB_DAC_CUR_CTRL 0x100 ++#define FFB_DAC_CUR_CTRL_P0 0x00000001 ++#define FFB_DAC_CUR_CTRL_P1 0x00000002 ++ + struct ffb_par { + spinlock_t lock; + struct ffb_fbc __iomem *fbc; + struct ffb_dac __iomem *dac; + + u32 flags; +-#define FFB_FLAG_AFB 0x00000001 +-#define FFB_FLAG_BLANKED 0x00000002 ++#define FFB_FLAG_AFB 0x00000001 /* AFB m3 or m6 */ ++#define FFB_FLAG_BLANKED 0x00000002 /* screen is blanked */ ++#define FFB_FLAG_INVCURSOR 0x00000004 /* DAC has inverted cursor logic */ + + u32 fg_cache __attribute__((aligned (8))); + u32 bg_cache; +@@ -354,7 +370,6 @@ struct ffb_par { + unsigned long physbase; + unsigned long fbsize; + +- int dac_rev; + int board_type; + }; + +@@ -426,11 +441,12 @@ static void ffb_switch_from_graph(struct + FFBWait(par); + + /* Disable cursor. */ +- upa_writel(0x100, &dac->type2); +- if (par->dac_rev <= 2) ++ upa_writel(FFB_DAC_CUR_CTRL, &dac->type2); ++ if (par->flags & FFB_FLAG_INVCURSOR) + upa_writel(0, &dac->value2); + else +- upa_writel(3, &dac->value2); ++ upa_writel((FFB_DAC_CUR_CTRL_P0 | ++ FFB_DAC_CUR_CTRL_P1), &dac->value2); + + spin_unlock_irqrestore(&par->lock, flags); + } +@@ -664,18 +680,18 @@ ffb_blank(int blank, struct fb_info *inf + struct ffb_par *par = (struct ffb_par *) info->par; + struct ffb_dac __iomem *dac = par->dac; + unsigned long flags; +- u32 tmp; ++ u32 val; ++ int i; + + spin_lock_irqsave(&par->lock, flags); + + FFBWait(par); + ++ upa_writel(FFB_DAC_TGEN, &dac->type); ++ val = upa_readl(&dac->value); + switch (blank) { + case FB_BLANK_UNBLANK: /* Unblanking */ +- upa_writel(0x6000, &dac->type); +- tmp = (upa_readl(&dac->value) | 0x1); +- upa_writel(0x6000, &dac->type); +- upa_writel(tmp, &dac->value); ++ val |= FFB_DAC_TGEN_VIDE; + par->flags &= ~FFB_FLAG_BLANKED; + break; + +@@ -683,13 +699,16 @@ ffb_blank(int blank, struct fb_info *inf + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + case FB_BLANK_POWERDOWN: /* Poweroff */ +- upa_writel(0x6000, &dac->type); +- tmp = (upa_readl(&dac->value) & ~0x1); +- upa_writel(0x6000, &dac->type); +- upa_writel(tmp, &dac->value); ++ val &= ~FFB_DAC_TGEN_VIDE; + par->flags |= FFB_FLAG_BLANKED; + break; + } ++ upa_writel(FFB_DAC_TGEN, &dac->type); ++ upa_writel(val, &dac->value); ++ for (i = 0; i < 10; i++) { ++ upa_writel(FFB_DAC_TGEN, &dac->type); ++ upa_readl(&dac->value); ++ } + + spin_unlock_irqrestore(&par->lock, flags); + +@@ -894,6 +913,7 @@ static int ffb_init_one(struct of_device + struct ffb_dac __iomem *dac; + struct all_info *all; + int err; ++ u32 dac_pnum, dac_rev, dac_mrev; + + all = kzalloc(sizeof(*all), GFP_KERNEL); + if (!all) +@@ -948,17 +968,31 @@ static int ffb_init_one(struct of_device + if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) + upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr); + +- ffb_switch_from_graph(&all->par); +- + dac = all->par.dac; +- upa_writel(0x8000, &dac->type); +- all->par.dac_rev = upa_readl(&dac->value) >> 0x1c; ++ upa_writel(FFB_DAC_DID, &dac->type); ++ dac_pnum = upa_readl(&dac->value); ++ dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT; ++ dac_pnum = (dac_pnum & FFB_DAC_DID_PNUM) >> FFB_DAC_DID_PNUM_SHIFT; ++ ++ upa_writel(FFB_DAC_UCTRL, &dac->type); ++ dac_mrev = upa_readl(&dac->value); ++ dac_mrev = (dac_mrev & FFB_DAC_UCTRL_MANREV) >> ++ FFB_DAC_UCTRL_MANREV_SHIFT; + + /* Elite3D has different DAC revision numbering, and no DAC revisions +- * have the reversed meaning of cursor enable. ++ * have the reversed meaning of cursor enable. Otherwise, Pacifica 1 ++ * ramdacs with manufacturing revision less than 3 have inverted ++ * cursor logic. We identify Pacifica 1 as not Pacifica 2, the ++ * latter having a part number value of 0x236e. + */ +- if (all->par.flags & FFB_FLAG_AFB) +- all->par.dac_rev = 10; ++ if ((all->par.flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) { ++ all->par.flags &= ~FFB_FLAG_INVCURSOR; ++ } else { ++ if (dac_mrev < 3) ++ all->par.flags |= FFB_FLAG_INVCURSOR; ++ } ++ ++ ffb_switch_from_graph(&all->par); + + /* Unblank it just to be sure. When there are multiple + * FFB/AFB cards in the system, or it is not the OBP +@@ -993,10 +1027,12 @@ static int ffb_init_one(struct of_device + + dev_set_drvdata(&op->dev, all); + +- printk("%s: %s at %016lx, type %d, DAC revision %d\n", ++ printk("%s: %s at %016lx, type %d, " ++ "DAC pnum[%x] rev[%d] manuf_rev[%d]\n", + dp->full_name, + ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), +- all->par.physbase, all->par.board_type, all->par.dac_rev); ++ all->par.physbase, all->par.board_type, ++ dac_pnum, dac_rev, dac_mrev); + + return 0; + }