From 821376bf15e692941f9235f13a14987009fd0b10 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Thu, 21 Apr 2005 11:07:59 -0700 Subject: [IA64] fix fls() The ia64-version of fls() never worked as intended (the bitnumbering was off by 1 and fls(0) was undefined). This patch fixes the problem by using a popcnt-based fls(), which on McKinley-derived cores is slightly faster than both ia64_fls() and generic_fls(). The resulting code, however, is bigger (7-8 bundles instead of about 3 bundles). Also switch ia64_popcnt() to __builtin_popcountl() for GCC v3.4 or newer since the compiler can predicate that and schedule it better. Thanks to Simon Derr and Matt Mackall for tracking down this bug. Signed-off-by: David Mosberger-Tang Signed-off-by: Tony Luck diff --git a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h index 925d54c..7232528 100644 --- a/include/asm-ia64/bitops.h +++ b/include/asm-ia64/bitops.h @@ -314,8 +314,8 @@ __ffs (unsigned long x) #ifdef __KERNEL__ /* - * find_last_zero_bit - find the last zero bit in a 64 bit quantity - * @x: The value to search + * Return bit number of last (most-significant) bit set. Undefined + * for x==0. Bits are numbered from 0..63 (e.g., ia64_fls(9) == 3). */ static inline unsigned long ia64_fls (unsigned long x) @@ -327,10 +327,23 @@ ia64_fls (unsigned long x) return exp - 0xffff; } +/* + * Find the last (most significant) bit set. Returns 0 for x==0 and + * bits are numbered from 1..32 (e.g., fls(9) == 4). + */ static inline int -fls (int x) +fls (int t) { - return ia64_fls((unsigned int) x); + unsigned long x = t & 0xffffffffu; + + if (!x) + return 0; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ia64_popcnt(x); } /* diff --git a/include/asm-ia64/gcc_intrin.h b/include/asm-ia64/gcc_intrin.h index 7c357df..4fb4e43 100644 --- a/include/asm-ia64/gcc_intrin.h +++ b/include/asm-ia64/gcc_intrin.h @@ -133,13 +133,17 @@ register unsigned long ia64_r13 asm ("r13") __attribute_used__; ia64_intri_res; \ }) -#define ia64_popcnt(x) \ -({ \ +#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# define ia64_popcnt(x) __builtin_popcountl(x) +#else +# define ia64_popcnt(x) \ + ({ \ __u64 ia64_intri_res; \ asm ("popcnt %0=%1" : "=r" (ia64_intri_res) : "r" (x)); \ \ ia64_intri_res; \ -}) + }) +#endif #define ia64_getf_exp(x) \ ({ \ -- cgit v0.10.2 From dfe547ab872951949a1a2fcc5cedbedad27a2fe5 Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Thu, 21 Apr 2005 14:09:42 -0700 Subject: [PATCH] ohci1394: tlabels misprinted in DBGMSG - Print the correct value in the DBGMSG in dma_rcv_tasklet(). See OHCI 1.1 section 8.7, page 103 ff. - Print tlabels as %d everywhere. Signed-off-by: Stefan Richter Signed-off-by: Jody McIntyre Signed-off-by: Linus Torvalds diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 97ff364..72830e6 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -2691,7 +2691,7 @@ static void dma_rcv_tasklet (unsigned long data) (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f, (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3, tcode, length, d->ctx, - (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>10)&0x3f); + (cond_le32_to_cpu(d->spb[0], ohci->no_swap_incoming)>>10)&0x3f); ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f) == 0x11) ? 1 : 0; @@ -2754,7 +2754,7 @@ static void dma_trm_tasklet (unsigned long data) d->ctx); else DBGMSG("Packet sent to node %d tcode=0x%X tLabel=" - "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d", + "%d ack=0x%X spd=%d dataLength=%d ctx=%d", (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16)&0x3f, (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf, (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>10)&0x3f, @@ -2763,7 +2763,7 @@ static void dma_trm_tasklet (unsigned long data) d->ctx); else DBGMSG("Packet sent to node %d tcode=0x%X tLabel=" - "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d", + "%d ack=0x%X spd=%d data=0x%08X ctx=%d", (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) >>16)&0x3f, (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) -- cgit v0.10.2 From e4ec0f23c878f761cf33f3cbb66c66d6c05931ba Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Thu, 21 Apr 2005 14:09:42 -0700 Subject: [PATCH] Fix non-legacy ISO receive regression Fix non-legacy multichannel ISO receive, broken by Parag Wardukar's allocation fix. Multichannel ISO receive still sucks; it should be possible to use both legacy and non-legacy modes at the same time, but with this patch, things are no worse than they were in 2.6.11 and allocation is still done at the correct time. Signed-off-by: Jody McIntyre Signed-off-by: Linus Torvalds diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 72830e6..6cb0b58 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -539,10 +539,8 @@ static void ohci_initialize(struct ti_ohci *ohci) initialize_dma_trm_ctx(&ohci->at_req_context); initialize_dma_trm_ctx(&ohci->at_resp_context); - /* Initialize IR Legacy DMA */ + /* Initialize IR Legacy DMA channel mask */ ohci->ir_legacy_channels = 0; - initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1); - DBGMSG("ISO receive legacy context activated"); /* * Accept AT requests from all nodes. This probably @@ -1032,6 +1030,8 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) case ISO_LISTEN_CHANNEL: { u64 mask; + struct dma_rcv_ctx *d = &ohci->ir_legacy_context; + int ir_legacy_active; if (arg<0 || arg>63) { PRINT(KERN_ERR, @@ -1052,9 +1052,37 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) return -EFAULT; } + ir_legacy_active = ohci->ir_legacy_channels; + ohci->ISO_channel_usage |= mask; ohci->ir_legacy_channels |= mask; + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + + if (!ir_legacy_active) { + if (ohci1394_register_iso_tasklet(ohci, + &ohci->ir_legacy_tasklet) < 0) { + PRINT(KERN_ERR, "No IR DMA context available"); + return -EBUSY; + } + + /* the IR context can be assigned to any DMA context + * by ohci1394_register_iso_tasklet */ + d->ctx = ohci->ir_legacy_tasklet.context; + d->ctrlSet = OHCI1394_IsoRcvContextControlSet + + 32*d->ctx; + d->ctrlClear = OHCI1394_IsoRcvContextControlClear + + 32*d->ctx; + d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx; + d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx; + + initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1); + + PRINT(KERN_ERR, "IR legacy activated"); + } + + spin_lock_irqsave(&ohci->IR_channel_lock, flags); + if (arg>31) reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, 1<<(arg-32)); @@ -1101,6 +1129,12 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); DBGMSG("Listening disabled on channel %d", arg); + + if (ohci->ir_legacy_channels == 0) { + stop_dma_rcv_ctx(&ohci->ir_legacy_context); + DBGMSG("ISO legacy receive context stopped"); + } + break; } default: @@ -1270,8 +1304,10 @@ static int ohci_iso_recv_init(struct hpsb_iso *iso) OHCI_ISO_RECEIVE, ohci_iso_recv_task, (unsigned long) iso); - if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) + if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) { + ret = -EBUSY; goto err; + } recv->task_active = 1; @@ -1896,8 +1932,10 @@ static int ohci_iso_xmit_init(struct hpsb_iso *iso) ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT, ohci_iso_xmit_task, (unsigned long) iso); - if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) + if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) { + ret = -EBUSY; goto err; + } xmit->task_active = 1; @@ -2999,20 +3037,6 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, ohci1394_init_iso_tasklet(&ohci->ir_legacy_tasklet, OHCI_ISO_MULTICHANNEL_RECEIVE, dma_rcv_tasklet, (unsigned long) d); - if (ohci1394_register_iso_tasklet(ohci, - &ohci->ir_legacy_tasklet) < 0) { - PRINT(KERN_ERR, "No IR DMA context available"); - free_dma_rcv_ctx(d); - return -EBUSY; - } - - /* the IR context can be assigned to any DMA context - * by ohci1394_register_iso_tasklet */ - d->ctx = ohci->ir_legacy_tasklet.context; - d->ctrlSet = OHCI1394_IsoRcvContextControlSet + 32*d->ctx; - d->ctrlClear = OHCI1394_IsoRcvContextControlClear + 32*d->ctx; - d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx; - d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx; } else { d->ctrlSet = context_base + OHCI1394_ContextControlSet; d->ctrlClear = context_base + OHCI1394_ContextControlClear; @@ -3413,7 +3437,6 @@ static void ohci1394_pci_remove(struct pci_dev *pdev) switch (ohci->init_state) { case OHCI_INIT_DONE: - stop_dma_rcv_ctx(&ohci->ir_legacy_context); hpsb_remove_host(ohci->host); /* Clear out BUS Options */ -- cgit v0.10.2 From 62b56faa43a7e672e659d14f38f553ed8b40ea70 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 21 Apr 2005 14:09:42 -0700 Subject: [PATCH] Fix tgafb.c compile failure The untested patch below should fix this compile error. Signed-off-by: Adrian Bunk Signed-off-by: Linus Torvalds diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 3099630..9d9d200 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -45,9 +45,7 @@ static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *); static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *); static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *); -#ifdef MODULE static void tgafb_pci_unregister(struct pci_dev *); -#endif static const char *mode_option = "640x480@60"; @@ -1484,7 +1482,6 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) return ret; } -#ifdef MODULE static void __exit tgafb_pci_unregister(struct pci_dev *pdev) { @@ -1500,6 +1497,7 @@ tgafb_pci_unregister(struct pci_dev *pdev) kfree(info); } +#ifdef MODULE static void __exit tgafb_exit(void) { -- cgit v0.10.2 From 1cff94c6fecdc54d6f022ae5a22888f8272804a1 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 21 Apr 2005 16:20:35 -0700 Subject: [PATCH] fix subarch breakage in amd dual core updates The patch to arch/i386/kernel/cpu/amd.c relies on the variable cpu_core_id which is defined in i386/kernel/smpboot.c. This means it is only present if CONFIG_X86_SMP is defined, not CONFIG_SMP (alternative SMP harnesses won't have it, which is why it breaks voyager). Signed-off-by: James Bottomley Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c index 8d182e8..16dbc41 100644 --- a/arch/i386/kernel/cpu/amd.c +++ b/arch/i386/kernel/cpu/amd.c @@ -24,7 +24,7 @@ __asm__(".align 4\nvide: ret"); static void __init init_amd(struct cpuinfo_x86 *c) { -#ifdef CONFIG_SMP +#ifdef CONFIG_X86_SMP int cpu = c == &boot_cpu_data ? 0 : c - cpu_data; #endif u32 l, h; @@ -198,7 +198,7 @@ static void __init init_amd(struct cpuinfo_x86 *c) c->x86_num_cores = 1; } -#ifdef CONFIG_SMP +#ifdef CONFIG_X86_SMP /* * On a AMD dual core setup the lower bits of the APIC id * distingush the cores. Assumes number of cores is a power -- cgit v0.10.2 From 26095455ac2943edb0852aba1ff8f8026aabe07b Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 21 Apr 2005 16:43:02 -0700 Subject: [NET]: Add missing newline for skb_*_panic While we're at it, lets also replace KERN_INFO by KERN_EMERG to make sure the user gets to see it. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 1b64817..f65b3de 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -86,8 +86,10 @@ static kmem_cache_t *skbuff_head_cache; */ void skb_over_panic(struct sk_buff *skb, int sz, void *here) { - printk(KERN_INFO "skput:over: %p:%d put:%d dev:%s", - here, skb->len, sz, skb->dev ? skb->dev->name : ""); + printk(KERN_EMERG "skb_over_panic: text:%p len:%d put:%d head:%p " + "data:%p tail:%p end:%p dev:%s\n", + here, skb->len, sz, skb->head, skb->data, skb->tail, skb->end, + skb->dev ? skb->dev->name : ""); BUG(); } @@ -102,8 +104,10 @@ void skb_over_panic(struct sk_buff *skb, int sz, void *here) void skb_under_panic(struct sk_buff *skb, int sz, void *here) { - printk(KERN_INFO "skput:under: %p:%d put:%d dev:%s", - here, skb->len, sz, skb->dev ? skb->dev->name : ""); + printk(KERN_EMERG "skb_under_panic: text:%p len:%d put:%d head:%p " + "data:%p tail:%p end:%p dev:%s\n", + here, skb->len, sz, skb->head, skb->data, skb->tail, skb->end, + skb->dev ? skb->dev->name : ""); BUG(); } -- cgit v0.10.2 From 208a6dfbd651f3a16c635678a731b419d3d9646f Mon Sep 17 00:00:00 2001 From: Chas Williams Date: Thu, 21 Apr 2005 16:44:57 -0700 Subject: [ATM]: sk_atm() conversion missed subtle change of vcc Signed-off-by: Chas Williams Signed-off-by: David S. Miller diff --git a/net/atm/signaling.c b/net/atm/signaling.c index 6ff8031..f7c449a 100644 --- a/net/atm/signaling.c +++ b/net/atm/signaling.c @@ -134,6 +134,7 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) break; case as_indicate: vcc = *(struct atm_vcc **) &msg->listen_vcc; + sk = sk_atm(vcc); DPRINTK("as_indicate!!!\n"); lock_sock(sk); if (sk_acceptq_is_full(sk)) { -- cgit v0.10.2 From 29c4be51e3fd52205d848248d38924941f22ca0e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 21 Apr 2005 16:46:56 -0700 Subject: [AX25]: make ax25_queue_xmit a net_device parameter I.e. not using skb->dev as a way to pass the parameter used to fill... skb->dev :-) Also to get the _type_trans open coded sequence grouped, next changesets will introduce ax25_type_trans. Signed-off-by: Ralf Baechle Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller diff --git a/include/net/ax25.h b/include/net/ax25.h index fb95ecb..875edbb 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -305,7 +305,7 @@ extern ax25_cb *ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_addr extern void ax25_output(ax25_cb *, int, struct sk_buff *); extern void ax25_kick(ax25_cb *); extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int); -extern void ax25_queue_xmit(struct sk_buff *); +extern void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev); extern int ax25_check_iframes_acked(ax25_cb *, unsigned short); /* ax25_route.c */ diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 33b1a37..707097d 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1587,9 +1587,7 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, *asmptr = AX25_UI; /* Datagram frames go straight out of the door as UI */ - skb->dev = ax25->ax25_dev->dev; - - ax25_queue_xmit(skb); + ax25_queue_xmit(skb, ax25->ax25_dev->dev); err = len; diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index 04d7113..bba0173 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c @@ -199,9 +199,7 @@ int ax25_rebuild_header(struct sk_buff *skb) skb = ourskb; } - skb->dev = dev; - - ax25_queue_xmit(skb); + ax25_queue_xmit(skb, dev); put: ax25_put_route(route); diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index 3475a3a..94557b1 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -340,21 +340,19 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type) ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus); - skb->dev = ax25->ax25_dev->dev; - - ax25_queue_xmit(skb); + ax25_queue_xmit(skb, ax25->ax25_dev->dev); } /* * A small shim to dev_queue_xmit to add the KISS control byte, and do * any packet forwarding in operation. */ -void ax25_queue_xmit(struct sk_buff *skb) +void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned char *ptr; skb->protocol = htons(ETH_P_AX25); - skb->dev = ax25_fwd_dev(skb->dev); + skb->dev = ax25_fwd_dev(dev); ptr = skb_push(skb, 1); *ptr = 0x00; /* KISS */ diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c index 8cf7270..99694b5 100644 --- a/net/ax25/ax25_subr.c +++ b/net/ax25/ax25_subr.c @@ -220,9 +220,7 @@ void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *des dptr = skb_push(skb, ax25_addr_size(digi)); dptr += ax25_addr_build(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS); - skb->dev = dev; - - ax25_queue_xmit(skb); + ax25_queue_xmit(skb, dev); } /* -- cgit v0.10.2 From ebc37b611616ad46dce7d590b15ad655aa50213a Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 21 Apr 2005 16:48:26 -0700 Subject: [ATM]: net/atm/resources.c: remove __free_atm_dev Signed-off-by: Adrian Bunk Signed-off-by: Chas Williams Signed-off-by: David S. Miller diff --git a/net/atm/resources.c b/net/atm/resources.c index 33f1685..a57a926 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -44,11 +44,6 @@ static struct atm_dev *__alloc_atm_dev(const char *type) return dev; } -static void __free_atm_dev(struct atm_dev *dev) -{ - kfree(dev); -} - static struct atm_dev *__atm_dev_lookup(int number) { struct atm_dev *dev; @@ -90,7 +85,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, if ((inuse = __atm_dev_lookup(number))) { atm_dev_put(inuse); spin_unlock(&atm_dev_lock); - __free_atm_dev(dev); + kfree(dev); return NULL; } dev->number = number; @@ -119,7 +114,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, spin_lock(&atm_dev_lock); list_del(&dev->dev_list); spin_unlock(&atm_dev_lock); - __free_atm_dev(dev); + kfree(dev); return NULL; } @@ -148,7 +143,7 @@ void atm_dev_deregister(struct atm_dev *dev) } } - __free_atm_dev(dev); + kfree(dev); } void shutdown_atm_dev(struct atm_dev *dev) -- cgit v0.10.2 From 2052da946096590035438626afbc7f329d2549d8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 21 Apr 2005 16:56:08 -0700 Subject: [TG3]: add basic bcm5752 support Add ASIC_REV_5752 definition. Track-down all references to ASIC_REV_5750 and mirror them with references to the newly defined ASIC_REV_5752. Signed-off-by: John W. Linville Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 12de808..34301ef 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -86,7 +86,8 @@ #define TG3_MIN_MTU 60 #define TG3_MAX_MTU(tp) \ ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && \ - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) ? 9000 : 1500) + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && \ + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) ? 9000 : 1500) /* These numbers seem to be hard coded in the NIC firmware somehow. * You can't change the ring sizes, but you can change where you place @@ -861,7 +862,8 @@ out: /* Cannot do read-modify-write on 5401 */ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20); } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) { u32 phy_reg; /* Set bit 14 with read-modify-write to preserve other bits */ @@ -874,7 +876,8 @@ out: * jumbo frames transmission. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) { u32 phy_reg; if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &phy_reg)) @@ -1068,7 +1071,8 @@ static int tg3_set_power_state(struct tg3 *tp, int state) mac_mode = MAC_MODE_PORT_MODE_TBI; } - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) tw32(MAC_LED_CTRL, tp->led_ctrl); if (((power_caps & PCI_PM_CAP_PME_D3cold) && @@ -3967,7 +3971,8 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; } } @@ -5041,7 +5046,8 @@ static int tg3_reset_hw(struct tg3 *tp) tw32(GRC_MISC_CFG, val); /* Initialize MBUF/DESC pool. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { /* Do nothing. */ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) { tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE); @@ -5240,7 +5246,8 @@ static int tg3_reset_hw(struct tg3 *tp) rdmac_mode |= RDMAC_MODE_SPLIT_ENABLE; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)) { + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)) { if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE && (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { @@ -5355,7 +5362,8 @@ static int tg3_reset_hw(struct tg3 *tp) if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)) { if ((tp->tg3_flags & TG3_FLG2_TSO_CAPABLE) && (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { @@ -7028,7 +7036,8 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) tw32(NVRAM_CFG1, nvcfg1); } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; @@ -7093,7 +7102,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) { tp->tg3_flags |= TG3_FLAG_NVRAM; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); @@ -7102,7 +7112,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_nvram_info(tp); tg3_get_nvram_size(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); @@ -7195,7 +7206,8 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) tg3_nvram_lock(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); @@ -7210,7 +7222,8 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) tg3_nvram_unlock(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); @@ -7438,7 +7451,8 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) tg3_nvram_lock(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); @@ -7463,7 +7477,8 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) grc_mode = tr32(GRC_MODE); tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); @@ -7581,7 +7596,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) } else eeprom_phy_id = 0; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK | SHASTA_EXT_LED_MODE_MASK); } else @@ -7634,7 +7650,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; } if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL) @@ -7932,10 +7949,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)) + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)) tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->tg3_flags2 |= TG3_FLG2_HW_TSO; if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0) @@ -8066,7 +8085,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; /* Only 5701 and later support tagged irq status mode. @@ -8462,7 +8482,8 @@ static int __devinit tg3_test_dma(struct tg3 *tp) tp->dma_rwctrl |= 0x00180000; } else if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->dma_rwctrl |= 0x003f0000; else tp->dma_rwctrl |= 0x003f000f; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d48887d..820df83 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -132,6 +132,7 @@ #define ASIC_REV_5704 0x02 #define ASIC_REV_5705 0x03 #define ASIC_REV_5750 0x04 +#define ASIC_REV_5752 0x05 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 -- cgit v0.10.2 From af2bcd97b570f39da94103f80f67433dab515049 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 21 Apr 2005 16:57:50 -0700 Subject: [TG3]: add bcm5752 to tg3_pci_tbl Add hard-coded definition of bcm5752 PCI ID to tg3_pci_tbl. Next patch will change entry to use pci_ids.h-based definition. Signed-off-by: John W. Linville Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 34301ef..b72e95e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -206,6 +206,8 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, 0x1600, /* TIGON3_5752 */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M, -- cgit v0.10.2 From 6e9017a7d9b949aea638eeba67d34affaa145f14 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 21 Apr 2005 16:58:56 -0700 Subject: [TG3]: add bcm5752 entry to pci_ids.h Add proper entry for bcm5752 PCI ID to pci_ids.h, and use it in tg3. I did this separately in case patches like this (i.e. new PCI IDs) need to come from more "official" sources. Signed-off-by: John W. Linville Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b72e95e..4375eec 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -206,7 +206,7 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_BROADCOM, 0x1600, /* TIGON3_5752 */ + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f1f75fd..6a18974 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2062,6 +2062,7 @@ #define PCI_DEVICE_ID_AFAVLAB_P030 0x2182 #define PCI_VENDOR_ID_BROADCOM 0x14e4 +#define PCI_DEVICE_ID_TIGON3_5752 0x1600 #define PCI_DEVICE_ID_TIGON3_5700 0x1644 #define PCI_DEVICE_ID_TIGON3_5701 0x1645 #define PCI_DEVICE_ID_TIGON3_5702 0x1646 -- cgit v0.10.2 From fcf026936c613fc6ca4685677a461100d87eec81 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 21 Apr 2005 17:00:02 -0700 Subject: [TG3]: use TG3_FLG2_5705_PLUS instead of multi-way if's Replace a number of three-way if statements checking for 5705, 5750, and 5752 to reference the equivalent TG3_FLG2_5705_PLUS flag instead. Signed-off-by: John W. Linville Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4375eec..7ff598c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -85,9 +85,7 @@ /* hardware minimum and maximum for a single frame's data payload */ #define TG3_MIN_MTU 60 #define TG3_MAX_MTU(tp) \ - ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && \ - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && \ - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) ? 9000 : 1500) + (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ? 9000 : 1500) /* These numbers seem to be hard coded in the NIC firmware somehow. * You can't change the ring sizes, but you can change where you place @@ -863,9 +861,7 @@ out: if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { /* Cannot do read-modify-write on 5401 */ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20); - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) { + } else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { u32 phy_reg; /* Set bit 14 with read-modify-write to preserve other bits */ @@ -877,9 +873,7 @@ out: /* Set phy register 0x10 bit 0 to high fifo elasticity to support * jumbo frames transmission. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) { + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { u32 phy_reg; if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &phy_reg)) @@ -8483,9 +8477,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp) /* DMA read watermark not used on PCIE */ tp->dma_rwctrl |= 0x00180000; } else if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) tp->dma_rwctrl |= 0x003f0000; else tp->dma_rwctrl |= 0x003f000f; -- cgit v0.10.2 From 6708e5cc103ba045fca035b4d8df236ca31fb8bc Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 21 Apr 2005 17:00:52 -0700 Subject: [TG3]: define TG3_FLG2_5750_PLUS flag Define TG3_FLG2_5750_PLUS flag and set it in tg3_get_invariants for ASIC_REV_5750 or ASIC_REV_5752. Signed-off-by: John W. Linville Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7ff598c..7b21b07 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7951,6 +7951,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->tg3_flags2 |= TG3_FLG2_HW_TSO; if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0) diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 820df83..0cce404 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2101,6 +2101,7 @@ struct tg3 { #define TG3_FLG2_HW_TSO 0x00010000 #define TG3_FLG2_SERDES_PREEMPHASIS 0x00020000 #define TG3_FLG2_5705_PLUS 0x00040000 +#define TG3_FLG2_5750_PLUS 0x00080000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 -- cgit v0.10.2 From cbf46853c8db75f98bd005dc545aca0703063d4b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 21 Apr 2005 17:01:29 -0700 Subject: [TG3]: use new TG3_FLG2_5750_PLUS flag Replace a number of two-way if statements checking for 5750, and/or 5752 to reference the newly-defined TG3_FLG2_5750_PLUS flag instead. Signed-off-by: John W. Linville Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7b21b07..e75e000 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1067,8 +1067,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) mac_mode = MAC_MODE_PORT_MODE_TBI; } - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) + if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tw32(MAC_LED_CTRL, tp->led_ctrl); if (((power_caps & PCI_PM_CAP_PME_D3cold) && @@ -3967,8 +3966,7 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; } } @@ -5042,8 +5040,7 @@ static int tg3_reset_hw(struct tg3 *tp) tw32(GRC_MISC_CFG, val); /* Initialize MBUF/DESC pool. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { /* Do nothing. */ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) { tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE); @@ -7032,8 +7029,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) tw32(NVRAM_CFG1, nvcfg1); } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; @@ -7098,8 +7094,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) { tp->tg3_flags |= TG3_FLAG_NVRAM; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); @@ -7108,8 +7103,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_nvram_info(tp); tg3_get_nvram_size(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); @@ -7202,8 +7196,7 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) tg3_nvram_lock(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); @@ -7218,8 +7211,7 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) tg3_nvram_unlock(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); @@ -7447,8 +7439,7 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) tg3_nvram_lock(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); @@ -7473,8 +7464,7 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) grc_mode = tr32(GRC_MODE); tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); @@ -7592,11 +7582,10 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) } else eeprom_phy_id = 0; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) { + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK | SHASTA_EXT_LED_MODE_MASK); - } else + else led_cfg = nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK; switch (led_cfg) { @@ -7646,8 +7635,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; } if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL) -- cgit v0.10.2 From 863925f59e5425e4af6996b9c50857c766940176 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 21 Apr 2005 17:02:04 -0700 Subject: [TG3]: more use of TG3_FLG2_5705_PLUS flag Rewrite of a couple of troublesome multi-way if statements to use TG3_FLG2_5705_PLUS flag. Signed-off-by: John W. Linville Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e75e000..46f8da6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5237,10 +5237,8 @@ static int tg3_reset_hw(struct tg3 *tp) RDMAC_MODE_LNGREAD_ENAB); if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE) rdmac_mode |= RDMAC_MODE_SPLIT_ENABLE; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && - tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)) { + if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) { if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE && (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { @@ -5353,10 +5351,8 @@ static int tg3_reset_hw(struct tg3 *tp) WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB | WDMAC_MODE_LNGREAD_ENAB); - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && - tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)) { + if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) { if ((tp->tg3_flags & TG3_FLG2_TSO_CAPABLE) && (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { -- cgit v0.10.2 From bb7064dc09ff90015ddc7d818dd8fefb8ca5b936 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 21 Apr 2005 17:02:41 -0700 Subject: [TG3]: use TG3_FLG2_57{05,50}_PLUS flags in tg3_get_invariants Rewrite checks in tg3_get_invariants to use TG3_FLG2_5705_PLUS and TG3_FLG2_5750_PLUS flags. Signed-off-by: John W. Linville Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 46f8da6..f47b305 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7937,8 +7937,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) tp->tg3_flags2 |= TG3_FLG2_HW_TSO; if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0) @@ -8068,9 +8067,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; /* Only 5701 and later support tagged irq status mode. -- cgit v0.10.2 From 1b440c568e28186956ef765c69ab124401088663 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 21 Apr 2005 17:03:18 -0700 Subject: [TG3]: check TG3_FLG2_5750_PLUS flag to set TG3_FLG2_5705_PLUS flag Use check of TG3_FLG2_5750_PLUS in tg3_get_invariants to set TG3_FLG2_5705_PLUS flag. Signed-off-by: John W. Linville Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f47b305..0951a96 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7928,15 +7928,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pci_hdr_type = (cacheline_sz_reg >> 16) & 0xff; tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)) - tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || + (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) + tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) tp->tg3_flags2 |= TG3_FLG2_HW_TSO; -- cgit v0.10.2 From 053d78000be4906fac6446ad517ca3897dc6cd84 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 21 Apr 2005 17:03:52 -0700 Subject: [TG3]: add support for bcm5752 rev a1 Replace existing ASIC_REV_5752 definition with ASIC_REV_5752_A0, and add definition for ASIC_REV_5752_A1. Then, add ASIC_REV_5752_A1 to check for setting TG3_FLG2_5750_PLUS in tg3_get_invariants. Signed-off-by: John W. Linville Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0951a96..c188197 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7929,7 +7929,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752_A0 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752_A1) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 0cce404..3a91a57 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -125,6 +125,8 @@ #define CHIPREV_ID_5750_A0 0x4000 #define CHIPREV_ID_5750_A1 0x4001 #define CHIPREV_ID_5750_A3 0x4003 +#define CHIPREV_ID_5752_A0 0x5000 +#define CHIPREV_ID_5752_A1 0x6001 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -132,7 +134,8 @@ #define ASIC_REV_5704 0x02 #define ASIC_REV_5705 0x03 #define ASIC_REV_5750 0x04 -#define ASIC_REV_5752 0x05 +#define ASIC_REV_5752_A0 0x05 +#define ASIC_REV_5752_A1 0x06 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 -- cgit v0.10.2 From 85e94cedc44d1c2c1663b5b18f703ca5e7316e59 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:05:28 -0700 Subject: [TG3]: Minor 5752 fixes Some minor 5752 fixes mostly for correctness and add 5752 PHY ID. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c188197..f22f19b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1094,7 +1094,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133); udelay(40); - } else if (!((GET_ASIC_REV(tp->pci_chip_rev_id) == 5750) && + } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) { u32 newbits1, newbits2; @@ -5237,8 +5237,11 @@ static int tg3_reset_hw(struct tg3 *tp) RDMAC_MODE_LNGREAD_ENAB); if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE) rdmac_mode |= RDMAC_MODE_SPLIT_ENABLE; - if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) { + + /* If statement applies to 5705 and 5750 PCI devices only */ + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && + tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)) { if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE && (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { @@ -5249,6 +5252,9 @@ static int tg3_reset_hw(struct tg3 *tp) } } + if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) + rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST; + #if TG3_TSO_SUPPORT != 0 if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) rdmac_mode |= (1 << 27); @@ -5351,8 +5357,10 @@ static int tg3_reset_hw(struct tg3 *tp) WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB | WDMAC_MODE_LNGREAD_ENAB); - if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) { + /* If statement applies to 5705 and 5750 PCI devices only */ + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && + tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { if ((tp->tg3_flags & TG3_FLG2_TSO_CAPABLE) && (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { @@ -7025,7 +7033,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) tw32(NVRAM_CFG1, nvcfg1); } - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; @@ -8462,7 +8470,8 @@ static int __devinit tg3_test_dma(struct tg3 *tp) /* DMA read watermark not used on PCIE */ tp->dma_rwctrl |= 0x00180000; } else if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) tp->dma_rwctrl |= 0x003f0000; else tp->dma_rwctrl |= 0x003f000f; @@ -8628,6 +8637,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5704: return "5704"; case PHY_ID_BCM5705: return "5705"; case PHY_ID_BCM5750: return "5750"; + case PHY_ID_BCM5752: return "5752"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 3a91a57..4732a80 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2150,6 +2150,7 @@ struct tg3 { #define PHY_ID_BCM5704 0x60008190 #define PHY_ID_BCM5705 0x600081a0 #define PHY_ID_BCM5750 0x60008180 +#define PHY_ID_BCM5752 0x60008100 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff #define PHY_ID_REV_MASK 0x0000000f -- cgit v0.10.2 From 7d0c41ef89dad9008edf1c3c0022721ebad39999 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:06:20 -0700 Subject: [TG3]: Split tg3_phy_probe into 2 functions Split the 1st half of tg3_phy_probe() into tg3_get_eeprom_hw_cfg() so that the TG3_FLAG_EEPROM_WRITE_PROT can be determined before calling tg3_set_power_state() in tg3_get_invariants(). This will allow tg3_set_power_state() to drive the GPIOs correctly based on the config. information in eeprom. On the 5752, there are no pull-up resistors on the GPIO pins and it is necessary to drive the unused GPIOs as output. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f22f19b..dd036c0 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7542,21 +7542,27 @@ static inline struct subsys_tbl_ent *lookup_by_subsys(struct tg3 *tp) return NULL; } -static int __devinit tg3_phy_probe(struct tg3 *tp) +/* Since this function may be called in D3-hot power state during + * tg3_init_one(), only config cycles are allowed. + */ +static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) { - u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2; - u32 hw_phy_id, hw_phy_id_masked; u32 val; - int eeprom_signature_found, eeprom_phy_serdes, err; + + /* Make sure register accesses (indirect or otherwise) + * will function correctly. + */ + pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, + tp->misc_host_ctrl); tp->phy_id = PHY_ID_INVALID; - eeprom_phy_id = PHY_ID_INVALID; - eeprom_phy_serdes = 0; - eeprom_signature_found = 0; + tp->led_ctrl = LED_CTRL_MODE_PHY_1; + tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg, led_cfg; - u32 nic_phy_id, ver, cfg2 = 0; + u32 nic_phy_id, ver, cfg2 = 0, eeprom_phy_id; + int eeprom_phy_serdes = 0; tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); tp->nic_sram_data_cfg = nic_cfg; @@ -7569,8 +7575,6 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) (ver > 0) && (ver < 0x100)) tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2); - eeprom_signature_found = 1; - if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) == NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) eeprom_phy_serdes = 1; @@ -7586,6 +7590,10 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) } else eeprom_phy_id = 0; + tp->phy_id = eeprom_phy_id; + if (eeprom_phy_serdes) + tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK | SHASTA_EXT_LED_MODE_MASK); @@ -7653,6 +7661,13 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) if (cfg2 & (1 << 18)) tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS; } +} + +static int __devinit tg3_phy_probe(struct tg3 *tp) +{ + u32 hw_phy_id_1, hw_phy_id_2; + u32 hw_phy_id, hw_phy_id_masked; + int err; /* Reading the PHY ID register can conflict with ASF * firwmare access to the PHY hardware. @@ -7681,10 +7696,10 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) if (hw_phy_id_masked == PHY_ID_BCM8002) tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; } else { - if (eeprom_signature_found) { - tp->phy_id = eeprom_phy_id; - if (eeprom_phy_serdes) - tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; + if (tp->phy_id != PHY_ID_INVALID) { + /* Do nothing, phy ID already set up in + * tg3_get_eeprom_hw_cfg(). + */ } else { struct subsys_tbl_ent *p; @@ -7755,9 +7770,6 @@ skip_phy_reset: err = tg3_init_5401phy_dsp(tp); } - if (!eeprom_signature_found) - tp->led_ctrl = LED_CTRL_MODE_PHY_1; - if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) tp->link_config.advertising = (ADVERTISED_1000baseT_Half | @@ -8023,6 +8035,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg); } + /* Get eeprom hw config before calling tg3_set_power_state(). + * In particular, the TG3_FLAG_EEPROM_WRITE_PROT flag must be + * determined before calling tg3_set_power_state() so that + * we know whether or not to switch out of Vaux power. + * When the flag is set, it means that GPIO1 is used for eeprom + * write protect and also implies that it is a LOM where GPIOs + * are not used to switch power. + */ + tg3_get_eeprom_hw_cfg(tp); + /* Force the chip into D0. */ err = tg3_set_power_state(tp, 0); if (err) { -- cgit v0.10.2 From 314fba348e1f64a30b53d3cff5d96872424e8498 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:07:04 -0700 Subject: [TG3]: Setup proper GPIO settings Setup proper GPIO settings in tp->grc_local_ctrl before calling tg3_set_power() state in tg3_get_invariants() and after chip reset. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index dd036c0..742340a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5336,10 +5336,23 @@ static int tg3_reset_hw(struct tg3 *tp) tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR); udelay(40); - tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) + /* tp->grc_local_ctrl is partially set up during tg3_get_invariants(). + * If TG3_FLAG_EEPROM_WRITE_PROT is set, we should read the + * register to preserve the GPIO settings for LOMs. The GPIOs, + * whether used as inputs or outputs, are set by boot code after + * reset. + */ + if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { + u32 gpio_mask; + + gpio_mask = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT2; + tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask; + + /* GPIO1 must be driven high for eeprom write protect */ tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); + } tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); @@ -7430,8 +7443,8 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) } if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { - tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | - GRC_LCLCTRL_GPIO_OE1); + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & + ~GRC_LCLCTRL_GPIO_OUTPUT1); udelay(40); } @@ -7477,8 +7490,7 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) } if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { - tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | - GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(40); } @@ -8045,6 +8057,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ tg3_get_eeprom_hw_cfg(tp); + /* Set up tp->grc_local_ctrl before calling tg3_set_power_state(). + * GPIO1 driven high will bring 5700's external PHY out of reset. + * It is also used as eeprom write protect on LOMs. + */ + tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM; + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) || + (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT)) + tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OUTPUT1); + /* Force the chip into D0. */ err = tg3_set_power_state(tp, 0); if (err) { -- cgit v0.10.2 From 8c6bda1a89c148f3a28edc09a76dac9bff57d8ee Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:09:08 -0700 Subject: [TG3]: Fix tg3_set_power_state() Fix tg3_set_power_state to drive GPIOs properly based on the TG3_FLAG_EEPROM_WRITE_PROTECT flag. Some delays are also added after D0 and D3 power state changes. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 742340a..f0b5dc7 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1005,8 +1005,13 @@ static int tg3_set_power_state(struct tg3 *tp, int state) pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); - tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); - udelay(100); + udelay(100); /* Delay after power state change */ + + /* Switch out of Vaux if it is not a LOM */ + if (!(tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT)) { + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); + udelay(100); + } return 0; @@ -1151,6 +1156,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) /* Finally, set the new power state. */ pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); + udelay(100); /* Delay after power state change */ tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); -- cgit v0.10.2 From ff645bec523819fa4d28d7e0de7d998e3edb0c57 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:09:53 -0700 Subject: [TG3]: Workaround 5752 A0 chip ID The 5752 A0 chip ID is wrong in hardware. The simplest way to workaround it is to change it to the correct value in tp->pci_chip_rev_id. This way, it is easier to check for the ASIC_REV_5752 in the rest of the driver. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f0b5dc7..a4d0d61 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7952,6 +7952,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pci_chip_rev_id = (misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT); + /* Wrong chip ID in 5752 A0. This code can be removed later + * as A0 is not in production. + */ + if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW) + tp->pci_chip_rev_id = CHIPREV_ID_5752_A0; + /* Initialize misc host control in PCI block. */ tp->misc_host_ctrl |= (misc_ctrl_reg & MISC_HOST_CTRL_CHIPREV); @@ -7967,8 +7973,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752_A0 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752_A1) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 4732a80..3f7cd6f 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -125,7 +125,8 @@ #define CHIPREV_ID_5750_A0 0x4000 #define CHIPREV_ID_5750_A1 0x4001 #define CHIPREV_ID_5750_A3 0x4003 -#define CHIPREV_ID_5752_A0 0x5000 +#define CHIPREV_ID_5752_A0_HW 0x5000 +#define CHIPREV_ID_5752_A0 0x6000 #define CHIPREV_ID_5752_A1 0x6001 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 @@ -134,8 +135,7 @@ #define ASIC_REV_5704 0x02 #define ASIC_REV_5705 0x03 #define ASIC_REV_5750 0x04 -#define ASIC_REV_5752_A0 0x05 -#define ASIC_REV_5752_A1 0x06 +#define ASIC_REV_5752 0x06 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 -- cgit v0.10.2 From 3e7d83bc96d59013792e5546e7832668d3adbce7 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:10:36 -0700 Subject: [TG3]: Add GPIO3 for 5752 Add bit definitions for the new GPIO3 in 5752. GPIO3 must be driven as output when it is unused. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a4d0d61..a94631a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5353,6 +5353,11 @@ static int tg3_reset_hw(struct tg3 *tp) gpio_mask = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT2; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + gpio_mask |= GRC_LCLCTRL_GPIO_OE3 | + GRC_LCLCTRL_GPIO_OUTPUT3; + tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask; /* GPIO1 must be driven high for eeprom write protect */ @@ -8077,6 +8082,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT)) tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); + /* Unused GPIO3 must be driven as output on 5752 because there + * are no pull-up resistors on unused GPIO pins. + */ + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3; /* Force the chip into D0. */ err = tg3_set_power_state(tp, 0); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 3f7cd6f..548f469 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1311,6 +1311,9 @@ #define GRC_LCLCTRL_CLEARINT 0x00000002 #define GRC_LCLCTRL_SETINT 0x00000004 #define GRC_LCLCTRL_INT_ON_ATTN 0x00000008 +#define GRC_LCLCTRL_GPIO_INPUT3 0x00000020 +#define GRC_LCLCTRL_GPIO_OE3 0x00000040 +#define GRC_LCLCTRL_GPIO_OUTPUT3 0x00000080 #define GRC_LCLCTRL_GPIO_INPUT0 0x00000100 #define GRC_LCLCTRL_GPIO_INPUT1 0x00000200 #define GRC_LCLCTRL_GPIO_INPUT2 0x00000400 -- cgit v0.10.2 From 361b4ac29bc651c7612d4bf21434ae6fe06b78e4 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:11:21 -0700 Subject: [TG3]: Add nvram detection for 5752 Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a94631a..dbdd3ec 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7096,6 +7096,63 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) } } +static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1; + + nvcfg1 = tr32(NVRAM_CFG1); + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ: + case FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + break; + } + + if (tp->tg3_flags2 & TG3_FLG2_FLASH) { + switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { + case FLASH_5752PAGE_SIZE_256: + tp->nvram_pagesize = 256; + break; + case FLASH_5752PAGE_SIZE_512: + tp->nvram_pagesize = 512; + break; + case FLASH_5752PAGE_SIZE_1K: + tp->nvram_pagesize = 1024; + break; + case FLASH_5752PAGE_SIZE_2K: + tp->nvram_pagesize = 2048; + break; + case FLASH_5752PAGE_SIZE_4K: + tp->nvram_pagesize = 4096; + break; + case FLASH_5752PAGE_SIZE_264: + tp->nvram_pagesize = 264; + break; + } + } + else { + /* For eeprom, set pagesize to maximum eeprom size */ + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + } +} + /* Chips other than 5700/5701 use the NVRAM for fetching info. */ static void __devinit tg3_nvram_init(struct tg3 *tp) { @@ -7128,7 +7185,11 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); } - tg3_get_nvram_info(tp); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + tg3_get_5752_nvram_info(tp); + else + tg3_get_nvram_info(tp); + tg3_get_nvram_size(tp); if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 548f469..261c2db 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1399,6 +1399,20 @@ #define FLASH_VENDOR_SAIFUN 0x01000003 #define FLASH_VENDOR_SST_SMALL 0x00000001 #define FLASH_VENDOR_SST_LARGE 0x02000001 +#define NVRAM_CFG1_5752VENDOR_MASK 0x03c00003 +#define FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ 0x00000000 +#define FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ 0x02000000 +#define FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED 0x02000003 +#define FLASH_5752VENDOR_ST_M45PE10 0x02400000 +#define FLASH_5752VENDOR_ST_M45PE20 0x02400002 +#define FLASH_5752VENDOR_ST_M45PE40 0x02400001 +#define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 +#define FLASH_5752PAGE_SIZE_256 0x00000000 +#define FLASH_5752PAGE_SIZE_512 0x10000000 +#define FLASH_5752PAGE_SIZE_1K 0x20000000 +#define FLASH_5752PAGE_SIZE_2K 0x30000000 +#define FLASH_5752PAGE_SIZE_4K 0x40000000 +#define FLASH_5752PAGE_SIZE_264 0x50000000 #define NVRAM_CFG2 0x00007018 #define NVRAM_CFG3 0x0000701c #define NVRAM_SWARB 0x00007020 -- cgit v0.10.2 From e6af301be3c129adbc8a7c8ffb76e62533ad9575 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:12:05 -0700 Subject: [TG3]: Add nvram lock-out support for 5752 TPM Add support for the NVRAM lock-out feature for TPM in 5752. If lock-out is enabled, certain NVRAM registers cannot be written to. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index dbdd3ec..3015464 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3732,6 +3732,28 @@ static void tg3_nvram_unlock(struct tg3 *tp) } /* tp->lock is held. */ +static void tg3_enable_nvram_access(struct tg3 *tp) +{ + if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && + !(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) { + u32 nvaccess = tr32(NVRAM_ACCESS); + + tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); + } +} + +/* tp->lock is held. */ +static void tg3_disable_nvram_access(struct tg3 *tp) +{ + if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && + !(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) { + u32 nvaccess = tr32(NVRAM_ACCESS); + + tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); + } +} + +/* tp->lock is held. */ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) { if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) @@ -7102,6 +7124,10 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) nvcfg1 = tr32(NVRAM_CFG1); + /* NVRAM protection for TPM */ + if (nvcfg1 & (1 << 27)) + tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM; + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ: case FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ: @@ -7179,11 +7205,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) { tp->tg3_flags |= TG3_FLAG_NVRAM; - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - u32 nvaccess = tr32(NVRAM_ACCESS); - - tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); - } + tg3_enable_nvram_access(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tg3_get_5752_nvram_info(tp); @@ -7192,11 +7214,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_nvram_size(tp); - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - u32 nvaccess = tr32(NVRAM_ACCESS); - - tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); - } + tg3_disable_nvram_access(tp); } else { tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED); @@ -7285,11 +7303,7 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) tg3_nvram_lock(tp); - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - u32 nvaccess = tr32(NVRAM_ACCESS); - - tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); - } + tg3_enable_nvram_access(tp); tw32(NVRAM_ADDR, offset); ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO | @@ -7300,11 +7314,7 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) tg3_nvram_unlock(tp); - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - u32 nvaccess = tr32(NVRAM_ACCESS); - - tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); - } + tg3_disable_nvram_access(tp); return ret; } @@ -7367,7 +7377,7 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len, while (len) { int j; - u32 phy_addr, page_off, size, nvaccess; + u32 phy_addr, page_off, size; phy_addr = offset & ~pagemask; @@ -7390,8 +7400,7 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len, offset = offset + (pagesize - page_off); - nvaccess = tr32(NVRAM_ACCESS); - tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); + tg3_enable_nvram_access(tp); /* * Before we can erase the flash page, we need @@ -7528,13 +7537,10 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) tg3_nvram_lock(tp); - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - u32 nvaccess = tr32(NVRAM_ACCESS); - - tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); - + tg3_enable_nvram_access(tp); + if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && + !(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) tw32(NVRAM_WRITE1, 0x406); - } grc_mode = tr32(GRC_MODE); tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE); @@ -7553,11 +7559,7 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) grc_mode = tr32(GRC_MODE); tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE); - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - u32 nvaccess = tr32(NVRAM_ACCESS); - - tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); - } + tg3_disable_nvram_access(tp); tg3_nvram_unlock(tp); } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 261c2db..d3f03f0 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2122,6 +2122,7 @@ struct tg3 { #define TG3_FLG2_SERDES_PREEMPHASIS 0x00020000 #define TG3_FLG2_5705_PLUS 0x00040000 #define TG3_FLG2_5750_PLUS 0x00080000 +#define TG3_FLG2_PROTECTED_NVRAM 0x00100000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 -- cgit v0.10.2 From 1c8594b48b00a98d12477355e944e165a5f64cd5 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:12:46 -0700 Subject: [TG3]: Fix bug in tg3_set_eeprom() Fix a bug in tg3_set_eeprom() when the length is less than 4 and the offset is not 4-byte aligned. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 3015464..fb3eb6f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6560,10 +6560,12 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, start = cpu_to_le32(start); len += b_offset; offset &= ~3; + if (len < 4) + len = 4; } odd_len = 0; - if ((len & 3) && ((len > 4) || (b_offset == 0))) { + if (len & 3) { /* adjustments to end on required 4 byte boundary */ odd_len = 1; len = (len + 3) & ~3; -- cgit v0.10.2 From 88b06bc26b87cf0490b0e3faea7fefc7549dd75d Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:13:25 -0700 Subject: [TG3]: Add msi support Add MSI support for 5751 C0 and 5752. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index fb3eb6f..2a17af9 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -2907,6 +2907,43 @@ static inline unsigned int tg3_has_work(struct net_device *dev, struct tg3 *tp) return work_exists; } +/* MSI ISR - No need to check for interrupt sharing and no need to + * flush status block and interrupt mailbox. PCI ordering rules + * guarantee that MSI will arrive after the status block. + */ +static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct tg3 *tp = netdev_priv(dev); + struct tg3_hw_status *sblk = tp->hw_status; + unsigned long flags; + + spin_lock_irqsave(&tp->lock, flags); + + /* + * writing any value to intr-mbox-0 clears PCI INTA# and + * chip-internal interrupt pending events. + * writing non-zero to intr-mbox-0 additional tells the + * NIC to stop sending us irqs, engaging "in-intr-handler" + * event coalescing. + */ + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + sblk->status &= ~SD_STATUS_UPDATED; + + if (likely(tg3_has_work(dev, tp))) + netif_rx_schedule(dev); /* schedule NAPI poll */ + else { + /* no work, re-enable interrupts + */ + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + 0x00000000); + } + + spin_unlock_irqrestore(&tp->lock, flags); + + return IRQ_RETVAL(1); +} + static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; @@ -2965,7 +3002,9 @@ static int tg3_halt(struct tg3 *); #ifdef CONFIG_NET_POLL_CONTROLLER static void tg3_poll_controller(struct net_device *dev) { - tg3_interrupt(dev->irq, dev, NULL); + struct tg3 *tp = netdev_priv(dev); + + tg3_interrupt(tp->pdev->irq, dev, NULL); } #endif @@ -5778,10 +5817,29 @@ static int tg3_open(struct net_device *dev) if (err) return err; - err = request_irq(dev->irq, tg3_interrupt, - SA_SHIRQ, dev->name, dev); + if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && + (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_AX) && + (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX)) { + if (pci_enable_msi(tp->pdev) == 0) { + u32 msi_mode; + + msi_mode = tr32(MSGINT_MODE); + tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); + tp->tg3_flags2 |= TG3_FLG2_USING_MSI; + } + } + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) + err = request_irq(tp->pdev->irq, tg3_msi, + 0, dev->name, dev); + else + err = request_irq(tp->pdev->irq, tg3_interrupt, + SA_SHIRQ, dev->name, dev); if (err) { + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + pci_disable_msi(tp->pdev); + tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; + } tg3_free_consistent(tp); return err; } @@ -5811,7 +5869,11 @@ static int tg3_open(struct net_device *dev) spin_unlock_irq(&tp->lock); if (err) { - free_irq(dev->irq, dev); + free_irq(tp->pdev->irq, dev); + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + pci_disable_msi(tp->pdev); + tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; + } tg3_free_consistent(tp); return err; } @@ -6086,7 +6148,11 @@ static int tg3_close(struct net_device *dev) spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - free_irq(dev->irq, dev); + free_irq(tp->pdev->irq, dev); + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + pci_disable_msi(tp->pdev); + tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; + } memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev), sizeof(tp->net_stats_prev)); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d3f03f0..8de6f21 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2123,6 +2123,7 @@ struct tg3 { #define TG3_FLG2_5705_PLUS 0x00040000 #define TG3_FLG2_5750_PLUS 0x00080000 #define TG3_FLG2_PROTECTED_NVRAM 0x00100000 +#define TG3_FLG2_USING_MSI 0x00200000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 -- cgit v0.10.2 From 7938109fff944e0117976a39946d99d2b0b0250d Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 21 Apr 2005 17:13:59 -0700 Subject: [TG3]: Add msi test Add MSI test for chips that support MSI. If MSI test fails, it will switch back to INTx mode and will print a message asking the user to report the failure. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2a17af9..f65ca3b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -2996,6 +2996,22 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_RETVAL(handled); } +/* ISR for interrupt test */ +static irqreturn_t tg3_test_isr(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct tg3 *tp = netdev_priv(dev); + struct tg3_hw_status *sblk = tp->hw_status; + + if (sblk->status & SD_STATUS_UPDATED) { + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + 0x00000001); + return IRQ_RETVAL(1); + } + return IRQ_RETVAL(0); +} + static int tg3_init_hw(struct tg3 *); static int tg3_halt(struct tg3 *); @@ -5796,6 +5812,118 @@ static void tg3_timer(unsigned long __opaque) add_timer(&tp->timer); } +static int tg3_test_interrupt(struct tg3 *tp) +{ + struct net_device *dev = tp->dev; + int err, i; + u32 int_mbox = 0; + + tg3_disable_ints(tp); + + free_irq(tp->pdev->irq, dev); + + err = request_irq(tp->pdev->irq, tg3_test_isr, + SA_SHIRQ, dev->name, dev); + if (err) + return err; + + tg3_enable_ints(tp); + + tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | + HOSTCC_MODE_NOW); + + for (i = 0; i < 5; i++) { + int_mbox = tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); + if (int_mbox != 0) + break; + msleep(10); + } + + tg3_disable_ints(tp); + + free_irq(tp->pdev->irq, dev); + + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) + err = request_irq(tp->pdev->irq, tg3_msi, + 0, dev->name, dev); + else + err = request_irq(tp->pdev->irq, tg3_interrupt, + SA_SHIRQ, dev->name, dev); + + if (err) + return err; + + if (int_mbox != 0) + return 0; + + return -EIO; +} + +/* Returns 0 if MSI test succeeds or MSI test fails and INTx mode is + * successfully restored + */ +static int tg3_test_msi(struct tg3 *tp) +{ + struct net_device *dev = tp->dev; + int err; + u16 pci_cmd; + + if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSI)) + return 0; + + /* Turn off SERR reporting in case MSI terminates with Master + * Abort. + */ + pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd); + pci_write_config_word(tp->pdev, PCI_COMMAND, + pci_cmd & ~PCI_COMMAND_SERR); + + err = tg3_test_interrupt(tp); + + pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); + + if (!err) + return 0; + + /* other failures */ + if (err != -EIO) + return err; + + /* MSI test failed, go back to INTx mode */ + printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, " + "switching to INTx mode. Please report this failure to " + "the PCI maintainer and include system chipset information.\n", + tp->dev->name); + + free_irq(tp->pdev->irq, dev); + pci_disable_msi(tp->pdev); + + tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; + + err = request_irq(tp->pdev->irq, tg3_interrupt, + SA_SHIRQ, dev->name, dev); + + if (err) + return err; + + /* Need to reset the chip because the MSI cycle may have terminated + * with Master Abort. + */ + spin_lock_irq(&tp->lock); + spin_lock(&tp->tx_lock); + + tg3_halt(tp); + err = tg3_init_hw(tp); + + spin_unlock(&tp->tx_lock); + spin_unlock_irq(&tp->lock); + + if (err) + free_irq(tp->pdev->irq, dev); + + return err; +} + static int tg3_open(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); @@ -5860,9 +5988,6 @@ static int tg3_open(struct net_device *dev) tp->timer.expires = jiffies + tp->timer_offset; tp->timer.data = (unsigned long) tp; tp->timer.function = tg3_timer; - add_timer(&tp->timer); - - tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; } spin_unlock(&tp->tx_lock); @@ -5878,9 +6003,32 @@ static int tg3_open(struct net_device *dev) return err; } + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + err = tg3_test_msi(tp); + if (err) { + spin_lock_irq(&tp->lock); + spin_lock(&tp->tx_lock); + + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + pci_disable_msi(tp->pdev); + tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; + } + tg3_halt(tp); + tg3_free_rings(tp); + tg3_free_consistent(tp); + + spin_unlock(&tp->tx_lock); + spin_unlock_irq(&tp->lock); + + return err; + } + } + spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); + add_timer(&tp->timer); + tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; tg3_enable_ints(tp); spin_unlock(&tp->tx_lock); -- cgit v0.10.2 From 5c5d281a93e9816966b6131ccec19519dab0e103 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 21 Apr 2005 20:12:32 -0700 Subject: [XFRM]: Fix existence lookup in xfrm_state_find Use 'daddr' instead of &tmpl->id.daddr, since the latter might be zero. Also, only perform the lookup when tmpl->id.spi is non-zero. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 1db59f1..d11747c 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -357,8 +357,9 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, x = best; if (!x && !error && !acquire_in_progress) { - x0 = afinfo->state_lookup(&tmpl->id.daddr, tmpl->id.spi, tmpl->id.proto); - if (x0 != NULL) { + if (tmpl->id.spi && + (x0 = afinfo->state_lookup(daddr, tmpl->id.spi, + tmpl->id.proto)) != NULL) { xfrm_state_put(x0); error = -EEXIST; goto out; -- cgit v0.10.2 From d7be828e03969ea7f922f299acb8daa0d8ce7006 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 21 Apr 2005 21:41:33 -0700 Subject: [SPARC64]: Provide a pgprot_noncached() implementation. Signed-off-by: David S. Miller diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index af9bf17..ae2cd5b 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -416,6 +416,11 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot); +/* Clear virtual and physical cachability, set side-effect bit. */ +#define pgprot_noncached(prot) \ + (__pgprot((pgprot_val(prot) & ~(_PAGE_CP | _PAGE_CV)) | \ + _PAGE_E)) + /* * For sparc32&64, the pfn in io_remap_pfn_range() carries in * its high 4 bits. These macros/functions put it there or get it from there. -- cgit v0.10.2 From b4bca26c0160f48b4eb04f21d31a229832732013 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 21 Apr 2005 21:42:34 -0700 Subject: [SPARC]: Provide generic ioctls in Sparc RTC driver. Provide support for drivers/char/rtc.c ioctls in the Mostek rtc driver as well as the Sparc specific RTCGET and RTCSET. This allows userspace to be much less messy. Currently util-linux and other spots jump through hoops trying various ioctl variants until it hits the right one whatever driver actually being used supports. Eventually all of this should move over to the genrtc.c driver, but not today... While we are here, fix up the register types for sparse. Thanks to Frans Pop for helping point out this issue. Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 6a717d4d..c60785c 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -48,7 +48,7 @@ DEFINE_SPINLOCK(mostek_lock); DEFINE_SPINLOCK(rtc_lock); -unsigned long mstk48t02_regs = 0UL; +void * __iomem mstk48t02_regs = 0UL; #ifdef CONFIG_PCI unsigned long ds1287_regs = 0UL; #endif @@ -59,8 +59,8 @@ u64 jiffies_64 = INITIAL_JIFFIES; EXPORT_SYMBOL(jiffies_64); -static unsigned long mstk48t08_regs = 0UL; -static unsigned long mstk48t59_regs = 0UL; +static void * __iomem mstk48t08_regs; +static void * __iomem mstk48t59_regs; static int set_rtc_mmss(unsigned long); @@ -520,7 +520,7 @@ void timer_tick_interrupt(struct pt_regs *regs) /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ static void __init kick_start_clock(void) { - unsigned long regs = mstk48t02_regs; + void * __iomem regs = mstk48t02_regs; u8 sec, tmp; int i, count; @@ -604,7 +604,7 @@ static void __init kick_start_clock(void) /* Return nonzero if the clock chip battery is low. */ static int __init has_low_battery(void) { - unsigned long regs = mstk48t02_regs; + void * __iomem regs = mstk48t02_regs; u8 data1, data2; spin_lock_irq(&mostek_lock); @@ -623,7 +623,7 @@ static int __init has_low_battery(void) static void __init set_system_time(void) { unsigned int year, mon, day, hour, min, sec; - unsigned long mregs = mstk48t02_regs; + void * __iomem mregs = mstk48t02_regs; #ifdef CONFIG_PCI unsigned long dregs = ds1287_regs; #else @@ -843,7 +843,8 @@ void __init clock_probe(void) !strcmp(model, "m5823")) { ds1287_regs = edev->resource[0].start; } else { - mstk48t59_regs = edev->resource[0].start; + mstk48t59_regs = (void * __iomem) + edev->resource[0].start; mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; } break; @@ -865,7 +866,8 @@ try_isa_clock: !strcmp(model, "m5823")) { ds1287_regs = isadev->resource.start; } else { - mstk48t59_regs = isadev->resource.start; + mstk48t59_regs = (void * __iomem) + isadev->resource.start; mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; } break; @@ -893,21 +895,24 @@ try_isa_clock: } if(model[5] == '0' && model[6] == '2') { - mstk48t02_regs = (((u64)clk_reg[0].phys_addr) | - (((u64)clk_reg[0].which_io)<<32UL)); + mstk48t02_regs = (void * __iomem) + (((u64)clk_reg[0].phys_addr) | + (((u64)clk_reg[0].which_io)<<32UL)); } else if(model[5] == '0' && model[6] == '8') { - mstk48t08_regs = (((u64)clk_reg[0].phys_addr) | - (((u64)clk_reg[0].which_io)<<32UL)); + mstk48t08_regs = (void * __iomem) + (((u64)clk_reg[0].phys_addr) | + (((u64)clk_reg[0].which_io)<<32UL)); mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; } else { - mstk48t59_regs = (((u64)clk_reg[0].phys_addr) | - (((u64)clk_reg[0].which_io)<<32UL)); + mstk48t59_regs = (void * __iomem) + (((u64)clk_reg[0].phys_addr) | + (((u64)clk_reg[0].which_io)<<32UL)); mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; } break; } - if (mstk48t02_regs != 0UL) { + if (mstk48t02_regs != NULL) { /* Report a low battery voltage condition. */ if (has_low_battery()) prom_printf("NVRAM: Low battery voltage!\n"); @@ -1087,7 +1092,7 @@ unsigned long long sched_clock(void) static int set_rtc_mmss(unsigned long nowtime) { int real_seconds, real_minutes, chip_minutes; - unsigned long mregs = mstk48t02_regs; + void * __iomem mregs = mstk48t02_regs; #ifdef CONFIG_PCI unsigned long dregs = ds1287_regs; #else diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c index bf3273e..49d1cd9 100644 --- a/drivers/sbus/char/rtc.c +++ b/drivers/sbus/char/rtc.c @@ -28,6 +28,42 @@ static int rtc_busy = 0; +/* This is the structure layout used by drivers/char/rtc.c, we + * support that driver's ioctls so that things are less messy in + * userspace. + */ +struct rtc_time_generic { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; +#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ +#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ +#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ +#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ +#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ +#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ +#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */ +#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */ +#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time_generic) /* Read RTC time */ +#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time_generic) /* Set RTC time */ +#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */ +#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */ +#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ +#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ +#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ +#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ +#define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/ +#define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/ +#define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ +#define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ + /* Retrieve the current date and time from the real time clock. */ static void get_rtc_time(struct rtc_time *t) { @@ -82,29 +118,87 @@ void set_rtc_time(struct rtc_time *t) spin_unlock_irq(&mostek_lock); } +static int put_rtc_time_generic(void __user *argp, struct rtc_time *tm) +{ + struct rtc_time_generic __user *utm = argp; + + if (__put_user(tm->sec, &utm->tm_sec) || + __put_user(tm->min, &utm->tm_min) || + __put_user(tm->hour, &utm->tm_hour) || + __put_user(tm->dom, &utm->tm_mday) || + __put_user(tm->month, &utm->tm_mon) || + __put_user(tm->year, &utm->tm_year) || + __put_user(tm->dow, &utm->tm_wday) || + __put_user(0, &utm->tm_yday) || + __put_user(0, &utm->tm_isdst)) + return -EFAULT; + + return 0; +} + +static int get_rtc_time_generic(struct rtc_time *tm, void __user *argp) +{ + struct rtc_time_generic __user *utm = argp; + + if (__get_user(tm->sec, &utm->tm_sec) || + __get_user(tm->min, &utm->tm_min) || + __get_user(tm->hour, &utm->tm_hour) || + __get_user(tm->dom, &utm->tm_mday) || + __get_user(tm->month, &utm->tm_mon) || + __get_user(tm->year, &utm->tm_year) || + __get_user(tm->dow, &utm->tm_wday)) + return -EFAULT; + + return 0; +} + static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time rtc_tm; void __user *argp = (void __user *)arg; - switch (cmd) - { + switch (cmd) { + /* No interrupt support, return an error + * compatible with drivers/char/rtc.c + */ + case RTC_AIE_OFF: + case RTC_AIE_ON: + case RTC_PIE_OFF: + case RTC_PIE_ON: + case RTC_UIE_OFF: + case RTC_UIE_ON: + case RTC_IRQP_READ: + case RTC_IRQP_SET: + case RTC_EPOCH_SET: + case RTC_EPOCH_READ: + return -EINVAL; + case RTCGET: + case RTC_RD_TIME: memset(&rtc_tm, 0, sizeof(struct rtc_time)); get_rtc_time(&rtc_tm); - if (copy_to_user(argp, &rtc_tm, sizeof(struct rtc_time))) + if (cmd == RTCGET) { + if (copy_to_user(argp, &rtc_tm, + sizeof(struct rtc_time))) + return -EFAULT; + } else if (put_rtc_time_generic(argp, &rtc_tm)) return -EFAULT; return 0; case RTCSET: + case RTC_SET_TIME: if (!capable(CAP_SYS_TIME)) return -EPERM; - if (copy_from_user(&rtc_tm, argp, sizeof(struct rtc_time))) + if (cmd == RTCSET) { + if (copy_from_user(&rtc_tm, argp, + sizeof(struct rtc_time))) + return -EFAULT; + } else if (get_rtc_time_generic(&rtc_tm, argp)) return -EFAULT; set_rtc_time(&rtc_tm); @@ -164,6 +258,7 @@ static int __init rtc_sun_init(void) printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n"); return error; } + printk("rtc_sun_init: Registered Mostek RTC driver.\n"); return 0; } diff --git a/include/asm-sparc64/mostek.h b/include/asm-sparc64/mostek.h index ccf2f5f..1f9b135 100644 --- a/include/asm-sparc64/mostek.h +++ b/include/asm-sparc64/mostek.h @@ -38,7 +38,7 @@ * * We now deal with physical addresses for I/O to the chip. -DaveM */ -static __inline__ u8 mostek_read(unsigned long addr) +static __inline__ u8 mostek_read(void * __iomem addr) { u8 ret; @@ -48,7 +48,7 @@ static __inline__ u8 mostek_read(unsigned long addr) return ret; } -static __inline__ void mostek_write(unsigned long addr, u8 val) +static __inline__ void mostek_write(void * __iomem addr, u8 val) { __asm__ __volatile__("stba %0, [%1] %2" : /* no outputs */ @@ -67,7 +67,7 @@ static __inline__ void mostek_write(unsigned long addr, u8 val) #define MOSTEK_YEAR 0x07ffUL extern spinlock_t mostek_lock; -extern unsigned long mstk48t02_regs; +extern void *__iomem mstk48t02_regs; /* Control register values. */ #define MSTK_CREG_WRITE 0x80 /* Must set this before placing values. */ -- cgit v0.10.2 From 623f41eb923d7f34888cbd9e4f50a7b1a79d0ae5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 21 Apr 2005 22:06:13 -0700 Subject: [SPARC64]: In sunsu driver, make sure to fully init chip for kbd/ms We were forgetting to call sunsu_change_speed(). The reason that replugging in the mouse cable "fixes things" is that causes a BREAK interrupt which in turn caused a call to sunsu_change_speed() which would get the chip setup properly. Signed-off-by: David S. Miller diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 23d19d3..ddc97c9 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1285,6 +1285,7 @@ static struct uart_driver sunsu_reg = { static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) { + int quot, baud; #ifdef CONFIG_SERIO struct serio *serio; #endif @@ -1293,10 +1294,14 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) up->port.type = PORT_UNKNOWN; up->port.uartclk = (SU_BASE_BAUD * 16); - if (up->su_type == SU_PORT_KBD) + if (up->su_type == SU_PORT_KBD) { up->cflag = B1200 | CS8 | CLOCAL | CREAD; - else + baud = 1200; + } else { up->cflag = B4800 | CS8 | CLOCAL | CREAD; + baud = 4800; + } + quot = up->port.uartclk / (16 * baud); sunsu_autoconfig(up); if (up->port.type == PORT_UNKNOWN) @@ -1337,6 +1342,8 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) } #endif + sunsu_change_speed(&up->port, up->cflag, 0, quot); + sunsu_startup(&up->port); return 0; } -- cgit v0.10.2 From b179fb8ca57590eeb0a5d6c8dc99f91773f09c73 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 21 Apr 2005 22:18:03 -0700 Subject: [SPARC64]: In sunsab driver, make sure to set the uart timeout. This breaks serial consoles badly. Thanks to Eric Brower for tracking down the problem. Signed-off-by: David S. Miller diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 8caaf2e..39b788d 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -682,7 +682,8 @@ static void calc_ebrg(int baud, int *n_ret, int *m_ret) /* Internal routine, port->lock is held and local interrupts are disabled. */ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cflag, - unsigned int iflag, int baud) + unsigned int iflag, unsigned int baud, + unsigned int quot) { unsigned int ebrg; unsigned char dafo; @@ -766,6 +767,9 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla up->port.ignore_status_mask |= (SAB82532_ISR0_RPF | SAB82532_ISR0_TCD); + uart_update_timeout(&up->port, cflag, + (up->port.uartclk / (16 * quot))); + /* Now bang the new settings into the chip. */ sunsab_cec_wait(up); sunsab_tec_wait(up); @@ -784,10 +788,11 @@ static void sunsab_set_termios(struct uart_port *port, struct termios *termios, { struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; unsigned long flags; - int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); + unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); + unsigned int quot = uart_get_divisor(port, baud); spin_lock_irqsave(&up->port.lock, flags); - sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud); + sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot); spin_unlock_irqrestore(&up->port.lock, flags); } @@ -880,7 +885,7 @@ static int sunsab_console_setup(struct console *con, char *options) { struct uart_sunsab_port *up = &sunsab_ports[con->index]; unsigned long flags; - int baud; + unsigned int baud, quot; printk("Console: ttyS%d (SAB82532)\n", (sunsab_reg.minor - 64) + con->index); @@ -926,7 +931,8 @@ static int sunsab_console_setup(struct console *con, char *options) SAB82532_IMR1_XPR; writeb(up->interrupt_mask1, &up->regs->w.imr1); - sunsab_convert_to_sab(up, con->cflag, 0, baud); + quot = uart_get_divisor(&up->port, baud); + sunsab_convert_to_sab(up, con->cflag, 0, baud, quot); sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); spin_unlock_irqrestore(&up->port.lock, flags); -- cgit v0.10.2 From efab7739d99eae948971140b2aa3dddf7f72c900 Mon Sep 17 00:00:00 2001 From: Alexander Nyberg Date: Fri, 22 Apr 2005 10:22:07 -0700 Subject: [PATCH] x86_64: fix new out of line put_user() The labels after the last put_user patch were misplaced so exceptions on the real mov instructions would not be handled. Noted by Brian Gerst diff --git a/arch/x86_64/lib/putuser.S b/arch/x86_64/lib/putuser.S index d9d3e5e..5828b81 100644 --- a/arch/x86_64/lib/putuser.S +++ b/arch/x86_64/lib/putuser.S @@ -49,8 +49,8 @@ __put_user_2: jc 20f cmpq threadinfo_addr_limit(%r8),%rcx jae 20f -2: decq %rcx - movw %dx,(%rcx) + decq %rcx +2: movw %dx,(%rcx) xorl %eax,%eax ret 20: decq %rcx @@ -64,8 +64,8 @@ __put_user_4: jc 30f cmpq threadinfo_addr_limit(%r8),%rcx jae 30f -3: subq $3,%rcx - movl %edx,(%rcx) + subq $3,%rcx +3: movl %edx,(%rcx) xorl %eax,%eax ret 30: subq $3,%rcx @@ -79,8 +79,8 @@ __put_user_8: jc 40f cmpq threadinfo_addr_limit(%r8),%rcx jae 40f -4: subq $7,%rcx - movq %rdx,(%rcx) + subq $7,%rcx +4: movq %rdx,(%rcx) xorl %eax,%eax ret 40: subq $7,%rcx -- cgit v0.10.2 From 7130667107cd3ab9d6802b69bab63c7d22f20bd4 Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Fri, 22 Apr 2005 13:06:47 -0700 Subject: [IA64] ia32_signal.c: erroneous use of memset/memcpy Found by Alexander Nyberg, improved by Bjorn Helgaas. - Fix the incorrect argument to sizeof() - looks like memcpy() code pass was dervived from code that used copy_from_user(). But in this case we are doing to kernel space to kernel space copy, so memcpy is the right routine, but it doesn't return an error code. Signed-off-by: Arun Sharma Signed-off-by: Tony Luck diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c index 19b02ad..ebb89be 100644 --- a/arch/ia64/ia32/ia32_signal.c +++ b/arch/ia64/ia32/ia32_signal.c @@ -460,10 +460,9 @@ __ia32_rt_sigsuspend (compat_sigset_t *sset, unsigned int sigsetsize, struct sig sigset_t oldset, set; scr->scratch_unat = 0; /* avoid leaking kernel bits to user level */ - memset(&set, 0, sizeof(&set)); + memset(&set, 0, sizeof(set)); - if (memcpy(&set.sig, &sset->sig, sigsetsize)) - return -EFAULT; + memcpy(&set.sig, &sset->sig, sigsetsize); sigdelsetmask(&set, ~_BLOCKABLE); -- cgit v0.10.2 From b8d8b883e6f029e99c35c88f853501740e322131 Mon Sep 17 00:00:00 2001 From: Ashok Raj Date: Fri, 22 Apr 2005 14:44:40 -0700 Subject: [IA64] cpu hotplug: return offlined cpus to SAL This patch is required to support cpu removal for IPF systems. Existing code just fakes the real offline by keeping it run the idle thread, and polling for the bit to re-appear in the cpu_state to get out of the idle loop. For the cpu-offline to work correctly, we need to pass control of this CPU back to SAL so it can continue in the boot-rendez mode. This gives the SAL control to not pick this cpu as the monarch processor for global MCA events, and addition does not wait for this cpu to checkin with SAL for global MCA events as well. The handoff is implemented as documented in SAL specification section 3.2.5.1 "OS_BOOT_RENDEZ to SAL return State" Signed-off-by: Ashok Raj Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index 105c7fe..0d535d6 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -15,6 +15,8 @@ * Copyright (C) 1999 Don Dugger * Copyright (C) 2002 Fenghua Yu * -Optimize __ia64_save_fpu() and __ia64_load_fpu() for Itanium 2. + * Copyright (C) 2004 Ashok Raj + * Support for CPU Hotplug */ #include @@ -29,6 +31,134 @@ #include #include #include +#include + +#ifdef CONFIG_HOTPLUG_CPU +#define SAL_PSR_BITS_TO_SET \ + (IA64_PSR_AC | IA64_PSR_BN | IA64_PSR_MFH | IA64_PSR_MFL) + +#define SAVE_FROM_REG(src, ptr, dest) \ + mov dest=src;; \ + st8 [ptr]=dest,0x08 + +#define RESTORE_REG(reg, ptr, _tmp) \ + ld8 _tmp=[ptr],0x08;; \ + mov reg=_tmp + +#define SAVE_BREAK_REGS(ptr, _idx, _breg, _dest)\ + mov ar.lc=IA64_NUM_DBG_REGS-1;; \ + mov _idx=0;; \ +1: \ + SAVE_FROM_REG(_breg[_idx], ptr, _dest);; \ + add _idx=1,_idx;; \ + br.cloop.sptk.many 1b + +#define RESTORE_BREAK_REGS(ptr, _idx, _breg, _tmp, _lbl)\ + mov ar.lc=IA64_NUM_DBG_REGS-1;; \ + mov _idx=0;; \ +_lbl: RESTORE_REG(_breg[_idx], ptr, _tmp);; \ + add _idx=1, _idx;; \ + br.cloop.sptk.many _lbl + +#define SAVE_ONE_RR(num, _reg, _tmp) \ + movl _tmp=(num<<61);; \ + mov _reg=rr[_tmp] + +#define SAVE_REGION_REGS(_tmp, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) \ + SAVE_ONE_RR(0,_r0, _tmp);; \ + SAVE_ONE_RR(1,_r1, _tmp);; \ + SAVE_ONE_RR(2,_r2, _tmp);; \ + SAVE_ONE_RR(3,_r3, _tmp);; \ + SAVE_ONE_RR(4,_r4, _tmp);; \ + SAVE_ONE_RR(5,_r5, _tmp);; \ + SAVE_ONE_RR(6,_r6, _tmp);; \ + SAVE_ONE_RR(7,_r7, _tmp);; + +#define STORE_REGION_REGS(ptr, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) \ + st8 [ptr]=_r0, 8;; \ + st8 [ptr]=_r1, 8;; \ + st8 [ptr]=_r2, 8;; \ + st8 [ptr]=_r3, 8;; \ + st8 [ptr]=_r4, 8;; \ + st8 [ptr]=_r5, 8;; \ + st8 [ptr]=_r6, 8;; \ + st8 [ptr]=_r7, 8;; + +#define RESTORE_REGION_REGS(ptr, _idx1, _idx2, _tmp) \ + mov ar.lc=0x08-1;; \ + movl _idx1=0x00;; \ +RestRR: \ + dep.z _idx2=_idx1,61,3;; \ + ld8 _tmp=[ptr],8;; \ + mov rr[_idx2]=_tmp;; \ + srlz.d;; \ + add _idx1=1,_idx1;; \ + br.cloop.sptk.few RestRR + +/* + * Adjust region registers saved before starting to save + * break regs and rest of the states that need to be preserved. + */ +#define SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(_reg1,_reg2,_pred) \ + SAVE_FROM_REG(b0,_reg1,_reg2);; \ + SAVE_FROM_REG(b1,_reg1,_reg2);; \ + SAVE_FROM_REG(b2,_reg1,_reg2);; \ + SAVE_FROM_REG(b3,_reg1,_reg2);; \ + SAVE_FROM_REG(b4,_reg1,_reg2);; \ + SAVE_FROM_REG(b5,_reg1,_reg2);; \ + st8 [_reg1]=r1,0x08;; \ + st8 [_reg1]=r12,0x08;; \ + st8 [_reg1]=r13,0x08;; \ + SAVE_FROM_REG(ar.fpsr,_reg1,_reg2);; \ + SAVE_FROM_REG(ar.pfs,_reg1,_reg2);; \ + SAVE_FROM_REG(ar.rnat,_reg1,_reg2);; \ + SAVE_FROM_REG(ar.unat,_reg1,_reg2);; \ + SAVE_FROM_REG(ar.bspstore,_reg1,_reg2);; \ + SAVE_FROM_REG(cr.dcr,_reg1,_reg2);; \ + SAVE_FROM_REG(cr.iva,_reg1,_reg2);; \ + SAVE_FROM_REG(cr.pta,_reg1,_reg2);; \ + SAVE_FROM_REG(cr.itv,_reg1,_reg2);; \ + SAVE_FROM_REG(cr.pmv,_reg1,_reg2);; \ + SAVE_FROM_REG(cr.cmcv,_reg1,_reg2);; \ + SAVE_FROM_REG(cr.lrr0,_reg1,_reg2);; \ + SAVE_FROM_REG(cr.lrr1,_reg1,_reg2);; \ + st8 [_reg1]=r4,0x08;; \ + st8 [_reg1]=r5,0x08;; \ + st8 [_reg1]=r6,0x08;; \ + st8 [_reg1]=r7,0x08;; \ + st8 [_reg1]=_pred,0x08;; \ + SAVE_FROM_REG(ar.lc, _reg1, _reg2);; \ + stf.spill.nta [_reg1]=f2,16;; \ + stf.spill.nta [_reg1]=f3,16;; \ + stf.spill.nta [_reg1]=f4,16;; \ + stf.spill.nta [_reg1]=f5,16;; \ + stf.spill.nta [_reg1]=f16,16;; \ + stf.spill.nta [_reg1]=f17,16;; \ + stf.spill.nta [_reg1]=f18,16;; \ + stf.spill.nta [_reg1]=f19,16;; \ + stf.spill.nta [_reg1]=f20,16;; \ + stf.spill.nta [_reg1]=f21,16;; \ + stf.spill.nta [_reg1]=f22,16;; \ + stf.spill.nta [_reg1]=f23,16;; \ + stf.spill.nta [_reg1]=f24,16;; \ + stf.spill.nta [_reg1]=f25,16;; \ + stf.spill.nta [_reg1]=f26,16;; \ + stf.spill.nta [_reg1]=f27,16;; \ + stf.spill.nta [_reg1]=f28,16;; \ + stf.spill.nta [_reg1]=f29,16;; \ + stf.spill.nta [_reg1]=f30,16;; \ + stf.spill.nta [_reg1]=f31,16;; + +#else +#define SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(a1,a2) +#define SAVE_REGION_REGS(_tmp, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) +#define STORE_REGION_REGS(ptr, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) +#endif + +#define SET_ONE_RR(num, pgsize, _tmp1, _tmp2, vhpt) \ + movl _tmp1=(num << 61);; \ + mov _tmp2=((ia64_rid(IA64_REGION_ID_KERNEL, (num<<61)) << 8) | (pgsize << 2) | vhpt);; \ + mov rr[_tmp1]=_tmp2 .section __special_page_section,"ax" @@ -64,6 +194,12 @@ start_ap: srlz.i ;; /* + * Save the region registers, predicate before they get clobbered + */ + SAVE_REGION_REGS(r2, r8,r9,r10,r11,r12,r13,r14,r15); + mov r25=pr;; + + /* * Initialize kernel region registers: * rr[0]: VHPT enabled, page size = PAGE_SHIFT * rr[1]: VHPT enabled, page size = PAGE_SHIFT @@ -76,32 +212,14 @@ start_ap: * We initialize all of them to prevent inadvertently assuming * something about the state of address translation early in boot. */ - mov r6=((ia64_rid(IA64_REGION_ID_KERNEL, (0<<61)) << 8) | (PAGE_SHIFT << 2) | 1) - movl r7=(0<<61) - mov r8=((ia64_rid(IA64_REGION_ID_KERNEL, (1<<61)) << 8) | (PAGE_SHIFT << 2) | 1) - movl r9=(1<<61) - mov r10=((ia64_rid(IA64_REGION_ID_KERNEL, (2<<61)) << 8) | (PAGE_SHIFT << 2) | 1) - movl r11=(2<<61) - mov r12=((ia64_rid(IA64_REGION_ID_KERNEL, (3<<61)) << 8) | (PAGE_SHIFT << 2) | 1) - movl r13=(3<<61) - mov r14=((ia64_rid(IA64_REGION_ID_KERNEL, (4<<61)) << 8) | (PAGE_SHIFT << 2) | 1) - movl r15=(4<<61) - mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, (5<<61)) << 8) | (PAGE_SHIFT << 2) | 1) - movl r17=(5<<61) - mov r18=((ia64_rid(IA64_REGION_ID_KERNEL, (6<<61)) << 8) | (IA64_GRANULE_SHIFT << 2)) - movl r19=(6<<61) - mov r20=((ia64_rid(IA64_REGION_ID_KERNEL, (7<<61)) << 8) | (IA64_GRANULE_SHIFT << 2)) - movl r21=(7<<61) - ;; - mov rr[r7]=r6 - mov rr[r9]=r8 - mov rr[r11]=r10 - mov rr[r13]=r12 - mov rr[r15]=r14 - mov rr[r17]=r16 - mov rr[r19]=r18 - mov rr[r21]=r20 - ;; + SET_ONE_RR(0, PAGE_SHIFT, r2, r16, 1);; + SET_ONE_RR(1, PAGE_SHIFT, r2, r16, 1);; + SET_ONE_RR(2, PAGE_SHIFT, r2, r16, 1);; + SET_ONE_RR(3, PAGE_SHIFT, r2, r16, 1);; + SET_ONE_RR(4, PAGE_SHIFT, r2, r16, 1);; + SET_ONE_RR(5, PAGE_SHIFT, r2, r16, 1);; + SET_ONE_RR(6, IA64_GRANULE_SHIFT, r2, r16, 0);; + SET_ONE_RR(7, IA64_GRANULE_SHIFT, r2, r16, 0);; /* * Now pin mappings into the TLB for kernel text and data */ @@ -142,6 +260,13 @@ start_ap: ;; 1: // now we are in virtual mode + movl r2=sal_state_for_booting_cpu;; + ld8 r16=[r2];; + + STORE_REGION_REGS(r16, r8,r9,r10,r11,r12,r13,r14,r15); + SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(r16,r17,r25) + ;; + // set IVT entry point---can't access I/O ports without it movl r3=ia64_ivt ;; @@ -211,12 +336,13 @@ start_ap: mov IA64_KR(CURRENT_STACK)=r16 mov r13=r2 /* - * Reserve space at the top of the stack for "struct pt_regs". Kernel threads - * don't store interesting values in that structure, but the space still needs - * to be there because time-critical stuff such as the context switching can - * be implemented more efficiently (for example, __switch_to() + * Reserve space at the top of the stack for "struct pt_regs". Kernel + * threads don't store interesting values in that structure, but the space + * still needs to be there because time-critical stuff such as the context + * switching can be implemented more efficiently (for example, __switch_to() * always sets the psr.dfh bit of the task it is switching to). */ + addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE-16,r2 addl r2=IA64_RBS_OFFSET,r2 // initialize the RSE mov ar.rsc=0 // place RSE in enforced lazy mode @@ -993,4 +1119,98 @@ END(ia64_spinlock_contention) #endif +#ifdef CONFIG_HOTPLUG_CPU +GLOBAL_ENTRY(ia64_jump_to_sal) + alloc r16=ar.pfs,1,0,0,0;; + rsm psr.i | psr.ic +{ + flushrs + srlz.i +} + tpa r25=in0 + movl r18=tlb_purge_done;; + DATA_VA_TO_PA(r18);; + mov b1=r18 // Return location + movl r18=ia64_do_tlb_purge;; + DATA_VA_TO_PA(r18);; + mov b2=r18 // doing tlb_flush work + mov ar.rsc=0 // Put RSE in enforced lazy, LE mode + movl r17=1f;; + DATA_VA_TO_PA(r17);; + mov cr.iip=r17 + movl r16=SAL_PSR_BITS_TO_SET;; + mov cr.ipsr=r16 + mov cr.ifs=r0;; + rfi;; +1: + /* + * Invalidate all TLB data/inst + */ + br.sptk.many b2;; // jump to tlb purge code + +tlb_purge_done: + RESTORE_REGION_REGS(r25, r17,r18,r19);; + RESTORE_REG(b0, r25, r17);; + RESTORE_REG(b1, r25, r17);; + RESTORE_REG(b2, r25, r17);; + RESTORE_REG(b3, r25, r17);; + RESTORE_REG(b4, r25, r17);; + RESTORE_REG(b5, r25, r17);; + ld8 r1=[r25],0x08;; + ld8 r12=[r25],0x08;; + ld8 r13=[r25],0x08;; + RESTORE_REG(ar.fpsr, r25, r17);; + RESTORE_REG(ar.pfs, r25, r17);; + RESTORE_REG(ar.rnat, r25, r17);; + RESTORE_REG(ar.unat, r25, r17);; + RESTORE_REG(ar.bspstore, r25, r17);; + RESTORE_REG(cr.dcr, r25, r17);; + RESTORE_REG(cr.iva, r25, r17);; + RESTORE_REG(cr.pta, r25, r17);; + RESTORE_REG(cr.itv, r25, r17);; + RESTORE_REG(cr.pmv, r25, r17);; + RESTORE_REG(cr.cmcv, r25, r17);; + RESTORE_REG(cr.lrr0, r25, r17);; + RESTORE_REG(cr.lrr1, r25, r17);; + ld8 r4=[r25],0x08;; + ld8 r5=[r25],0x08;; + ld8 r6=[r25],0x08;; + ld8 r7=[r25],0x08;; + ld8 r17=[r25],0x08;; + mov pr=r17,-1;; + RESTORE_REG(ar.lc, r25, r17);; + /* + * Now Restore floating point regs + */ + ldf.fill.nta f2=[r25],16;; + ldf.fill.nta f3=[r25],16;; + ldf.fill.nta f4=[r25],16;; + ldf.fill.nta f5=[r25],16;; + ldf.fill.nta f16=[r25],16;; + ldf.fill.nta f17=[r25],16;; + ldf.fill.nta f18=[r25],16;; + ldf.fill.nta f19=[r25],16;; + ldf.fill.nta f20=[r25],16;; + ldf.fill.nta f21=[r25],16;; + ldf.fill.nta f22=[r25],16;; + ldf.fill.nta f23=[r25],16;; + ldf.fill.nta f24=[r25],16;; + ldf.fill.nta f25=[r25],16;; + ldf.fill.nta f26=[r25],16;; + ldf.fill.nta f27=[r25],16;; + ldf.fill.nta f28=[r25],16;; + ldf.fill.nta f29=[r25],16;; + ldf.fill.nta f30=[r25],16;; + ldf.fill.nta f31=[r25],16;; + + /* + * Now that we have done all the register restores + * we are now ready for the big DIVE to SAL Land + */ + ssm psr.ic;; + srlz.d;; + br.ret.sptk.many b0;; +END(ia64_jump_to_sal) +#endif /* CONFIG_HOTPLUG_CPU */ + #endif /* CONFIG_SMP */ diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S index cf3f8014..ef3fd72 100644 --- a/arch/ia64/kernel/mca_asm.S +++ b/arch/ia64/kernel/mca_asm.S @@ -110,46 +110,19 @@ .global ia64_os_mca_dispatch_end .global ia64_sal_to_os_handoff_state .global ia64_os_to_sal_handoff_state + .global ia64_do_tlb_purge .text .align 16 -ia64_os_mca_dispatch: - - // Serialize all MCA processing - mov r3=1;; - LOAD_PHYSICAL(p0,r2,ia64_mca_serialize);; -ia64_os_mca_spin: - xchg8 r4=[r2],r3;; - cmp.ne p6,p0=r4,r0 -(p6) br ia64_os_mca_spin - - // Save the SAL to OS MCA handoff state as defined - // by SAL SPEC 3.0 - // NOTE : The order in which the state gets saved - // is dependent on the way the C-structure - // for ia64_mca_sal_to_os_state_t has been - // defined in include/asm/mca.h - SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2) - ;; - - // LOG PROCESSOR STATE INFO FROM HERE ON.. -begin_os_mca_dump: - br ia64_os_mca_proc_state_dump;; - -ia64_os_mca_done_dump: - - LOAD_PHYSICAL(p0,r16,ia64_sal_to_os_handoff_state+56) - ;; - ld8 r18=[r16] // Get processor state parameter on existing PALE_CHECK. - ;; - tbit.nz p6,p7=r18,60 -(p7) br.spnt done_tlb_purge_and_reload - - // The following code purges TC and TR entries. Then reload all TC entries. - // Purge percpu data TC entries. -begin_tlb_purge_and_reload: +/* + * Just the TLB purge part is moved to a separate function + * so we can re-use the code for cpu hotplug code as well + * Caller should now setup b1, so we can branch once the + * tlb flush is complete. + */ +ia64_do_tlb_purge: #define O(member) IA64_CPUINFO_##member##_OFFSET GET_THIS_PADDR(r2, cpu_info) // load phys addr of cpu_info into r2 @@ -230,6 +203,51 @@ begin_tlb_purge_and_reload: ;; srlz.i ;; + // Now branch away to caller. + br.sptk.many b1 + ;; + +ia64_os_mca_dispatch: + + // Serialize all MCA processing + mov r3=1;; + LOAD_PHYSICAL(p0,r2,ia64_mca_serialize);; +ia64_os_mca_spin: + xchg8 r4=[r2],r3;; + cmp.ne p6,p0=r4,r0 +(p6) br ia64_os_mca_spin + + // Save the SAL to OS MCA handoff state as defined + // by SAL SPEC 3.0 + // NOTE : The order in which the state gets saved + // is dependent on the way the C-structure + // for ia64_mca_sal_to_os_state_t has been + // defined in include/asm/mca.h + SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2) + ;; + + // LOG PROCESSOR STATE INFO FROM HERE ON.. +begin_os_mca_dump: + br ia64_os_mca_proc_state_dump;; + +ia64_os_mca_done_dump: + + LOAD_PHYSICAL(p0,r16,ia64_sal_to_os_handoff_state+56) + ;; + ld8 r18=[r16] // Get processor state parameter on existing PALE_CHECK. + ;; + tbit.nz p6,p7=r18,60 +(p7) br.spnt done_tlb_purge_and_reload + + // The following code purges TC and TR entries. Then reload all TC entries. + // Purge percpu data TC entries. +begin_tlb_purge_and_reload: + movl r18=ia64_reload_tr;; + LOAD_PHYSICAL(p0,r18,ia64_reload_tr);; + mov b1=r18;; + br.sptk.many ia64_do_tlb_purge;; + +ia64_reload_tr: // Finally reload the TR registers. // 1. Reload DTR/ITR registers for kernel. mov r18=KERNEL_TR_PAGE_SHIFT<<2 diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 9129338..7c43aea 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -3,6 +3,7 @@ * * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang + * 04/11/17 Ashok Raj Added CPU Hotplug Support */ #define __KERNEL_SYSCALLS__ /* see */ #include @@ -200,27 +201,20 @@ default_idle (void) static inline void play_dead(void) { extern void ia64_cpu_local_tick (void); + unsigned int this_cpu = smp_processor_id(); + /* Ack it */ __get_cpu_var(cpu_state) = CPU_DEAD; - /* We shouldn't have to disable interrupts while dead, but - * some interrupts just don't seem to go away, and this makes - * it "work" for testing purposes. */ max_xtp(); local_irq_disable(); - /* Death loop */ - while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) - cpu_relax(); - + idle_task_exit(); + ia64_jump_to_sal(&sal_boot_rendez_state[this_cpu]); /* - * Enable timer interrupts from now on - * Not required if we put processor in SAL_BOOT_RENDEZ mode. + * The above is a point of no-return, the processor is + * expected to be in SAL loop now. */ - local_flush_tlb_all(); - cpu_set(smp_processor_id(), cpu_online_map); - wmb(); - ia64_cpu_local_tick (); - local_irq_enable(); + BUG(); } #else static inline void play_dead(void) diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 5318f0c..ca1536d 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -9,6 +9,7 @@ * 02/07/31 David Mosberger Switch over to hotplug-CPU boot-sequence. * smp_boot_cpus()/smp_commence() is replaced by * smp_prepare_cpus()/__cpu_up()/smp_cpus_done(). + * 04/06/21 Ashok Raj Added CPU Hotplug Support */ #include @@ -58,6 +59,37 @@ #define Dprintk(x...) #endif +#ifdef CONFIG_HOTPLUG_CPU +/* + * Store all idle threads, this can be reused instead of creating + * a new thread. Also avoids complicated thread destroy functionality + * for idle threads. + */ +struct task_struct *idle_thread_array[NR_CPUS]; + +/* + * Global array allocated for NR_CPUS at boot time + */ +struct sal_to_os_boot sal_boot_rendez_state[NR_CPUS]; + +/* + * start_ap in head.S uses this to store current booting cpu + * info. + */ +struct sal_to_os_boot *sal_state_for_booting_cpu = &sal_boot_rendez_state[0]; + +#define set_brendez_area(x) (sal_state_for_booting_cpu = &sal_boot_rendez_state[(x)]); + +#define get_idle_for_cpu(x) (idle_thread_array[(x)]) +#define set_idle_for_cpu(x,p) (idle_thread_array[(x)] = (p)) + +#else + +#define get_idle_for_cpu(x) (NULL) +#define set_idle_for_cpu(x,p) +#define set_brendez_area(x) +#endif + /* * ITC synchronization related stuff: @@ -345,7 +377,6 @@ start_secondary (void *unused) { /* Early console may use I/O ports */ ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase)); - Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id()); efi_map_pal_code(); cpu_init(); @@ -384,6 +415,13 @@ do_boot_cpu (int sapicid, int cpu) .done = COMPLETION_INITIALIZER(c_idle.done), }; DECLARE_WORK(work, do_fork_idle, &c_idle); + + c_idle.idle = get_idle_for_cpu(cpu); + if (c_idle.idle) { + init_idle(c_idle.idle, cpu); + goto do_rest; + } + /* * We can't use kernel_thread since we must avoid to reschedule the child. */ @@ -396,10 +434,15 @@ do_boot_cpu (int sapicid, int cpu) if (IS_ERR(c_idle.idle)) panic("failed fork for CPU %d", cpu); + + set_idle_for_cpu(cpu, c_idle.idle); + +do_rest: task_for_booting_cpu = c_idle.idle; Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid); + set_brendez_area(cpu); platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); /* @@ -555,16 +598,6 @@ void __devinit smp_prepare_boot_cpu(void) #ifdef CONFIG_HOTPLUG_CPU extern void fixup_irqs(void); /* must be called with cpucontrol mutex held */ -static int __devinit cpu_enable(unsigned int cpu) -{ - per_cpu(cpu_state,cpu) = CPU_UP_PREPARE; - wmb(); - - while (!cpu_online(cpu)) - cpu_relax(); - return 0; -} - int __cpu_disable(void) { int cpu = smp_processor_id(); @@ -577,7 +610,7 @@ int __cpu_disable(void) fixup_irqs(); local_flush_tlb_all(); - printk ("Disabled cpu %u\n", smp_processor_id()); + cpu_clear(cpu, cpu_callin_map); return 0; } @@ -589,12 +622,7 @@ void __cpu_die(unsigned int cpu) /* They ack this in play_dead by setting CPU_DEAD */ if (per_cpu(cpu_state, cpu) == CPU_DEAD) { - /* - * TBD: Enable this when physical removal - * or when we put the processor is put in - * SAL_BOOT_RENDEZ mode - * cpu_clear(cpu, cpu_callin_map); - */ + printk ("CPU %d is now offline\n", cpu); return; } msleep(100); @@ -602,11 +630,6 @@ void __cpu_die(unsigned int cpu) printk(KERN_ERR "CPU %u didn't die...\n", cpu); } #else /* !CONFIG_HOTPLUG_CPU */ -static int __devinit cpu_enable(unsigned int cpu) -{ - return 0; -} - int __cpu_disable(void) { return -ENOSYS; @@ -648,16 +671,12 @@ __cpu_up (unsigned int cpu) return -EINVAL; /* - * Already booted.. just enable and get outa idle lool + * Already booted cpu? not valid anymore since we dont + * do idle loop tightspin anymore. */ if (cpu_isset(cpu, cpu_callin_map)) - { - cpu_enable(cpu); - local_irq_enable(); - while (!cpu_isset(cpu, cpu_online_map)) - mb(); - return 0; - } + return -EINVAL; + /* Processor goes to start_secondary(), sets online flag */ ret = do_boot_cpu(sapicid, cpu); if (ret < 0) diff --git a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h index ea1ed37..240676f 100644 --- a/include/asm-ia64/sal.h +++ b/include/asm-ia64/sal.h @@ -832,6 +832,44 @@ extern int ia64_sal_oemcall_nolock(struct ia64_sal_retval *, u64, u64, u64, u64, u64, u64, u64, u64); extern int ia64_sal_oemcall_reentrant(struct ia64_sal_retval *, u64, u64, u64, u64, u64, u64, u64, u64); +#ifdef CONFIG_HOTPLUG_CPU +/* + * System Abstraction Layer Specification + * Section 3.2.5.1: OS_BOOT_RENDEZ to SAL return State. + * Note: region regs are stored first in head.S _start. Hence they must + * stay up front. + */ +struct sal_to_os_boot { + u64 rr[8]; /* Region Registers */ + u64 br[6]; /* br0: return addr into SAL boot rendez routine */ + u64 gr1; /* SAL:GP */ + u64 gr12; /* SAL:SP */ + u64 gr13; /* SAL: Task Pointer */ + u64 fpsr; + u64 pfs; + u64 rnat; + u64 unat; + u64 bspstore; + u64 dcr; /* Default Control Register */ + u64 iva; + u64 pta; + u64 itv; + u64 pmv; + u64 cmcv; + u64 lrr[2]; + u64 gr[4]; + u64 pr; /* Predicate registers */ + u64 lc; /* Loop Count */ + struct ia64_fpreg fp[20]; +}; + +/* + * Global array allocated for NR_CPUS at boot time + */ +extern struct sal_to_os_boot sal_boot_rendez_state[NR_CPUS]; + +extern void ia64_jump_to_sal(struct sal_to_os_boot *); +#endif extern void ia64_sal_handler_init(void *entry_point, void *gpval); -- cgit v0.10.2 From df6c6804ce1d383c878ab071bce8125125d96abc Mon Sep 17 00:00:00 2001 From: Ashok Raj Date: Fri, 22 Apr 2005 14:46:24 -0700 Subject: [IA64] Fix build errors for !HOTPLUG case. Signed-off-by: Ashok Raj Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index 0d535d6..8d3a929 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -95,6 +95,10 @@ RestRR: \ add _idx1=1,_idx1;; \ br.cloop.sptk.few RestRR +#define SET_AREA_FOR_BOOTING_CPU(reg1, reg2) \ + movl reg1=sal_state_for_booting_cpu;; \ + ld8 reg2=[reg1];; + /* * Adjust region registers saved before starting to save * break regs and rest of the states that need to be preserved. @@ -150,7 +154,8 @@ RestRR: \ stf.spill.nta [_reg1]=f31,16;; #else -#define SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(a1,a2) +#define SET_AREA_FOR_BOOTING_CPU(a1, a2) +#define SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(a1,a2, a3) #define SAVE_REGION_REGS(_tmp, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) #define STORE_REGION_REGS(ptr, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) #endif @@ -260,8 +265,7 @@ start_ap: ;; 1: // now we are in virtual mode - movl r2=sal_state_for_booting_cpu;; - ld8 r16=[r2];; + SET_AREA_FOR_BOOTING_CPU(r2, r16); STORE_REGION_REGS(r16, r8,r9,r10,r11,r12,r13,r14,r15); SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(r16,r17,r25) -- cgit v0.10.2 From 275cfdf412aee2367883b6cd764e06c07bd37a79 Mon Sep 17 00:00:00 2001 From: Hideaki YOSHIFUJI Date: Fri, 22 Apr 2005 15:06:58 -0700 Subject: [PATCH] USB: compilation failure on usb/image/microtek.c maybe typo? Signed-off-by: Hideaki YOSHIFUJI Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index cab89a9..7d21a4f 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -335,7 +335,7 @@ static int mts_scsi_abort (Scsi_Cmnd *srb) mts_urb_abort(desc); - return FAILURE; + return FAILED; } static int mts_scsi_host_reset (Scsi_Cmnd *srb) -- cgit v0.10.2 From 35f4a0c4416b4fd789f94328dc5940e79e1507b0 Mon Sep 17 00:00:00 2001 From: Sven Anderson Date: Fri, 22 Apr 2005 15:06:58 -0700 Subject: [PATCH] USB: clean up all iPod models in unusual_devs.h Phil Dibowitz wrote: > 1. You're adding product IDs 1202, 1203, 1204, and 1205. 1203 was > already there, but you remove it, OK, but 1205 is already there, so > you'll need to fix that. I was not removing 1203, it's just the extension of the bcd range. You are right about 1205, as I wrote, it was a patch against 2.6.11.7. Attached is a patch against 2.6.12-rc2. > 2. I'm OK with the full bcd range if Apple is changing it on firmware > revs... fine, but it's bcd, not hex... 0x9999 =) I just copied from other entries. There're a lot 0xffffs in unusual_dev.h, so I assumed it is correct. I changed it to 0x9999. > 3. It's rather obnoxious to take the original submitter's credit away. I didn't remove it, I changed it to "based on...". Because I changed something (the range) in his entry, I thought it is the best to take the responsibility but keep the origin. Anyway, in the new patch I did it in a different way. > 4. Your /proc/bus/usb/devices shows 1204, but I see no evidence 1202 is > really an iPod. I don't have an old iPod mini, but you find a lot of evidence here: http://www.google.com/search?q=0x1202+ipod Especially this one: http://www.qbik.ch/usb/devices/showdescr.php?id=2737 > It also looks like 1205's entry is getting mangled, but I haven't > attempted to apply the patch, so I'm not sure. No, the patch was ok, but I agree it looks strange. It's not very readable, because I cannot tell diff to work blockwise instead of linewise. Because of the similarity of the entries, diff splits and merges them. Anyway, the new patch "looks" better. ;-) Signed-off-by: Sven Anderson Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index fa68dea..bbda63c2 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -517,14 +517,32 @@ UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110, 0 ), #endif +/* Submitted by Sven Anderson + * There are at least four ProductIDs used for iPods, so I added 0x1202 and + * 0x1204. They just need the US_FL_FIX_CAPACITY. As the bcdDevice appears + * to change with firmware updates, I changed the range to maximum for all + * iPod entries. + */ +UNUSUAL_DEV( 0x05ac, 0x1202, 0x0000, 0x9999, + "Apple", + "iPod", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Reported by Avi Kivity */ -UNUSUAL_DEV( 0x05ac, 0x1203, 0x0001, 0x0001, +UNUSUAL_DEV( 0x05ac, 0x1203, 0x0000, 0x9999, + "Apple", + "iPod", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + +UNUSUAL_DEV( 0x05ac, 0x1204, 0x0000, 0x9999, "Apple", "iPod", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), -UNUSUAL_DEV( 0x05ac, 0x1205, 0x0001, 0x0001, +UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999, "Apple", "iPod", US_SC_DEVICE, US_PR_DEVICE, NULL, -- cgit v0.10.2 From 36045fb77cb8b4043063ea54067907a1afd317b4 Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Fri, 22 Apr 2005 15:06:59 -0700 Subject: [PATCH] USB: add HP49G+ Calculator USB Serial support Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index b869076..0c4aa00 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -395,6 +395,15 @@ config USB_SERIAL_PL2303 To compile this driver as a module, choose M here: the module will be called pl2303. +config USB_SERIAL_HP4X + tristate "USB HP4x Calculators support" + depends on USB_SERIAL + help + Say Y here if you want to use an Hewlett-Packard 4x Calculator. + + To compile this driver as a module, choose M here: the + module will be called hp4x. + config USB_SERIAL_SAFE tristate "USB Safe Serial (Encapsulated) Driver (EXPERIMENTAL)" depends on USB_SERIAL && EXPERIMENTAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 351b818..b0aac47 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o +obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c new file mode 100644 index 0000000..020f9a1 --- /dev/null +++ b/drivers/usb/serial/hp4x.c @@ -0,0 +1,97 @@ +/* + * HP4x Calculators Serial USB driver + * + * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net) + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + * + * 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. + * + * See Documentation/usb/usb-serial.txt for more information on using this driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "usb-serial.h" + +/* + * Version Information + */ +#define DRIVER_VERSION "v1.00" +#define DRIVER_DESC "HP4x (48/49) Generic Serial driver" + +#define HP_VENDOR_ID 0x03f0 +#define HP49GP_PRODUCT_ID 0x0121 + +static int debug; + +static struct usb_device_id id_table [] = { + { USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver hp49gp_driver = { + .owner = THIS_MODULE, + .name = "HP4X", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, +}; + +static struct usb_serial_device_type hp49gp_device = { + .owner = THIS_MODULE, + .name = "HP4X", + .id_table = id_table, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 1, +}; + +static int __init hp49gp_init(void) +{ + int retval; + retval = usb_serial_register(&hp49gp_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&hp49gp_driver); + if (retval) + goto failed_usb_register; + info(DRIVER_DESC " " DRIVER_VERSION); + return 0; +failed_usb_register: + usb_serial_deregister(&hp49gp_device); +failed_usb_serial_register: + return retval; +} + + +static void __exit hp49gp_exit(void) +{ + usb_deregister(&hp49gp_driver); + usb_serial_deregister(&hp49gp_device); +} + + +module_init(hp49gp_init); +module_exit(hp49gp_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 35ecc486a3f1811b85b7b22196b8b7422d713b51 Mon Sep 17 00:00:00 2001 From: Greg KH Date: Fri, 22 Apr 2005 15:06:59 -0700 Subject: [PATCH] USB: fix up the HP49G+ Calculator USB Serial driver Fix compiler warnings, and remove unneeded #includes Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index 020f9a1..64d55fb 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -2,7 +2,7 @@ * HP4x Calculators Serial USB driver * * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net) - * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com) * * 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 @@ -14,17 +14,9 @@ #include #include -#include #include -#include #include -#include -#include -#include #include -#include -#include -#include #include #include "usb-serial.h" @@ -37,8 +29,6 @@ #define HP_VENDOR_ID 0x03f0 #define HP49GP_PRODUCT_ID 0x0121 -static int debug; - static struct usb_device_id id_table [] = { { USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) }, { } /* Terminating entry */ @@ -81,14 +71,12 @@ failed_usb_serial_register: return retval; } - static void __exit hp49gp_exit(void) { usb_deregister(&hp49gp_driver); usb_serial_deregister(&hp49gp_device); } - module_init(hp49gp_init); module_exit(hp49gp_exit); -- cgit v0.10.2 From cef11127ea59cc5ac8fb956c355727999c6796dc Mon Sep 17 00:00:00 2001 From: Thomas Winischhofer Date: Fri, 22 Apr 2005 15:06:59 -0700 Subject: [PATCH] USB: new SiS device id Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 57b82d5..4bdbd0c 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3105,6 +3105,7 @@ static void sisusb_disconnect(struct usb_interface *intf) static struct usb_device_id sisusb_table [] = { { USB_DEVICE(0x0711, 0x0900) }, { USB_DEVICE(0x182d, 0x021c) }, + { USB_DEVICE(0x182d, 0x0269) }, { } }; -- cgit v0.10.2 From be5e3383a95446e933be198d3025df10a072794b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 22 Apr 2005 15:07:00 -0700 Subject: [PATCH] USB: drivers/usb/input/usbkbd.c: make a function static This patch makes a needlessly global function static. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index 01514b0..7038fb9 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -133,7 +133,8 @@ resubmit: kbd->usbdev->devpath, i); } -int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static int usb_kbd_event(struct input_dev *dev, unsigned int type, + unsigned int code, int value) { struct usb_kbd *kbd = dev->private; -- cgit v0.10.2 From 7107627b04b46bce8212e6a6811add5eb8bcb476 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 22 Apr 2005 15:07:00 -0700 Subject: [PATCH] USB: drivers/usb/media/sn9c102_core.c: make 2 functions static This patch makes two needlessly global functions static. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c index 898401c..31d5740 100644 --- a/drivers/usb/media/sn9c102_core.c +++ b/drivers/usb/media/sn9c102_core.c @@ -429,7 +429,7 @@ sn9c102_i2c_try_read(struct sn9c102_device* cam, } -int +static int sn9c102_i2c_try_write(struct sn9c102_device* cam, struct sn9c102_sensor* sensor, u8 address, u8 value) { @@ -785,7 +785,7 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam) } -int sn9c102_stream_interrupt(struct sn9c102_device* cam) +static int sn9c102_stream_interrupt(struct sn9c102_device* cam) { int err = 0; diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h index 16f7483..6a7adeb 100644 --- a/drivers/usb/media/sn9c102_sensor.h +++ b/drivers/usb/media/sn9c102_sensor.h @@ -145,8 +145,6 @@ static const struct usb_device_id sn9c102_id_table[] = { \ */ /* The "try" I2C I/O versions are used when probing the sensor */ -extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, - u8 address, u8 value); extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, u8 address); -- cgit v0.10.2 From 2c47e7f37830cc83e7c77f0d5b7d4ac15105475b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 22 Apr 2005 15:07:00 -0700 Subject: [PATCH] USB: drivers/usb/media/pwc/: make code static This patch makes needlessly global code static. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/media/pwc/pwc-ctrl.c b/drivers/usb/media/pwc/pwc-ctrl.c index 26aa914..42352f5 100644 --- a/drivers/usb/media/pwc/pwc-ctrl.c +++ b/drivers/usb/media/pwc/pwc-ctrl.c @@ -418,6 +418,44 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr +static void pwc_set_image_buffer_size(struct pwc_device *pdev) +{ + int i, factor = 0, filler = 0; + + /* for PALETTE_YUV420P */ + switch(pdev->vpalette) + { + case VIDEO_PALETTE_YUV420P: + factor = 6; + filler = 128; + break; + case VIDEO_PALETTE_RAW: + factor = 6; /* can be uncompressed YUV420P */ + filler = 0; + break; + } + + /* Set sizes in bytes */ + pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; + pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; + + /* Align offset, or you'll get some very weird results in + YUV420 mode... x must be multiple of 4 (to get the Y's in + place), and y even (or you'll mixup U & V). This is less of a + problem for YUV420P. + */ + pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; + pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; + + /* Fill buffers with gray or black */ + for (i = 0; i < MAX_IMAGES; i++) { + if (pdev->image_ptr[i] != NULL) + memset(pdev->image_ptr[i], filler, pdev->view.size); + } +} + + + /** @pdev: device structure @width: viewport width @@ -475,44 +513,6 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame } -void pwc_set_image_buffer_size(struct pwc_device *pdev) -{ - int i, factor = 0, filler = 0; - - /* for PALETTE_YUV420P */ - switch(pdev->vpalette) - { - case VIDEO_PALETTE_YUV420P: - factor = 6; - filler = 128; - break; - case VIDEO_PALETTE_RAW: - factor = 6; /* can be uncompressed YUV420P */ - filler = 0; - break; - } - - /* Set sizes in bytes */ - pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; - pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; - - /* Align offset, or you'll get some very weird results in - YUV420 mode... x must be multiple of 4 (to get the Y's in - place), and y even (or you'll mixup U & V). This is less of a - problem for YUV420P. - */ - pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; - pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; - - /* Fill buffers with gray or black */ - for (i = 0; i < MAX_IMAGES; i++) { - if (pdev->image_ptr[i] != NULL) - memset(pdev->image_ptr[i], filler, pdev->view.size); - } -} - - - /* BRIGHTNESS */ int pwc_get_brightness(struct pwc_device *pdev) @@ -949,7 +949,7 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); } -int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) +static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) { unsigned char buf[2]; int ret; diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c index 100a5a4..c3c3e5a 100644 --- a/drivers/usb/media/pwc/pwc-if.c +++ b/drivers/usb/media/pwc/pwc-if.c @@ -129,7 +129,7 @@ static int default_mbufs = 2; /* Default number of mmap() buffers */ int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; static int power_save = 0; static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ - int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ +static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ static struct { int type; char serial_number[30]; diff --git a/drivers/usb/media/pwc/pwc.h b/drivers/usb/media/pwc/pwc.h index 53b516d..267869d 100644 --- a/drivers/usb/media/pwc/pwc.h +++ b/drivers/usb/media/pwc/pwc.h @@ -226,9 +226,8 @@ struct pwc_device extern "C" { #endif -/* Global variables */ +/* Global variable */ extern int pwc_trace; -extern int pwc_preferred_compression; /** functions in pwc-if.c */ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); @@ -243,8 +242,6 @@ void pwc_construct(struct pwc_device *pdev); /** Functions in pwc-ctrl.c */ /* Request a certain video mode. Returns < 0 if not possible */ extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); -/* Calculate the number of bytes per image (not frame) */ -extern void pwc_set_image_buffer_size(struct pwc_device *pdev); /* Various controls; should be obvious. Value 0..65535, or < 0 on error */ extern int pwc_get_brightness(struct pwc_device *pdev); @@ -256,7 +253,6 @@ extern int pwc_set_gamma(struct pwc_device *pdev, int value); extern int pwc_get_saturation(struct pwc_device *pdev); extern int pwc_set_saturation(struct pwc_device *pdev, int value); extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); -extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value); extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); /* Power down or up the camera; not supported by all models */ -- cgit v0.10.2 From 2e0a6b8cd27375089f8356e7f1ce2319059696eb Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 22 Apr 2005 15:07:01 -0700 Subject: [PATCH] USB: drivers/usb/net/zd1201.c: make some code static This patch makes some needlessly global code static. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index c81cd0a..f98cb2a 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -45,7 +45,7 @@ MODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded"); MODULE_DEVICE_TABLE(usb, zd1201_table); -int zd1201_fw_upload(struct usb_device *dev, int apfw) +static int zd1201_fw_upload(struct usb_device *dev, int apfw) { const struct firmware *fw_entry; char* data; @@ -111,7 +111,7 @@ exit: return err; } -void zd1201_usbfree(struct urb *urb, struct pt_regs *regs) +static void zd1201_usbfree(struct urb *urb, struct pt_regs *regs) { struct zd1201 *zd = urb->context; @@ -142,7 +142,8 @@ void zd1201_usbfree(struct urb *urb, struct pt_regs *regs) total: 4 + 2 + 2 + 2 + 2 + 4 = 16 */ -int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, int parm1, int parm2) +static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, + int parm1, int parm2) { unsigned char *command; int ret; @@ -175,7 +176,7 @@ int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, int parm1, int parm2) } /* Callback after sending out a packet */ -void zd1201_usbtx(struct urb *urb, struct pt_regs *regs) +static void zd1201_usbtx(struct urb *urb, struct pt_regs *regs) { struct zd1201 *zd = urb->context; netif_wake_queue(zd->dev); @@ -183,7 +184,7 @@ void zd1201_usbtx(struct urb *urb, struct pt_regs *regs) } /* Incomming data */ -void zd1201_usbrx(struct urb *urb, struct pt_regs *regs) +static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs) { struct zd1201 *zd = urb->context; int free = 0; @@ -613,7 +614,7 @@ static inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val) return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1)); } -int zd1201_drvr_start(struct zd1201 *zd) +static int zd1201_drvr_start(struct zd1201 *zd) { int err, i; short max; @@ -1739,7 +1740,8 @@ static const struct iw_handler_def zd1201_iw_handlers = { .private_args = (struct iw_priv_args *) zd1201_private_args, }; -int zd1201_probe(struct usb_interface *interface, const struct usb_device_id *id) +static int zd1201_probe(struct usb_interface *interface, + const struct usb_device_id *id) { struct zd1201 *zd; struct usb_device *usb; @@ -1851,7 +1853,7 @@ err_zd: return err; } -void zd1201_disconnect(struct usb_interface *interface) +static void zd1201_disconnect(struct usb_interface *interface) { struct zd1201 *zd=(struct zd1201 *)usb_get_intfdata(interface); struct hlist_node *node, *node2; @@ -1882,7 +1884,7 @@ void zd1201_disconnect(struct usb_interface *interface) kfree(zd); } -struct usb_driver zd1201_usb = { +static struct usb_driver zd1201_usb = { .owner = THIS_MODULE, .name = "zd1201", .probe = zd1201_probe, -- cgit v0.10.2 From b19dcd9341a81ff6e04fcec396f77eeb91570584 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 22 Apr 2005 15:07:01 -0700 Subject: [PATCH] USB: scripts/mod/file2alias.c: handle numeric ranges for USB bcdDevice Another attempt at that... The attached patch fixes the longstanding problem with USB bcdDevice numeric ranges incorrectly converted into patterns for MODULE_ALIAS generation. Previously it put both the lower and the upper limits into the pattern, dlXdhY, making it impossible to fnmatch against except for a few special cases, like dl*dh* or dlXdhX. The patch makes it generate multiple MODULE_ALIAS lines covering the whole range with fnmatch-able patterns. E.g. for a range between 0x0001 and 0x8345 it gives the following patterns: 000[1-9] 00[1-9]* 0[1-9]* [1-7]* 8[0-2]* 83[0-3]* 834[0-5] Since bcdDevice is 2 bytes wide = 4 digits in hex representation, the max no. of patters is 2 * 4 - 1 = 7. The values are BCD (binary-coded decimals) and not hex, so patterns using a dash seem to be safe regardless of locale collation order. The patch changes bcdDevice part of the alias from dlXdhY to dZ, but this shouldn't have big compatibility issues because fnmatch()-based modprobing hasn't yet been widely used. Besides, the most common (and almost the only working) case of dl*dh* becomes d* and thus continues to work. The patch is against 2.6.12-rc2, applies to -mm3 with an offset. The matching patch to fix the MODALIAS environment variable now generated by the usb hotplug function follows. Signed-off-by: Roman Kagan Signed-off-by: Greg Kroah-Hartman diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index d54b52d..32197ef 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -47,32 +47,31 @@ do { \ sprintf(str + strlen(str), "*"); \ } while(0) -/* Looks like "usb:vNpNdlNdhNdcNdscNdpNicNiscNipN" */ -static int do_usb_entry(const char *filename, - struct usb_device_id *id, char *alias) +/* USB is special because the bcdDevice can be matched against a numeric range */ +/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */ +static void do_usb_entry(struct usb_device_id *id, + unsigned int bcdDevice_initial, int bcdDevice_initial_digits, + unsigned char range_lo, unsigned char range_hi, + struct module *mod) { - id->match_flags = TO_NATIVE(id->match_flags); - id->idVendor = TO_NATIVE(id->idVendor); - id->idProduct = TO_NATIVE(id->idProduct); - id->bcdDevice_lo = TO_NATIVE(id->bcdDevice_lo); - id->bcdDevice_hi = TO_NATIVE(id->bcdDevice_hi); - - /* - * Some modules (visor) have empty slots as placeholder for - * run-time specification that results in catch-all alias - */ - if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass)) - return 1; - + char alias[500]; strcpy(alias, "usb:"); ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR, id->idVendor); ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT, id->idProduct); - ADD(alias, "dl", id->match_flags&USB_DEVICE_ID_MATCH_DEV_LO, - id->bcdDevice_lo); - ADD(alias, "dh", id->match_flags&USB_DEVICE_ID_MATCH_DEV_HI, - id->bcdDevice_hi); + + strcat(alias, "d"); + if (bcdDevice_initial_digits) + sprintf(alias + strlen(alias), "%0*X", + bcdDevice_initial_digits, bcdDevice_initial); + if (range_lo == range_hi) + sprintf(alias + strlen(alias), "%u", range_lo); + else if (range_lo > 0 || range_hi < 9) + sprintf(alias + strlen(alias), "[%u-%u]", range_lo, range_hi); + if (bcdDevice_initial_digits < (sizeof(id->bcdDevice_lo) * 2 - 1)) + strcat(alias, "*"); + ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, id->bDeviceClass); ADD(alias, "dsc", @@ -90,7 +89,73 @@ static int do_usb_entry(const char *filename, ADD(alias, "ip", id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, id->bInterfaceProtocol); - return 1; + + /* Always end in a wildcard, for future extension */ + if (alias[strlen(alias)-1] != '*') + strcat(alias, "*"); + buf_printf(&mod->dev_table_buf, + "MODULE_ALIAS(\"%s\");\n", alias); +} + +static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) +{ + unsigned int devlo, devhi; + unsigned char chi, clo; + int ndigits; + + id->match_flags = TO_NATIVE(id->match_flags); + id->idVendor = TO_NATIVE(id->idVendor); + id->idProduct = TO_NATIVE(id->idProduct); + + devlo = id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO ? + TO_NATIVE(id->bcdDevice_lo) : 0x0U; + devhi = id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? + TO_NATIVE(id->bcdDevice_hi) : ~0x0U; + + /* + * Some modules (visor) have empty slots as placeholder for + * run-time specification that results in catch-all alias + */ + if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass)) + return; + + /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */ + for (ndigits = sizeof(id->bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) { + clo = devlo & 0xf; + chi = devhi & 0xf; + if (chi > 9) /* it's bcd not hex */ + chi = 9; + devlo >>= 4; + devhi >>= 4; + + if (devlo == devhi || !ndigits) { + do_usb_entry(id, devlo, ndigits, clo, chi, mod); + break; + } + + if (clo > 0) + do_usb_entry(id, devlo++, ndigits, clo, 9, mod); + + if (chi < 9) + do_usb_entry(id, devhi--, ndigits, 0, chi, mod); + } +} + +static void do_usb_table(void *symval, unsigned long size, + struct module *mod) +{ + unsigned int i; + const unsigned long id_size = sizeof(struct usb_device_id); + + if (size % id_size || size < id_size) { + fprintf(stderr, "*** Warning: %s ids %lu bad size " + "(each on %lu)\n", mod->name, size, id_size); + } + /* Leave last one: it's the terminator. */ + size -= id_size; + + for (i = 0; i < size; i += id_size) + do_usb_entry_multi(symval + i, mod); } /* Looks like: ieee1394:venNmoNspNverN */ @@ -280,8 +345,8 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct pci_device_id), do_pci_entry, mod); else if (sym_is(symname, "__mod_usb_device_table")) - do_table(symval, sym->st_size, sizeof(struct usb_device_id), - do_usb_entry, mod); + /* special case to handle bcdDevice ranges */ + do_usb_table(symval, sym->st_size, mod); else if (sym_is(symname, "__mod_ieee1394_device_table")) do_table(symval, sym->st_size, sizeof(struct ieee1394_device_id), do_ieee1394_entry, mod); -- cgit v0.10.2 From fb3b4ebc0be618dbcc2326482a83c920d51af7de Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 22 Apr 2005 15:07:01 -0700 Subject: [PATCH] USB: MODALIAS change for bcdDevice The patch below adjusts the MODALIAS generated by the usb hotplug function to match the proposed change to scripts/mod/file2alias.c. Signed-off-by: Roman Kagan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index c231b4b..25cf7e9 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -611,11 +611,10 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=usb:v%04Xp%04Xdl%04Xdh%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", + "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice), - le16_to_cpu(usb_dev->descriptor.bcdDevice), usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol, @@ -626,11 +625,10 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, } else { if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=usb:v%04Xp%04Xdl%04Xdh%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*", + "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice), - le16_to_cpu(usb_dev->descriptor.bcdDevice), usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) -- cgit v0.10.2 From 7ea13c9c0e40d24c5f45a3a6bee8a2a39bfb1df4 Mon Sep 17 00:00:00 2001 From: David Hollis Date: Fri, 22 Apr 2005 15:07:02 -0700 Subject: [PATCH] usbnet: Convert ASIX code to use new status infrastructure Modify the ASIX USB Ethernet code to make use of the new status infrastructure in usbnet. Additionally, add a link_reset() handler to the struct usbnet structure to provide a generic means for a driver to perform link reset tasks such as a determining link speed and setting device flags accordingly. Signed-off-by: David Hollis Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index bbaef04..0eefc14 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -210,6 +210,7 @@ struct usbnet { # define EVENT_RX_HALT 1 # define EVENT_RX_MEMORY 2 # define EVENT_STS_SPLIT 3 +# define EVENT_LINK_RESET 4 }; // device-specific info used by the driver @@ -243,6 +244,9 @@ struct driver_info { /* for status polling */ void (*status)(struct usbnet *, struct urb *); + /* link reset handling, called from defer_kevent */ + int (*link_reset)(struct usbnet *); + /* fixup rx packet (strip framing) */ int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); @@ -304,6 +308,7 @@ static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); static u32 usbnet_get_link (struct net_device *); static u32 usbnet_get_msglevel (struct net_device *); static void usbnet_set_msglevel (struct net_device *, u32); +static void defer_kevent (struct usbnet *, int); /* mostly for PDA style devices, which are always connected if present */ static int always_connected (struct usbnet *dev) @@ -501,6 +506,7 @@ static const struct driver_info an2720_info = { #define AX_CMD_WRITE_MULTI_FILTER 0x16 #define AX_CMD_READ_NODE_ID 0x17 #define AX_CMD_READ_PHY_ID 0x19 +#define AX_CMD_READ_MEDIUM_STATUS 0x1a #define AX_CMD_WRITE_MEDIUM_MODE 0x1b #define AX_CMD_READ_MONITOR_MODE 0x1c #define AX_CMD_WRITE_MONITOR_MODE 0x1d @@ -515,11 +521,14 @@ static const struct driver_info an2720_info = { #define AX_MONITOR_MAGIC 0x04 #define AX_MONITOR_HSFS 0x10 +/* AX88172 Medium Status Register values */ +#define AX_MEDIUM_FULL_DUPLEX 0x02 +#define AX_MEDIUM_TX_ABORT_ALLOW 0x04 +#define AX_MEDIUM_FLOW_CONTROL_EN 0x10 + #define AX_MCAST_FILTER_SIZE 8 #define AX_MAX_MCAST 64 -#define AX_INTERRUPT_BUFSIZE 8 - #define AX_EEPROM_LEN 0x40 #define AX_SWRESET_CLEAR 0x00 @@ -535,15 +544,33 @@ static const struct driver_info an2720_info = { #define AX88772_IPG1_DEFAULT 0x0c #define AX88772_IPG2_DEFAULT 0x12 +#define AX88772_MEDIUM_FULL_DUPLEX 0x0002 +#define AX88772_MEDIUM_RESERVED 0x0004 +#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010 +#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020 +#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080 +#define AX88772_MEDIUM_RX_ENABLE 0x0100 +#define AX88772_MEDIUM_100MB 0x0200 +#define AX88772_MEDIUM_DEFAULT \ + (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \ + AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \ + AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE ) + #define AX_EEPROM_MAGIC 0xdeadbeef /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ struct ax8817x_data { u8 multi_filter[AX_MCAST_FILTER_SIZE]; - struct urb *int_urb; - u8 *int_buf; }; +struct ax88172_int_data { + u16 res1; + u8 link; + u16 res2; + u8 status; + u16 res3; +} __attribute__ ((packed)); + static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data) { @@ -586,25 +613,23 @@ static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) usb_free_urb(urb); } -static void ax8817x_interrupt_complete(struct urb *urb, struct pt_regs *regs) +static void ax8817x_status(struct usbnet *dev, struct urb *urb) { - struct usbnet *dev = (struct usbnet *)urb->context; - struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + struct ax88172_int_data *event; int link; - if (urb->status < 0) { - devdbg(dev,"ax8817x_interrupt_complete() failed with %d", - urb->status); - } else { - link = data->int_buf[2] & 0x01; - if (netif_carrier_ok(dev->net) != link) { - if (link) - netif_carrier_on(dev->net); - else - netif_carrier_off(dev->net); - devdbg(dev, "ax8817x - Link Status is: %d", link); - } - usb_submit_urb(data->int_urb, GFP_ATOMIC); + if (urb->actual_length < 8) + return; + + event = urb->transfer_buffer; + link = event->link & 0x01; + if (netif_carrier_ok(dev->net) != link) { + if (link) { + netif_carrier_on(dev->net); + defer_kevent (dev, EVENT_LINK_RESET ); + } else + netif_carrier_off(dev->net); + devdbg(dev, "ax8817x - Link Status is: %d", link); } } @@ -711,6 +736,20 @@ static void ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, i ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); } +static int ax88172_link_reset(struct usbnet *dev) +{ + u16 lpa; + u8 mode; + + mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN; + lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA); + if (lpa & LPA_DUPLEX) + mode |= AX_MEDIUM_FULL_DUPLEX; + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); + + return 0; +} + static void ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) { struct usbnet *dev = netdev_priv(net); @@ -824,35 +863,13 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) void *buf; int i; unsigned long gpio_bits = dev->driver_info->data; - struct ax8817x_data *data = (struct ax8817x_data *)dev->data; get_endpoints(dev,intf); - if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == NULL) { - dbg ("%s: cannot allocate interrupt URB", - dev->net->name); - ret = -ENOMEM; - goto out1; - } - - if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == NULL) { - dbg ("%s: cannot allocate memory for interrupt buffer", - dev->net->name); - ret = -ENOMEM; - goto out1; - } - memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE); - - usb_fill_int_urb (data->int_urb, dev->udev, - usb_rcvintpipe (dev->udev, 1), - data->int_buf, AX_INTERRUPT_BUFSIZE, - ax8817x_interrupt_complete, dev, - dev->udev->speed == USB_SPEED_HIGH ? 8 : 100); - buf = kmalloc(ETH_ALEN, GFP_KERNEL); if(!buf) { ret = -ENOMEM; - goto out2; + goto out1; } /* Toggle the GPIOs in a manufacturer/model specific way */ @@ -860,32 +877,32 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, (gpio_bits >> (i * 8)) & 0xff, 0, 0, buf)) < 0) - goto out3; + goto out2; msleep(5); } if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf)) < 0) { dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret); - goto out3; + goto out2; } /* Get the MAC address */ memset(buf, 0, ETH_ALEN); if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) { dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); - goto out3; + goto out2; } memcpy(dev->net->dev_addr, buf, ETH_ALEN); /* Get the PHY id */ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret); - goto out3; + goto out2; } else if (ret < 2) { /* this should always return 2 bytes */ dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret); ret = -EIO; - goto out3; + goto out2; } /* Initialize MII structure */ @@ -899,36 +916,18 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->set_multicast_list = ax8817x_set_multicast; dev->net->ethtool_ops = &ax8817x_ethtool_ops; - ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, - cpu_to_le16(BMCR_RESET)); + ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400)); + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); mii_nway_restart(&dev->mii); - if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) { - dbg("Failed to submit interrupt URB: %02x", ret); - goto out2; - } - return 0; -out3: - kfree(buf); out2: - kfree(data->int_buf); + kfree(buf); out1: - usb_free_urb(data->int_urb); return ret; } -static void ax8817x_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - struct ax8817x_data *data = (struct ax8817x_data *)dev->data; - - usb_kill_urb(data->int_urb); - usb_free_urb(data->int_urb); - kfree(data->int_buf); -} - static struct ethtool_ops ax88772_ethtool_ops = { .get_drvinfo = ax8817x_get_drvinfo, .get_link = ethtool_op_get_link, @@ -946,64 +945,44 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) { int ret; void *buf; - struct ax8817x_data *data = (struct ax8817x_data *)dev->data; get_endpoints(dev,intf); - if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) { - dbg ("Cannot allocate interrupt URB"); - ret = -ENOMEM; - goto out1; - } - - if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == NULL) { - dbg ("Cannot allocate memory for interrupt buffer"); - ret = -ENOMEM; - goto out1; - } - memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE); - - usb_fill_int_urb (data->int_urb, dev->udev, - usb_rcvintpipe (dev->udev, 1), - data->int_buf, AX_INTERRUPT_BUFSIZE, - ax8817x_interrupt_complete, dev, - dev->udev->speed == USB_SPEED_HIGH ? 8 : 100); - buf = kmalloc(6, GFP_KERNEL); if(!buf) { dbg ("Cannot allocate memory for buffer"); ret = -ENOMEM; - goto out2; + goto out1; } if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, 0x00B0, 0, 0, buf)) < 0) - goto out3; + goto out2; msleep(5); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, buf)) < 0) { dbg("Select PHY #1 failed: %d", ret); - goto out3; + goto out2; } if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, 0, 0, buf)) < 0) { dbg("Failed to power down internal PHY: %d", ret); - goto out3; + goto out2; } msleep(150); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, 0, 0, buf)) < 0) { dbg("Failed to perform software reset: %d", ret); - goto out3; + goto out2; } msleep(150); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { dbg("Failed to set Internal/External PHY reset control: %d", ret); - goto out3; + goto out2; } msleep(150); @@ -1011,27 +990,27 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0000, 0, 0, buf)) < 0) { dbg("Failed to reset RX_CTL: %d", ret); - goto out3; + goto out2; } /* Get the MAC address */ memset(buf, 0, ETH_ALEN); if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) { dbg("Failed to read MAC address: %d", ret); - goto out3; + goto out2; } memcpy(dev->net->dev_addr, buf, ETH_ALEN); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, buf)) < 0) { dbg("Enabling software MII failed: %d", ret); - goto out3; + goto out2; } if (((ret = ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 0) || (*((u16 *)buf) != 0x003b)) { dbg("Read PHY register 2 must be 0x3b00: %d", ret); - goto out3; + goto out2; } /* Initialize MII structure */ @@ -1044,26 +1023,26 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) /* Get the PHY id */ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { dbg("Error reading PHY ID: %02x", ret); - goto out3; + goto out2; } else if (ret < 2) { /* this should always return 2 bytes */ dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret); ret = -EIO; - goto out3; + goto out2; } dev->mii.phy_id = *((u8 *)buf + 1); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, 0, 0, buf)) < 0) { dbg("Set external PHY reset pin level: %d", ret); - goto out3; + goto out2; } msleep(150); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { dbg("Set Internal/External PHY reset control: %d", ret); - goto out3; + goto out2; } msleep(150); @@ -1071,25 +1050,24 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->set_multicast_list = ax8817x_set_multicast; dev->net->ethtool_ops = &ax88772_ethtool_ops; - ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, - cpu_to_le16(BMCR_RESET)); + ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA)); + ADVERTISE_ALL | ADVERTISE_CSMA); mii_nway_restart(&dev->mii); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, 0x0336, 0, 0, buf)) < 0) { + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) { dbg("Write medium mode register: %d", ret); - goto out3; + goto out2; } if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,AX88772_IPG2_DEFAULT, 0, buf)) < 0) { dbg("Write IPG,IPG1,IPG2 failed: %d", ret); - goto out3; + goto out2; } if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { dbg("Failed to set hardware MII: %02x", ret); - goto out3; + goto out2; } /* Set RX_CTL to default values with 2k buffer, and enable cactus */ @@ -1097,25 +1075,16 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, buf)) < 0) { dbg("Reset RX_CTL failed: %d", ret); - goto out3; - } - - if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) { - dbg("Failed to submit interrupt URB: %02x", ret); - goto out3; + goto out2; } kfree(buf); return 0; -out3: - kfree(buf); out2: - kfree(data->int_buf); + kfree(buf); out1: - usb_free_urb(data->int_urb); - return ret; } @@ -1213,10 +1182,29 @@ static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, return skb; } +static int ax88772_link_reset(struct usbnet *dev) +{ + u16 lpa; + u16 mode; + + mode = AX88772_MEDIUM_DEFAULT; + lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA); + + if ((lpa & LPA_DUPLEX) == 0) + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; + if ((lpa & LPA_100) == 0) + mode &= ~AX88772_MEDIUM_100MB; + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); + + return 0; +} + static const struct driver_info ax8817x_info = { .description = "ASIX AX8817x USB 2.0 Ethernet", .bind = ax8817x_bind, - .unbind = ax8817x_unbind, + .status = ax8817x_status, + .link_reset = ax88172_link_reset, + .reset = ax88172_link_reset, .flags = FLAG_ETHER, .data = 0x00130103, }; @@ -1224,7 +1212,9 @@ static const struct driver_info ax8817x_info = { static const struct driver_info dlink_dub_e100_info = { .description = "DLink DUB-E100 USB Ethernet", .bind = ax8817x_bind, - .unbind = ax8817x_unbind, + .status = ax8817x_status, + .link_reset = ax88172_link_reset, + .reset = ax88172_link_reset, .flags = FLAG_ETHER, .data = 0x009f9d9f, }; @@ -1232,7 +1222,9 @@ static const struct driver_info dlink_dub_e100_info = { static const struct driver_info netgear_fa120_info = { .description = "Netgear FA-120 USB Ethernet", .bind = ax8817x_bind, - .unbind = ax8817x_unbind, + .status = ax8817x_status, + .link_reset = ax88172_link_reset, + .reset = ax88172_link_reset, .flags = FLAG_ETHER, .data = 0x00130103, }; @@ -1240,7 +1232,9 @@ static const struct driver_info netgear_fa120_info = { static const struct driver_info hawking_uf200_info = { .description = "Hawking UF200 USB Ethernet", .bind = ax8817x_bind, - .unbind = ax8817x_unbind, + .status = ax8817x_status, + .link_reset = ax88172_link_reset, + .reset = ax88172_link_reset, .flags = FLAG_ETHER, .data = 0x001f1d1f, }; @@ -1248,7 +1242,9 @@ static const struct driver_info hawking_uf200_info = { static const struct driver_info ax88772_info = { .description = "ASIX AX88772 USB 2.0 Ethernet", .bind = ax88772_bind, - .unbind = ax8817x_unbind, + .status = ax8817x_status, + .link_reset = ax88772_link_reset, + .reset = ax88772_link_reset, .flags = FLAG_ETHER | FLAG_FRAMING_AX, .rx_fixup = ax88772_rx_fixup, .tx_fixup = ax88772_tx_fixup, @@ -3307,6 +3303,19 @@ kevent (void *data) } } + if (test_bit (EVENT_LINK_RESET, &dev->flags)) { + struct driver_info *info = dev->driver_info; + int retval = 0; + + clear_bit (EVENT_LINK_RESET, &dev->flags); + if(info->link_reset && (retval = info->link_reset(dev)) < 0) { + devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", + retval, + dev->udev->bus->bus_name, dev->udev->devpath, + info->description); + } + } + if (dev->flags) devdbg (dev, "kevent done, flags = 0x%lx", dev->flags); -- cgit v0.10.2 From f3fae6ed6aafe71826e03876ad3d4e1d3f238ec8 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 22 Apr 2005 15:07:02 -0700 Subject: [PATCH] USB: better usbnet zaurus/mdlm/... fix This is a somewhat more comprehensive fix for the problem of devices like the newer Zaurii ... or in this case some Motorola cell phones. To recap, the problem's root cause is that these devices aren't using standard USB class specifications for their network links, and so far we've had to add lots of device-specific driver entries. The vendor fix abuses the CDC MDLM descriptors (they _could_ have conformed to the spec, but didn't) and defines a "Belcarra firmware" pseudo-class. This patch recognizes that pseudo-class by the GUIDs in those descriptors, and handles the devices that just use the Zaurus framing. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 0eefc14..1748159 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1,6 +1,6 @@ /* * USB Networking Links - * Copyright (C) 2000-2003 by David Brownell + * Copyright (C) 2000-2005 by David Brownell * Copyright (C) 2002 Pavel Machek * Copyright (C) 2003-2005 David Hollis * Copyright (C) 2005 Phil Chang @@ -2657,7 +2657,7 @@ static const struct driver_info blob_info = { * All known Zaurii lie about their standards conformance. Most lie by * saying they support CDC Ethernet. Some lie and say they support CDC * MDLM (as if for access to cell phone modems). Someone, please beat - * on Sharp for a while with a cluestick. + * on Sharp (and other such vendors) for a while with a cluestick. * *-------------------------------------------------------------------------*/ @@ -2710,13 +2710,6 @@ static const struct driver_info zaurus_pxa_info = { }; #define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info) -static const struct driver_info zaurus_pxa_mdlm_info = { - .description = "Sharp Zaurus, PXA-255 based", - .flags = FLAG_FRAMING_Z, - .check_connect = always_connected, - .tx_fixup = zaurus_tx_fixup, -}; - static const struct driver_info olympus_mxl_info = { .description = "Olympus R1000", .flags = FLAG_FRAMING_Z, @@ -2727,6 +2720,133 @@ static const struct driver_info olympus_mxl_info = { }; #define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info) + +/* Some more recent products using Lineo/Belcarra code will wrongly claim + * CDC MDLM conformance. They aren't conformant: data endpoints live + * in the control interface, there's no data interface, and it's not used + * to talk to a cell phone radio. But at least we can detect these two + * pseudo-classes, rather than growing this product list with entries for + * each new nonconformant product (sigh). + */ +static const u8 safe_guid[16] = { + 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, + 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, +}; +static const u8 blan_guid[16] = { + 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70, + 0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37, +}; + +static int blan_mdlm_bind (struct usbnet *dev, struct usb_interface *intf) +{ + u8 *buf = intf->cur_altsetting->extra; + int len = intf->cur_altsetting->extralen; + struct usb_cdc_mdlm_desc *desc = NULL; + struct usb_cdc_mdlm_detail_desc *detail = NULL; + + while (len > 3) { + if (buf [1] != USB_DT_CS_INTERFACE) + goto next_desc; + + /* use bDescriptorSubType, and just verify that we get a + * "BLAN" (or "SAFE") descriptor. + */ + switch (buf [2]) { + case USB_CDC_MDLM_TYPE: + if (desc) { + dev_dbg (&intf->dev, "extra MDLM\n"); + goto bad_desc; + } + desc = (void *) buf; + if (desc->bLength != sizeof *desc) { + dev_dbg (&intf->dev, "MDLM len %u\n", + desc->bLength); + goto bad_desc; + } + /* expect bcdVersion 1.0, ignore */ + if (memcmp(&desc->bGUID, blan_guid, 16) + || memcmp(&desc->bGUID, blan_guid, 16) ) { + /* hey, this one might _really_ be MDLM! */ + dev_dbg (&intf->dev, "MDLM guid\n"); + goto bad_desc; + } + break; + case USB_CDC_MDLM_DETAIL_TYPE: + if (detail) { + dev_dbg (&intf->dev, "extra MDLM detail\n"); + goto bad_desc; + } + detail = (void *) buf; + switch (detail->bGuidDescriptorType) { + case 0: /* "SAFE" */ + if (detail->bLength != (sizeof *detail + 2)) + goto bad_detail; + break; + case 1: /* "BLAN" */ + if (detail->bLength != (sizeof *detail + 3)) + goto bad_detail; + break; + default: + goto bad_detail; + } + + /* assuming we either noticed BLAN already, or will + * find it soon, there are some data bytes here: + * - bmNetworkCapabilities (unused) + * - bmDataCapabilities (bits, see below) + * - bPad (ignored, for PADAFTER -- BLAN-only) + * bits are: + * - 0x01 -- Zaurus framing (add CRC) + * - 0x02 -- PADBEFORE + * - 0x04 -- PADAFTER + * - 0x08 -- "fermat" packet mangling (for hw bugs) + */ + if (detail->bDetailData[1] != 0x01) { + /* bmDataCapabilites == 0 would be fine too, + * but framing is minidriver-coupled for now. + */ +bad_detail: + dev_dbg (&intf->dev, + "bad MDLM detail, %d %d %d\n", + detail->bLength, + detail->bDetailData[0], + detail->bDetailData[2]); + goto bad_desc; + } + break; + } +next_desc: + len -= buf [0]; /* bLength */ + buf += buf [0]; + } + + if (!desc || !detail) { + dev_dbg (&intf->dev, "missing cdc mdlm %s%sdescriptor\n", + desc ? "" : "func ", + detail ? "" : "detail "); + goto bad_desc; + } + + /* There's probably a CDC Ethernet descriptor there, but we can't + * rely on the Ethernet address it provides since not all vendors + * bother to make it unique. Likewise there's no point in tracking + * of the CDC event notifications. + */ + return get_endpoints (dev, intf); + +bad_desc: + dev_info (&dev->udev->dev, "unsupported MDLM descriptors\n"); + return -ENODEV; +} + +static const struct driver_info bogus_mdlm_info = { + .description = "pseudo-MDLM (BLAN) device", + .flags = FLAG_FRAMING_Z, + .check_connect = always_connected, + .tx_fixup = zaurus_tx_fixup, + .bind = blan_mdlm_bind, +}; + #else /* blacklist all those devices */ @@ -4029,30 +4149,14 @@ static const struct usb_device_id products [] = { }, #ifdef CONFIG_USB_ZAURUS - /* at least some (reports vary) PXA units have very different - * lies about their standards support: they claim to be cell - * phones giving direct radio access (which they aren't). + /* At least some (reports vary) PXA units have very different lies + * about their standards support: they claim to be cell phones with + * direct access to their radios. (They don't conform to CDC MDLM.) */ { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - /* Sharp ROM v1.32 */ - .idProduct = 0x8006, /* SL-5600 */ - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, - .bInterfaceProtocol = USB_CDC_PROTO_NONE, - .driver_info = (unsigned long) &zaurus_pxa_mdlm_info, -}, { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - /* reported with some C860 units */ - .idProduct = 0x9031, /* C-860 */ - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, - .bInterfaceProtocol = USB_CDC_PROTO_NONE, - .driver_info = (unsigned long) &zaurus_pxa_mdlm_info, + USB_INTERFACE_INFO (USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &bogus_mdlm_info, }, #endif -- cgit v0.10.2 From 9719b0c298bd6a4a608843dc989a5f94cd0a7c13 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sat, 23 Apr 2005 13:16:15 -0700 Subject: [PATCH] USB: Fix for ati_remote when stealing code from ati_remote for a GPL-driver of my usbradio (because of its neat usb int transfers) I found out, that the inbuf is freed twice. I don't have the ati-remote, so I don't know it is a problem at all, but it looks strange to me anyway. Also I don't know if it has been fixed already in newer kernel versions. From: Patrick Boettcher Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 355add5..860df26 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -619,7 +619,7 @@ static void ati_remote_delete(struct ati_remote *ati_remote) if (ati_remote->outbuf) usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, - ati_remote->inbuf, ati_remote->outbuf_dma); + ati_remote->outbuf, ati_remote->outbuf_dma); if (ati_remote->irq_urb) usb_free_urb(ati_remote->irq_urb); -- cgit v0.10.2 From bc86120a85ebf553180946e8854d1993f074e9f5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 12:28:34 -0700 Subject: [PATCH] SCSI GFP fixes Somebody forgot that | has higher priority than ?:. As the result, allocation is done with bogus flags - instead of GFP_ATOMIC + possibly GFP_DMA we always get GFP_DMA and no GFP_ATOMIC. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 1a135f3..2bf1ee2 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -584,7 +584,7 @@ static int scsi_request_sense(struct scsi_cmnd *scmd) memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense)); - scsi_result = kmalloc(252, GFP_ATOMIC | (scmd->device->host->hostt->unchecked_isa_dma) ? __GFP_DMA : 0); + scsi_result = kmalloc(252, GFP_ATOMIC | ((scmd->device->host->hostt->unchecked_isa_dma) ? __GFP_DMA : 0)); if (unlikely(!scsi_result)) { diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 287d197..cca7726 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -801,7 +801,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, if (!sreq) goto out_free_sdev; result = kmalloc(256, GFP_ATOMIC | - (shost->unchecked_isa_dma) ? __GFP_DMA : 0); + ((shost->unchecked_isa_dma) ? __GFP_DMA : 0)); if (!result) goto out_free_sreq; -- cgit v0.10.2 From 01424961e621737c638e489b6a0b5e6602b02612 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 12:28:34 -0700 Subject: [PATCH] mempolicy.c GFP fix zonelist_policy() forgot to mask non-zone bits from gfp when comparing zone number with policy_zone. ACKed-by: Andi Kleen Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/mm/mempolicy.c b/mm/mempolicy.c index a3b44a6..08c41da 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -661,7 +661,7 @@ static struct zonelist *zonelist_policy(unsigned int __nocast gfp, struct mempol case MPOL_BIND: /* Lower zones don't get a policy applied */ /* Careful: current->mems_allowed might have moved */ - if (gfp >= policy_zone) + if ((gfp & GFP_ZONEMASK) >= policy_zone) if (cpuset_zonelist_valid_mems_allowed(policy->v.zonelist)) return policy->v.zonelist; /*FALL THROUGH*/ -- cgit v0.10.2 From fa732f556896836e88cd662ee7a664c4db6d080d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 12:28:34 -0700 Subject: [PATCH] msnd_pinnacle GFP fix Dumb typo - __get_free_page() takes gfp mask (in this case - GFP_KERNEL), not the page size... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index 6ba03f8..0c2db65 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c @@ -892,7 +892,7 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start) static int dsp_read(char __user *buf, size_t len) { int count = len; - char *page = (char *)__get_free_page(PAGE_SIZE); + char *page = (char *)__get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; -- cgit v0.10.2 From e3b9ab1a6da339312bb23747693805fa63e2ffd0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 12:28:35 -0700 Subject: [PATCH] missing dependency on sparc64 CONFIG_HW_CONSOLE selects vt.c; without the stuff pulled by CONFIG_VT it will not build. Normally we get both in drivers/char/Kconfig and there HW_CONSOLE depends on VT. sparc64 does not pull drivers/char/Kconfig and has that sutff in arch/sparc64/Kconfig instead. However, it forgets to add the same dependency. As the result, turning VT off [which is possible] will end up with broken build. For no good reason... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index fb11896..a72fd15 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -118,6 +118,7 @@ config VT_CONSOLE config HW_CONSOLE bool + depends on VT default y config SMP -- cgit v0.10.2 From b5a48daddc88fa0467a6ba371fcff0710781bf11 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 12:28:35 -0700 Subject: [PATCH] broken dependency for I2C_MPC All boards dealt with by I2C_MPC are 32bit. Moreover, driver simply won't build on ppc64 - it uses ppc32-only types all over the place. Dependency fixed - it's PPC32, not PPC. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a2827e4..a0018de 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -237,7 +237,7 @@ config I2C_KEYWEST config I2C_MPC tristate "MPC107/824x/85xx/52xx" - depends on I2C && PPC + depends on I2C && PPC32 help If you say yes to this option, support will be included for the built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and -- cgit v0.10.2 From 3106dbcd914d8dac4b89f52d8d51ec93526cbb95 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 12:28:35 -0700 Subject: [PATCH] __get_unaligned() turned into macro Turns __get_unaligned() and __put_unaligned into macros. That is definitely safe; leaving them as inlines breaks on e.g. alpha [try to build ncpfs there and you'll get unresolved symbols since we end up getting __get_unaligned() not inlined]. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/include/asm-generic/unaligned.h b/include/asm-generic/unaligned.h index c856a43e..6c90f0f 100644 --- a/include/asm-generic/unaligned.h +++ b/include/asm-generic/unaligned.h @@ -76,46 +76,47 @@ static inline void __ustw(__u16 val, __u16 *addr) ptr->x = val; } -static inline unsigned long __get_unaligned(const void *ptr, size_t size) -{ - unsigned long val; - switch (size) { - case 1: - val = *(const __u8 *)ptr; - break; - case 2: - val = __uldw((const __u16 *)ptr); - break; - case 4: - val = __uldl((const __u32 *)ptr); - break; - case 8: - val = __uldq((const __u64 *)ptr); - break; - default: - bad_unaligned_access_length(); - }; - return val; -} - -static inline void __put_unaligned(unsigned long val, void *ptr, size_t size) -{ - switch (size) { - case 1: - *(__u8 *)ptr = val; - break; - case 2: - __ustw(val, (__u16 *)ptr); - break; - case 4: - __ustl(val, (__u32 *)ptr); - break; - case 8: - __ustq(val, (__u64 *)ptr); - break; - default: - bad_unaligned_access_length(); - }; -} +#define __get_unaligned(ptr, size) ({ \ + const void *__gu_p = ptr; \ + unsigned long val; \ + switch (size) { \ + case 1: \ + val = *(const __u8 *)__gu_p; \ + break; \ + case 2: \ + val = __uldw(__gu_p); \ + break; \ + case 4: \ + val = __uldl(__gu_p); \ + break; \ + case 8: \ + val = __uldq(__gu_p); \ + break; \ + default: \ + bad_unaligned_access_length(); \ + }; \ + val; \ +}) + +#define __put_unaligned(val, ptr, size) \ +do { \ + void *__gu_p = ptr; \ + switch (size) { \ + case 1: \ + *(__u8 *)__gu_p = val; \ + break; \ + case 2: \ + __ustw(val, __gu_p); \ + break; \ + case 4: \ + __ustl(val, __gu_p); \ + break; \ + case 8: \ + __ustq(val, __gu_p); \ + break; \ + default: \ + bad_unaligned_access_length(); \ + }; \ +} while(0) #endif /* _ASM_GENERIC_UNALIGNED_H */ -- cgit v0.10.2 From a62e7cef1aef9f98bddd92b8f9f8f3c2fb25037b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 12:28:35 -0700 Subject: [PATCH] missing include in hisax Missing include, breaks at least on arm. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index 1ac46c26..ba1d028 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "hisax_if.h" #include "hfc4s8s_l1.h" -- cgit v0.10.2 From 461790f79028ee9bfc3dd9d9afccc7e264aff9c7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 12:28:35 -0700 Subject: [PATCH] broken dependency for floppy on ARM (!ARCH_S390 && !M68K && !IA64 && !UML) is obviously always true on ARM. Intended behaviour for ARM is "absent unless we are on RiscPC or EBSA285". So what we want is added && !ARM in the first term - without it the last part (|| ARCH_RPC || ARCH_EBSA285, that is) doesn't do anything. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index e830be1..e43e023 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -6,7 +6,7 @@ menu "Block devices" config BLK_DEV_FD tristate "Normal floppy disk support" - depends on (!ARCH_S390 && !M68K && !IA64 && !UML) || Q40 || (SUN3X && BROKEN) || ARCH_RPC || ARCH_EBSA285 + depends on (!ARCH_S390 && !M68K && !IA64 && !UML && !ARM) || Q40 || (SUN3X && BROKEN) || ARCH_RPC || ARCH_EBSA285 ---help--- If you want to use the floppy disk drive(s) of your PC under Linux, say Y. Information about this driver, especially important for IBM -- cgit v0.10.2 From fdca124a1bcc7e624f6b887c6f26153f40ee43ee Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 12:28:36 -0700 Subject: [PATCH] missing include in mthca Missing include - usual portability problems... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 5824b6d..986f218 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -35,6 +35,7 @@ #include "mthca_memfree.h" #include "mthca_dev.h" #include "mthca_cmd.h" +#include /* * We allocate in as big chunks as we can, up to a maximum of 256 KB -- cgit v0.10.2 From ef0299bf8e868c09bff13e6f3c4fc9b835f60471 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 12:28:36 -0700 Subject: [PATCH] mostek bogus sparse annotations fixed void * __iomem foo is not a pointer to iomem - it's an iomem variable containing void *. A pile of such guys in arch/sparc64/kernel/time.c, drivers/sbus/char/rtc.c and include/asm-sparc64/mostek.h turned into intended void __iomem *. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index c60785c..71b4e38 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -48,7 +48,7 @@ DEFINE_SPINLOCK(mostek_lock); DEFINE_SPINLOCK(rtc_lock); -void * __iomem mstk48t02_regs = 0UL; +void __iomem *mstk48t02_regs = NULL; #ifdef CONFIG_PCI unsigned long ds1287_regs = 0UL; #endif @@ -59,8 +59,8 @@ u64 jiffies_64 = INITIAL_JIFFIES; EXPORT_SYMBOL(jiffies_64); -static void * __iomem mstk48t08_regs; -static void * __iomem mstk48t59_regs; +static void __iomem *mstk48t08_regs; +static void __iomem *mstk48t59_regs; static int set_rtc_mmss(unsigned long); @@ -520,7 +520,7 @@ void timer_tick_interrupt(struct pt_regs *regs) /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ static void __init kick_start_clock(void) { - void * __iomem regs = mstk48t02_regs; + void __iomem *regs = mstk48t02_regs; u8 sec, tmp; int i, count; @@ -604,7 +604,7 @@ static void __init kick_start_clock(void) /* Return nonzero if the clock chip battery is low. */ static int __init has_low_battery(void) { - void * __iomem regs = mstk48t02_regs; + void __iomem *regs = mstk48t02_regs; u8 data1, data2; spin_lock_irq(&mostek_lock); @@ -623,7 +623,7 @@ static int __init has_low_battery(void) static void __init set_system_time(void) { unsigned int year, mon, day, hour, min, sec; - void * __iomem mregs = mstk48t02_regs; + void __iomem *mregs = mstk48t02_regs; #ifdef CONFIG_PCI unsigned long dregs = ds1287_regs; #else @@ -843,7 +843,7 @@ void __init clock_probe(void) !strcmp(model, "m5823")) { ds1287_regs = edev->resource[0].start; } else { - mstk48t59_regs = (void * __iomem) + mstk48t59_regs = (void __iomem *) edev->resource[0].start; mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; } @@ -866,7 +866,7 @@ try_isa_clock: !strcmp(model, "m5823")) { ds1287_regs = isadev->resource.start; } else { - mstk48t59_regs = (void * __iomem) + mstk48t59_regs = (void __iomem *) isadev->resource.start; mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; } @@ -895,16 +895,16 @@ try_isa_clock: } if(model[5] == '0' && model[6] == '2') { - mstk48t02_regs = (void * __iomem) + mstk48t02_regs = (void __iomem *) (((u64)clk_reg[0].phys_addr) | (((u64)clk_reg[0].which_io)<<32UL)); } else if(model[5] == '0' && model[6] == '8') { - mstk48t08_regs = (void * __iomem) + mstk48t08_regs = (void __iomem *) (((u64)clk_reg[0].phys_addr) | (((u64)clk_reg[0].which_io)<<32UL)); mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; } else { - mstk48t59_regs = (void * __iomem) + mstk48t59_regs = (void __iomem *) (((u64)clk_reg[0].phys_addr) | (((u64)clk_reg[0].which_io)<<32UL)); mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; @@ -1092,7 +1092,7 @@ unsigned long long sched_clock(void) static int set_rtc_mmss(unsigned long nowtime) { int real_seconds, real_minutes, chip_minutes; - void * __iomem mregs = mstk48t02_regs; + void __iomem *mregs = mstk48t02_regs; #ifdef CONFIG_PCI unsigned long dregs = ds1287_regs; #else diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c index 49d1cd9..9b988ba 100644 --- a/drivers/sbus/char/rtc.c +++ b/drivers/sbus/char/rtc.c @@ -67,7 +67,7 @@ struct rtc_time_generic { /* Retrieve the current date and time from the real time clock. */ static void get_rtc_time(struct rtc_time *t) { - void * __iomem regs = mstk48t02_regs; + void __iomem *regs = mstk48t02_regs; u8 tmp; spin_lock_irq(&mostek_lock); @@ -94,7 +94,7 @@ static void get_rtc_time(struct rtc_time *t) /* Set the current date and time inthe real time clock. */ void set_rtc_time(struct rtc_time *t) { - void * __iomem regs = mstk48t02_regs; + void __iomem *regs = mstk48t02_regs; u8 tmp; spin_lock_irq(&mostek_lock); @@ -250,7 +250,7 @@ static int __init rtc_sun_init(void) /* It is possible we are being driven by some other RTC chip * and thus another RTC driver is handling things. */ - if (mstk48t02_regs == 0) + if (!mstk48t02_regs) return -ENODEV; error = misc_register(&rtc_dev); diff --git a/include/asm-sparc64/mostek.h b/include/asm-sparc64/mostek.h index 1f9b135..09b5aba 100644 --- a/include/asm-sparc64/mostek.h +++ b/include/asm-sparc64/mostek.h @@ -38,7 +38,7 @@ * * We now deal with physical addresses for I/O to the chip. -DaveM */ -static __inline__ u8 mostek_read(void * __iomem addr) +static __inline__ u8 mostek_read(void __iomem *addr) { u8 ret; @@ -48,7 +48,7 @@ static __inline__ u8 mostek_read(void * __iomem addr) return ret; } -static __inline__ void mostek_write(void * __iomem addr, u8 val) +static __inline__ void mostek_write(void __iomem *addr, u8 val) { __asm__ __volatile__("stba %0, [%1] %2" : /* no outputs */ @@ -67,7 +67,7 @@ static __inline__ void mostek_write(void * __iomem addr, u8 val) #define MOSTEK_YEAR 0x07ffUL extern spinlock_t mostek_lock; -extern void *__iomem mstk48t02_regs; +extern void __iomem *mstk48t02_regs; /* Control register values. */ #define MSTK_CREG_WRITE 0x80 /* Must set this before placing values. */ -- cgit v0.10.2 From 28a6815979b4eff29956549d62f72582a81f041e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 14:58:08 -0700 Subject: [PATCH] ppc trivial iomem annotations: pmac_time.c Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c index 0963654..de60ccc 100644 --- a/arch/ppc/platforms/pmac_time.c +++ b/arch/ppc/platforms/pmac_time.c @@ -165,7 +165,7 @@ int __init via_calibrate_decr(void) { struct device_node *vias; - volatile unsigned char *via; + volatile unsigned char __iomem *via; int count = VIA_TIMER_FREQ_6 / 100; unsigned int dstart, dend; @@ -176,8 +176,7 @@ via_calibrate_decr(void) vias = find_devices("via"); if (vias == 0 || vias->n_addrs == 0) return 0; - via = (volatile unsigned char *) - ioremap(vias->addrs[0].address, vias->addrs[0].size); + via = ioremap(vias->addrs[0].address, vias->addrs[0].size); /* set timer 1 for continuous interrupts */ out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT); @@ -202,7 +201,7 @@ via_calibrate_decr(void) printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", tb_ticks_per_jiffy, dstart - dend); - iounmap((void*)via); + iounmap(via); return 1; } -- cgit v0.10.2 From e2178f199b341cc3e3ac86be50a54b0d8d8a132f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 14:58:08 -0700 Subject: [PATCH] ppc trivial iomem annotations: chrp Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c index 5bb6492..7d0ee30 100644 --- a/arch/ppc/platforms/chrp_pci.c +++ b/arch/ppc/platforms/chrp_pci.c @@ -129,7 +129,7 @@ static struct pci_ops rtas_pci_ops = rtas_write_config }; -volatile struct Hydra *Hydra = NULL; +volatile struct Hydra __iomem *Hydra = NULL; int __init hydra_init(void) @@ -175,13 +175,14 @@ chrp_pcibios_fixup(void) static void __init setup_python(struct pci_controller *hose, struct device_node *dev) { - u32 *reg, val; + u32 __iomem *reg; + u32 val; unsigned long addr = dev->addrs[0].address; setup_indirect_pci(hose, addr + 0xf8000, addr + 0xf8010); /* Clear the magic go-slow bit */ - reg = (u32 *) ioremap(dev->addrs[0].address + 0xf6000, 0x40); + reg = ioremap(dev->addrs[0].address + 0xf6000, 0x40); val = in_be32(®[12]); if (val & PRG_CL_RESET_VALID) { out_be32(®[12], val & ~PRG_CL_RESET_VALID); diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c index f23c4f3..57f29ab 100644 --- a/arch/ppc/platforms/chrp_setup.c +++ b/arch/ppc/platforms/chrp_setup.c @@ -356,7 +356,7 @@ static void __init chrp_find_openpic(void) struct device_node *np; int len, i; unsigned int *iranges; - void *isu; + void __iomem *isu; np = find_type_devices("open-pic"); if (np == NULL || np->n_addrs == 0) diff --git a/include/asm-ppc/hydra.h b/include/asm-ppc/hydra.h index 1134431..833a8af 100644 --- a/include/asm-ppc/hydra.h +++ b/include/asm-ppc/hydra.h @@ -51,7 +51,7 @@ struct Hydra { char OpenPIC[0x40000]; }; -extern volatile struct Hydra *Hydra; +extern volatile struct Hydra __iomem *Hydra; /* -- cgit v0.10.2 From 8e293ada7d6aaee43dd56a8077b83577dd108667 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 24 Apr 2005 14:58:08 -0700 Subject: [PATCH] ppc trivial iomem annotations: pmac_smp.c Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c index 731841f..8e049da 100644 --- a/arch/ppc/platforms/pmac_smp.c +++ b/arch/ppc/platforms/pmac_smp.c @@ -91,11 +91,11 @@ extern void __secondary_start_psurge3(void); /* Temporary horrible hack */ #define PSURGE_QUAD_BIC(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v))) /* virtual addresses for the above */ -static volatile u8 *hhead_base; -static volatile u8 *quad_base; -static volatile u32 *psurge_pri_intr; -static volatile u8 *psurge_sec_intr; -static volatile u32 *psurge_start; +static volatile u8 __iomem *hhead_base; +static volatile u8 __iomem *quad_base; +static volatile u32 __iomem *psurge_pri_intr; +static volatile u8 __iomem *psurge_sec_intr; +static volatile u32 __iomem *psurge_start; /* values for psurge_type */ #define PSURGE_NONE -1 @@ -322,10 +322,10 @@ static int __init smp_psurge_probe(void) /* All released cards using this HW design have 4 CPUs */ ncpus = 4; } else { - iounmap((void *) quad_base); + iounmap(quad_base); if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) { /* not a dual-cpu card */ - iounmap((void *) hhead_base); + iounmap(hhead_base); psurge_type = PSURGE_NONE; return 1; } -- cgit v0.10.2 From e281e3ac2b6c294d672034909883e7bb9e649ac7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sun, 24 Apr 2005 18:41:38 -0700 Subject: [NETFILTER]: Fix NAT sequence number adjustment The NAT changes in 2.6.11 changed the position where helpers are called and perform packet mangling. Before 2.6.11, a NAT helper was called before the packet was NATed and had its sequence number adjusted. Since 2.6.11, the helpers get packets with already adjusted sequence numbers. This breaks sequence number adjustment, adjust_tcp_sequence() needs the original sequence number to determine whether a packet was a retransmission and to store it for further corrections. It can't be reconstructed without more information than available, so this patch restores the old order by calling helpers from a new conntrack hook two priorities below ip_conntrack_confirm() and adjusting the sequence number from a new NAT hook one priority below ip_conntrack_confirm(). Tracked down by Phil Oester Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index c9bacf9..9e57500 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -62,6 +62,9 @@ enum nf_ip_hook_priorities { NF_IP_PRI_FILTER = 0, NF_IP_PRI_NAT_SRC = 100, NF_IP_PRI_SELINUX_LAST = 225, + NF_IP_PRI_CONNTRACK_HELPER = INT_MAX - 2, + NF_IP_PRI_NAT_SEQ_ADJUST = INT_MAX - 1, + NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, NF_IP_PRI_LAST = INT_MAX, }; diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 80a7bde..0c29ccf 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -401,6 +401,16 @@ static unsigned int ip_confirm(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { + /* We've seen it coming out the other side: confirm it */ + return ip_conntrack_confirm(pskb); +} + +static unsigned int ip_conntrack_help(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; @@ -412,9 +422,7 @@ static unsigned int ip_confirm(unsigned int hooknum, if (ret != NF_ACCEPT) return ret; } - - /* We've seen it coming out the other side: confirm it */ - return ip_conntrack_confirm(pskb); + return NF_ACCEPT; } static unsigned int ip_conntrack_defrag(unsigned int hooknum, @@ -516,13 +524,30 @@ static struct nf_hook_ops ip_conntrack_local_out_ops = { .priority = NF_IP_PRI_CONNTRACK, }; +/* helpers */ +static struct nf_hook_ops ip_conntrack_helper_out_ops = { + .hook = ip_conntrack_help, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_HELPER, +}; + +static struct nf_hook_ops ip_conntrack_helper_in_ops = { + .hook = ip_conntrack_help, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_CONNTRACK_HELPER, +}; + /* Refragmenter; last chance. */ static struct nf_hook_ops ip_conntrack_out_ops = { .hook = ip_refrag, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_POST_ROUTING, - .priority = NF_IP_PRI_LAST, + .priority = NF_IP_PRI_CONNTRACK_CONFIRM, }; static struct nf_hook_ops ip_conntrack_local_in_ops = { @@ -530,7 +555,7 @@ static struct nf_hook_ops ip_conntrack_local_in_ops = { .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_IN, - .priority = NF_IP_PRI_LAST-1, + .priority = NF_IP_PRI_CONNTRACK_CONFIRM, }; /* Sysctl support */ @@ -831,10 +856,20 @@ static int init_or_cleanup(int init) printk("ip_conntrack: can't register local out hook.\n"); goto cleanup_inops; } + ret = nf_register_hook(&ip_conntrack_helper_in_ops); + if (ret < 0) { + printk("ip_conntrack: can't register local in helper hook.\n"); + goto cleanup_inandlocalops; + } + ret = nf_register_hook(&ip_conntrack_helper_out_ops); + if (ret < 0) { + printk("ip_conntrack: can't register postrouting helper hook.\n"); + goto cleanup_helperinops; + } ret = nf_register_hook(&ip_conntrack_out_ops); if (ret < 0) { printk("ip_conntrack: can't register post-routing hook.\n"); - goto cleanup_inandlocalops; + goto cleanup_helperoutops; } ret = nf_register_hook(&ip_conntrack_local_in_ops); if (ret < 0) { @@ -860,6 +895,10 @@ static int init_or_cleanup(int init) nf_unregister_hook(&ip_conntrack_local_in_ops); cleanup_inoutandlocalops: nf_unregister_hook(&ip_conntrack_out_ops); + cleanup_helperoutops: + nf_unregister_hook(&ip_conntrack_helper_out_ops); + cleanup_helperinops: + nf_unregister_hook(&ip_conntrack_helper_in_ops); cleanup_inandlocalops: nf_unregister_hook(&ip_conntrack_local_out_ops); cleanup_inops: diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 162ceac..9fc6f93 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -356,15 +356,6 @@ unsigned int nat_packet(struct ip_conntrack *ct, unsigned long statusbit; enum ip_nat_manip_type mtype = HOOK2MANIP(hooknum); - if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) - && (hooknum == NF_IP_POST_ROUTING || hooknum == NF_IP_LOCAL_IN)) { - DEBUGP("ip_nat_core: adjusting sequence number\n"); - /* future: put this in a l4-proto specific function, - * and call this function here. */ - if (!ip_nat_seq_adjust(pskb, ct, ctinfo)) - return NF_DROP; - } - if (mtype == IP_NAT_MANIP_SRC) statusbit = IPS_SRC_NAT; else diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index dec4a74..79f56f6 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -230,6 +230,25 @@ ip_nat_local_fn(unsigned int hooknum, return ret; } +static unsigned int +ip_nat_adjust(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + ct = ip_conntrack_get(*pskb, &ctinfo); + if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { + DEBUGP("ip_nat_standalone: adjusting sequence number\n"); + if (!ip_nat_seq_adjust(pskb, ct, ctinfo)) + return NF_DROP; + } + return NF_ACCEPT; +} + /* We must be after connection tracking and before packet filtering. */ /* Before packet filtering, change destination */ @@ -250,6 +269,15 @@ static struct nf_hook_ops ip_nat_out_ops = { .priority = NF_IP_PRI_NAT_SRC, }; +/* After conntrack, adjust sequence number */ +static struct nf_hook_ops ip_nat_adjust_out_ops = { + .hook = ip_nat_adjust, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, +}; + /* Before packet filtering, change destination */ static struct nf_hook_ops ip_nat_local_out_ops = { .hook = ip_nat_local_fn, @@ -268,6 +296,16 @@ static struct nf_hook_ops ip_nat_local_in_ops = { .priority = NF_IP_PRI_NAT_SRC, }; +/* After conntrack, adjust sequence number */ +static struct nf_hook_ops ip_nat_adjust_in_ops = { + .hook = ip_nat_adjust, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, +}; + + static int init_or_cleanup(int init) { int ret = 0; @@ -296,10 +334,20 @@ static int init_or_cleanup(int init) printk("ip_nat_init: can't register out hook.\n"); goto cleanup_inops; } + ret = nf_register_hook(&ip_nat_adjust_in_ops); + if (ret < 0) { + printk("ip_nat_init: can't register adjust in hook.\n"); + goto cleanup_outops; + } + ret = nf_register_hook(&ip_nat_adjust_out_ops); + if (ret < 0) { + printk("ip_nat_init: can't register adjust out hook.\n"); + goto cleanup_adjustin_ops; + } ret = nf_register_hook(&ip_nat_local_out_ops); if (ret < 0) { printk("ip_nat_init: can't register local out hook.\n"); - goto cleanup_outops; + goto cleanup_adjustout_ops;; } ret = nf_register_hook(&ip_nat_local_in_ops); if (ret < 0) { @@ -312,6 +360,10 @@ static int init_or_cleanup(int init) nf_unregister_hook(&ip_nat_local_in_ops); cleanup_localoutops: nf_unregister_hook(&ip_nat_local_out_ops); + cleanup_adjustout_ops: + nf_unregister_hook(&ip_nat_adjust_out_ops); + cleanup_adjustin_ops: + nf_unregister_hook(&ip_nat_adjust_in_ops); cleanup_outops: nf_unregister_hook(&ip_nat_out_ops); cleanup_inops: -- cgit v0.10.2 From 3b2d59d1fc86cc7217f165100a939907802dc67c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sun, 24 Apr 2005 18:42:39 -0700 Subject: [NETFILTER]: Ignore PSH on SYN/ACK in TCP connection tracking Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index e800b16..2b87c19 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -770,6 +770,7 @@ static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] = { [TH_SYN] = 1, [TH_SYN|TH_ACK] = 1, + [TH_SYN|TH_ACK|TH_PUSH] = 1, [TH_RST] = 1, [TH_RST|TH_ACK] = 1, [TH_RST|TH_ACK|TH_PUSH] = 1, -- cgit v0.10.2 From 56cb515628e6a831bb76783f282a71f7285dad33 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 24 Apr 2005 18:53:06 -0700 Subject: [AX25] Introduce ax25_type_trans Replacing the open coded equivalents and making ax25 look more like a linux network protocol, i.e. more similar to inet. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 067b353..8945491 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -394,13 +394,11 @@ static void sp_bump(struct sixpack *sp, char cmd) if ((skb = dev_alloc_skb(count)) == NULL) goto out_mem; - skb->dev = sp->dev; ptr = skb_put(skb, count); *ptr++ = cmd; /* KISS command */ memcpy(ptr, sp->cooked_buf + 1, count); - skb->mac.raw = skb->data; - skb->protocol = htons(ETH_P_AX25); + skb->protocol = ax25_type_trans(skb, sp->dev); netif_rx(skb); sp->dev->last_rx = jiffies; sp->stats.rx_packets++; diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index e8cb87d..1c563f9 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -601,12 +601,10 @@ static void do_rxpacket(struct net_device *dev) bc->stats.rx_dropped++; return; } - skb->dev = dev; cp = skb_put(skb, pktlen); *cp++ = 0; /* KISS kludge */ memcpy(cp, bc->hdlcrx.buf, pktlen - 1); - skb->protocol = htons(ETH_P_AX25); - skb->mac.raw = skb->data; + skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; bc->stats.rx_packets++; diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index ef1a359..ba9f058 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -211,11 +211,7 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty ptr = skb_push(skb, 1); *ptr = 0; - skb->dev = dev; - skb->protocol = htons(ETH_P_AX25); - skb->mac.raw = skb->data; - skb->pkt_type = PACKET_HOST; - + skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; unlock: @@ -272,8 +268,6 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) skb = newskb; } - skb->protocol = htons(ETH_P_AX25); - ptr = skb_push(skb, 2); *ptr++ = (size + 5) % 256; @@ -287,7 +281,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) return -ENODEV; } - skb->dev = dev; + skb->protocol = ax25_type_trans(skb, dev); skb->nh.raw = skb->data; dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0); bpq->stats.tx_packets++; diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index f3269b7..f515245 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -1306,9 +1306,7 @@ static void rx_bh(void *arg) data = skb_put(skb, cb + 1); data[0] = 0; memcpy(&data[1], priv->rx_buf[i], cb); - skb->dev = priv->dev; - skb->protocol = ntohs(ETH_P_AX25); - skb->mac.raw = skb->data; + skb->protocol = ax25_type_trans(skb, priv->dev); netif_rx(skb); priv->dev->last_rx = jiffies; priv->stats.rx_packets++; diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index b89959a..b4c836e 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -174,12 +174,10 @@ static void hdlc_rx_flag(struct net_device *dev, struct hdlcdrv_state *s) s->stats.rx_dropped++; return; } - skb->dev = dev; cp = skb_put(skb, pkt_len); *cp++ = 0; /* KISS kludge */ memcpy(cp, s->hdlcrx.buffer, pkt_len - 1); - skb->protocol = htons(ETH_P_AX25); - skb->mac.raw = skb->data; + skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; s->stats.rx_packets++; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index d9ea080..6279051 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -332,12 +332,10 @@ static void ax_bump(struct ax_disp *ax) return; } - skb->dev = ax->dev; spin_lock_bh(&ax->buflock); memcpy(skb_put(skb,count), ax->rbuff, count); spin_unlock_bh(&ax->buflock); - skb->mac.raw = skb->data; - skb->protocol = htons(ETH_P_AX25); + skb->protocol = ax25_type_trans(skb, ax->dev); netif_rx(skb); ax->dev->last_rx = jiffies; ax->rx_packets++; diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index ce9e7af..ece1b1a 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1630,10 +1630,7 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) scc->dev_stat.rx_packets++; scc->dev_stat.rx_bytes += skb->len; - skb->dev = scc->dev; - skb->protocol = htons(ETH_P_AX25); - skb->mac.raw = skb->data; - skb->pkt_type = PACKET_HOST; + skb->protocol = ax25_type_trans(skb, scc->dev); netif_rx(skb); scc->dev->last_rx = jiffies; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index fd7b00f..41213ef 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -522,12 +522,10 @@ static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp) ++yp->stats.rx_dropped; } else { unsigned char *cp; - skb->dev = dev; cp = skb_put(skb, pkt_len); *cp++ = 0; /* KISS kludge */ memcpy(cp, yp->rx_buf, pkt_len - 1); - skb->protocol = htons(ETH_P_AX25); - skb->mac.raw = skb->data; + skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; ++yp->stats.rx_packets; diff --git a/include/net/ax25.h b/include/net/ax25.h index 875edbb..9e6368a 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -220,6 +220,14 @@ static __inline__ void ax25_cb_put(ax25_cb *ax25) } } +static inline unsigned short ax25_type_trans(struct sk_buff *skb, struct net_device *dev) +{ + skb->dev = dev; + skb->pkt_type = PACKET_HOST; + skb->mac.raw = skb->data; + return htons(ETH_P_AX25); +} + /* af_ax25.c */ extern struct hlist_head ax25_list; extern spinlock_t ax25_list_lock; diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c index 10ffd2b..1d4ab64 100644 --- a/net/ax25/ax25_ds_subr.c +++ b/net/ax25/ax25_ds_subr.c @@ -143,8 +143,7 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p *p++ = cmd; *p++ = param; - skb->dev = ax25_dev->dev; - skb->protocol = htons(ETH_P_AX25); + skb->protocol = ax25_type_trans(skb, ax25_dev->dev); dev_queue_xmit(skb); } diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index 94557b1..5fc048d 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -351,8 +351,7 @@ void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned char *ptr; - skb->protocol = htons(ETH_P_AX25); - skb->dev = ax25_fwd_dev(dev); + skb->protocol = ax25_type_trans(skb, ax25_fwd_dev(dev)); ptr = skb_push(skb, 1); *ptr = 0x00; /* KISS */ -- cgit v0.10.2 From e5695f0800f8450d9a48efb1424918d18093b00b Mon Sep 17 00:00:00 2001 From: chas williams Date: Sun, 24 Apr 2005 18:55:35 -0700 Subject: [ATM]: [he] Use the DMA_32BIT_MASK constant from dma-mapping.h Signed-off-by: Tobias Klauser Signed-off-by: Domen Puncer Signed-off-by: Chas Williams Signed-off-by: David S. Miller diff --git a/drivers/atm/he.c b/drivers/atm/he.c index c2c31a5..3022c54 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -371,7 +372,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) if (pci_enable_device(pci_dev)) return -EIO; - if (pci_set_dma_mask(pci_dev, HE_DMA_MASK) != 0) { + if (pci_set_dma_mask(pci_dev, DMA_32BIT_MASK) != 0) { printk(KERN_WARNING "he: no suitable dma available\n"); err = -EIO; goto init_one_failure; diff --git a/drivers/atm/he.h b/drivers/atm/he.h index 1a90385..1dc2775 100644 --- a/drivers/atm/he.h +++ b/drivers/atm/he.h @@ -380,8 +380,6 @@ struct he_vcc #define PCI_VENDOR_ID_FORE 0x1127 #define PCI_DEVICE_ID_FORE_HE 0x400 -#define HE_DMA_MASK 0xffffffff - #define GEN_CNTL_0 0x40 #define INT_PROC_ENBL (1<<25) #define SLAVE_ENDIAN_MODE (1<<16) -- cgit v0.10.2 From 18900829f32443658ca4d4793c01621c75d551c1 Mon Sep 17 00:00:00 2001 From: chas williams Date: Sun, 24 Apr 2005 18:58:15 -0700 Subject: [ATM]: [fore200e] pci doesn't use global board list; use pci_register_driver() Signed-off-by: Chas Williams Signed-off-by: David S. Miller diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 196b336..9e65bfb 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2792,8 +2792,6 @@ static void __devexit fore200e_pca_remove_one(struct pci_dev *pci_dev) fore200e = pci_get_drvdata(pci_dev); - list_del(&fore200e->entry); - fore200e_shutdown(fore200e); kfree(fore200e); pci_disable_device(pci_dev); @@ -2850,7 +2848,7 @@ fore200e_module_init(void) } #ifdef CONFIG_ATM_FORE200E_PCA - if (!pci_module_init(&fore200e_pca_driver)) + if (!pci_register_driver(&fore200e_pca_driver)) return 0; #endif -- cgit v0.10.2 From 158a0e45b69254a9ee4d7795e3b98d8c959fb799 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 24 Apr 2005 18:59:30 -0700 Subject: [SLIP]: Remove redundant NULL pointer checks prior to kfree Signed-off-by: Jesper Juhl Signed-off-by: David S. Miller diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 4ce52f5..8f7841c 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -185,15 +185,12 @@ sl_alloc_bufs(struct slip *sl, int mtu) /* Cleanup */ err_exit: #ifdef SL_INCLUDE_CSLIP - if (cbuff) - kfree(cbuff); + kfree(cbuff); if (slcomp) slhc_free(slcomp); #endif - if (xbuff) - kfree(xbuff); - if (rbuff) - kfree(rbuff); + kfree(xbuff); + kfree(rbuff); return err; } @@ -204,13 +201,13 @@ sl_free_bufs(struct slip *sl) void * tmp; /* Free all SLIP frame buffers. */ - if ((tmp = xchg(&sl->rbuff, NULL)) != NULL) - kfree(tmp); - if ((tmp = xchg(&sl->xbuff, NULL)) != NULL) - kfree(tmp); + tmp = xchg(&sl->rbuff, NULL); + kfree(tmp); + tmp = xchg(&sl->xbuff, NULL); + kfree(tmp); #ifdef SL_INCLUDE_CSLIP - if ((tmp = xchg(&sl->cbuff, NULL)) != NULL) - kfree(tmp); + tmp = xchg(&sl->cbuff, NULL); + kfree(tmp); if ((tmp = xchg(&sl->slcomp, NULL)) != NULL) slhc_free(tmp); #endif @@ -297,13 +294,10 @@ done_on_bh: spin_unlock_bh(&sl->lock); done: - if (xbuff) - kfree(xbuff); - if (rbuff) - kfree(rbuff); + kfree(xbuff); + kfree(rbuff); #ifdef SL_INCLUDE_CSLIP - if (cbuff) - kfree(cbuff); + kfree(cbuff); #endif return err; } -- cgit v0.10.2 From d5ac99a648b8c61d0c7f1c32a8ab7f1dca0123d2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 24 Apr 2005 19:12:33 -0700 Subject: [TCP]: skb pcount with MTU discovery The problem is that when doing MTU discovery, the too-large segments in the write queue will be calculated as having a pcount of >1. When tcp_write_xmit() is trying to send, tcp_snd_test() fails the cwnd test when pcount > cwnd. The segments are eventually transmitted one at a time by keepalive, but this can take a long time. This patch checks if TSO is enabled when setting pcount. Signed-off-by: John Heffner Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index 503810a..9355ae5 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1417,19 +1417,20 @@ tcp_nagle_check(const struct tcp_sock *tp, const struct sk_buff *skb, tcp_minshall_check(tp)))); } -extern void tcp_set_skb_tso_segs(struct sk_buff *, unsigned int); +extern void tcp_set_skb_tso_segs(struct sock *, struct sk_buff *); /* This checks if the data bearing packet SKB (usually sk->sk_send_head) * should be put on the wire right now. */ -static __inline__ int tcp_snd_test(const struct tcp_sock *tp, +static __inline__ int tcp_snd_test(struct sock *sk, struct sk_buff *skb, unsigned cur_mss, int nonagle) { + struct tcp_sock *tp = tcp_sk(sk); int pkts = tcp_skb_pcount(skb); if (!pkts) { - tcp_set_skb_tso_segs(skb, tp->mss_cache_std); + tcp_set_skb_tso_segs(sk, skb); pkts = tcp_skb_pcount(skb); } @@ -1490,7 +1491,7 @@ static __inline__ void __tcp_push_pending_frames(struct sock *sk, if (skb) { if (!tcp_skb_is_last(sk, skb)) nonagle = TCP_NAGLE_PUSH; - if (!tcp_snd_test(tp, skb, cur_mss, nonagle) || + if (!tcp_snd_test(sk, skb, cur_mss, nonagle) || tcp_write_xmit(sk, nonagle)) tcp_check_probe_timer(sk, tp); } @@ -1508,7 +1509,7 @@ static __inline__ int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp) struct sk_buff *skb = sk->sk_send_head; return (skb && - tcp_snd_test(tp, skb, tcp_current_mss(sk, 1), + tcp_snd_test(sk, skb, tcp_current_mss(sk, 1), tcp_skb_is_last(sk, skb) ? TCP_NAGLE_PUSH : tp->nonagle)); } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 13c14cb..a12df69 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -427,7 +427,7 @@ void tcp_push_one(struct sock *sk, unsigned cur_mss) struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb = sk->sk_send_head; - if (tcp_snd_test(tp, skb, cur_mss, TCP_NAGLE_PUSH)) { + if (tcp_snd_test(sk, skb, cur_mss, TCP_NAGLE_PUSH)) { /* Send it out now. */ TCP_SKB_CB(skb)->when = tcp_time_stamp; tcp_tso_set_push(skb); @@ -440,9 +440,12 @@ void tcp_push_one(struct sock *sk, unsigned cur_mss) } } -void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_std) +void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb) { - if (skb->len <= mss_std) { + struct tcp_sock *tp = tcp_sk(sk); + + if (skb->len <= tp->mss_cache_std || + !(sk->sk_route_caps & NETIF_F_TSO)) { /* Avoid the costly divide in the normal * non-TSO case. */ @@ -451,10 +454,10 @@ void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_std) } else { unsigned int factor; - factor = skb->len + (mss_std - 1); - factor /= mss_std; + factor = skb->len + (tp->mss_cache_std - 1); + factor /= tp->mss_cache_std; skb_shinfo(skb)->tso_segs = factor; - skb_shinfo(skb)->tso_size = mss_std; + skb_shinfo(skb)->tso_size = tp->mss_cache_std; } } @@ -525,8 +528,8 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len) } /* Fix up tso_factor for both original and new SKB. */ - tcp_set_skb_tso_segs(skb, tp->mss_cache_std); - tcp_set_skb_tso_segs(buff, tp->mss_cache_std); + tcp_set_skb_tso_segs(sk, skb); + tcp_set_skb_tso_segs(sk, buff); if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { tp->lost_out += tcp_skb_pcount(skb); @@ -601,7 +604,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) * factor and mss. */ if (tcp_skb_pcount(skb) > 1) - tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); + tcp_set_skb_tso_segs(sk, skb); return 0; } @@ -752,7 +755,7 @@ int tcp_write_xmit(struct sock *sk, int nonagle) mss_now = tcp_current_mss(sk, 1); while ((skb = sk->sk_send_head) && - tcp_snd_test(tp, skb, mss_now, + tcp_snd_test(sk, skb, mss_now, tcp_skb_is_last(sk, skb) ? nonagle : TCP_NAGLE_PUSH)) { if (skb->len > mss_now) { @@ -1676,7 +1679,7 @@ int tcp_write_wakeup(struct sock *sk) tp->mss_cache = tp->mss_cache_std; } } else if (!tcp_skb_pcount(skb)) - tcp_set_skb_tso_segs(skb, tp->mss_cache_std); + tcp_set_skb_tso_segs(sk, skb); TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; TCP_SKB_CB(skb)->when = tcp_time_stamp; -- cgit v0.10.2 From 758d11bf096ada9d38fc690c2efe5e4661685bfc Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 24 Apr 2005 19:14:36 -0700 Subject: [ATM]: ENI155P error handling fix From: Panagiotis Issaris In the ENI155P device driver in six possible failure cases the requested irq is not being released. In three of the above possible failure cases additionally there seems to be a memory leak. Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 78e34ee..10da369 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -59,7 +59,6 @@ * - doesn't support OAM cells * - eni_put_free may hang if not putting memory fragments that _complete_ * 2^n block (never happens in real life, though) - * - keeps IRQ even if initialization fails */ @@ -1802,22 +1801,22 @@ static int __devinit eni_start(struct atm_dev *dev) if (request_irq(eni_dev->irq,&eni_int,SA_SHIRQ,DEV_LABEL,dev)) { printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", dev->number,eni_dev->irq); - return -EAGAIN; + error = -EAGAIN; + goto out; } - /* @@@ should release IRQ on error */ pci_set_master(eni_dev->pci_dev); if ((error = pci_write_config_word(eni_dev->pci_dev,PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" "master (0x%02x)\n",dev->number,error); - return error; + goto free_irq; } if ((error = pci_write_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL, END_SWAP_DMA))) { printk(KERN_ERR DEV_LABEL "(itf %d): can't set endian swap " "(0x%02x)\n",dev->number,error); - return error; + goto free_irq; } /* determine addresses of internal tables */ eni_dev->vci = eni_dev->ram; @@ -1839,7 +1838,8 @@ static int __devinit eni_start(struct atm_dev *dev) if (!eni_dev->free_list) { printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n", dev->number); - return -ENOMEM; + error = -ENOMEM; + goto free_irq; } eni_dev->free_len = 0; eni_put_free(eni_dev,buf,buffer_mem); @@ -1855,17 +1855,26 @@ static int __devinit eni_start(struct atm_dev *dev) */ eni_out(0xffffffff,MID_IE); error = start_tx(dev); - if (error) return error; + if (error) goto free_list; error = start_rx(dev); - if (error) return error; + if (error) goto free_list; error = dev->phy->start(dev); - if (error) return error; + if (error) goto free_list; eni_out(eni_in(MID_MC_S) | (1 << MID_INT_SEL_SHIFT) | MID_TX_LOCK_MODE | MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE, MID_MC_S); /* Tonga uses SBus INTReq1 */ (void) eni_in(MID_ISA); /* clear Midway interrupts */ return 0; + +free_list: + kfree(eni_dev->free_list); + +free_irq: + free_irq(eni_dev->irq, eni_dev); + +out: + return error; } -- cgit v0.10.2 From ac6910e189471e6b46ecea59e7620b083329ad4f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 24 Apr 2005 20:06:16 -0700 Subject: [TG3]: Update driver version and release date. Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f65ca3b..10d4761 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -61,8 +61,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.25" -#define DRV_MODULE_RELDATE "March 24, 2005" +#define DRV_MODULE_VERSION "3.26" +#define DRV_MODULE_RELDATE "April 24, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v0.10.2 From db7530797992bb2be703f9f3cc69b1a578f812f8 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sun, 24 Apr 2005 20:10:16 -0700 Subject: [PKT_SCHED]: Introduce simple actions. And provide an example simply action in order to demonstrate usage. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller diff --git a/include/linux/tc_act/tc_defact.h b/include/linux/tc_act/tc_defact.h new file mode 100644 index 0000000..964f473 --- /dev/null +++ b/include/linux/tc_act/tc_defact.h @@ -0,0 +1,21 @@ +#ifndef __LINUX_TC_DEF_H +#define __LINUX_TC_DEF_H + +#include + +struct tc_defact +{ + tc_gen; +}; + +enum +{ + TCA_DEF_UNSPEC, + TCA_DEF_TM, + TCA_DEF_PARMS, + TCA_DEF_DATA, + __TCA_DEF_MAX +}; +#define TCA_DEF_MAX (__TCA_DEF_MAX - 1) + +#endif diff --git a/include/net/act_generic.h b/include/net/act_generic.h new file mode 100644 index 0000000..95b1207 --- /dev/null +++ b/include/net/act_generic.h @@ -0,0 +1,142 @@ +/* + * include/net/act_generic.h + * +*/ +#ifndef ACT_GENERIC_H +#define ACT_GENERIC_H +static inline int tcf_defact_release(struct tcf_defact *p, int bind) +{ + int ret = 0; + if (p) { + if (bind) { + p->bindcnt--; + } + p->refcnt--; + if (p->bindcnt <= 0 && p->refcnt <= 0) { + kfree(p->defdata); + tcf_hash_destroy(p); + ret = 1; + } + } + return ret; +} + +static inline int +alloc_defdata(struct tcf_defact *p, u32 datalen, void *defdata) +{ + p->defdata = kmalloc(datalen, GFP_KERNEL); + if (p->defdata == NULL) + return -ENOMEM; + p->datalen = datalen; + memcpy(p->defdata, defdata, datalen); + return 0; +} + +static inline int +realloc_defdata(struct tcf_defact *p, u32 datalen, void *defdata) +{ + /* safer to be just brute force for now */ + kfree(p->defdata); + return alloc_defdata(p, datalen, defdata); +} + +static inline int +tcf_defact_init(struct rtattr *rta, struct rtattr *est, + struct tc_action *a, int ovr, int bind) +{ + struct rtattr *tb[TCA_DEF_MAX]; + struct tc_defact *parm; + struct tcf_defact *p; + void *defdata; + u32 datalen = 0; + int ret = 0; + + if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0) + return -EINVAL; + + if (tb[TCA_DEF_PARMS - 1] == NULL || + RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm)) + return -EINVAL; + + parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]); + defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]); + if (defdata == NULL) + return -EINVAL; + + datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]); + if (datalen <= 0) + return -EINVAL; + + p = tcf_hash_check(parm->index, a, ovr, bind); + if (p == NULL) { + p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind); + if (p == NULL) + return -ENOMEM; + + ret = alloc_defdata(p, datalen, defdata); + if (ret < 0) { + kfree(p); + return ret; + } + ret = ACT_P_CREATED; + } else { + if (!ovr) { + tcf_defact_release(p, bind); + return -EEXIST; + } + realloc_defdata(p, datalen, defdata); + } + + spin_lock_bh(&p->lock); + p->action = parm->action; + spin_unlock_bh(&p->lock); + if (ret == ACT_P_CREATED) + tcf_hash_insert(p); + return ret; +} + +static inline int tcf_defact_cleanup(struct tc_action *a, int bind) +{ + struct tcf_defact *p = PRIV(a, defact); + + if (p != NULL) + return tcf_defact_release(p, bind); + return 0; +} + +static inline int +tcf_defact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) +{ + unsigned char *b = skb->tail; + struct tc_defact opt; + struct tcf_defact *p = PRIV(a, defact); + struct tcf_t t; + + opt.index = p->index; + opt.refcnt = p->refcnt - ref; + opt.bindcnt = p->bindcnt - bind; + opt.action = p->action; + RTA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); + RTA_PUT(skb, TCA_DEF_DATA, p->datalen, p->defdata); + t.install = jiffies_to_clock_t(jiffies - p->tm.install); + t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse); + t.expires = jiffies_to_clock_t(p->tm.expires); + RTA_PUT(skb, TCA_DEF_TM, sizeof(t), &t); + return skb->len; + +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +#define tca_use_default_ops \ + .dump = tcf_defact_dump, \ + .cleanup = tcf_defact_cleanup, \ + .init = tcf_defact_init, \ + .walk = tcf_generic_walker, \ + +#define tca_use_default_defines(name) \ + static u32 idx_gen; \ + static struct tcf_defact *tcf_##name_ht[MY_TAB_SIZE]; \ + static DEFINE_RWLOCK(##name_lock); +#endif /* _NET_ACT_GENERIC_H */ diff --git a/include/net/tc_act/tc_defact.h b/include/net/tc_act/tc_defact.h new file mode 100644 index 0000000..463aa671 --- /dev/null +++ b/include/net/tc_act/tc_defact.h @@ -0,0 +1,13 @@ +#ifndef __NET_TC_DEF_H +#define __NET_TC_DEF_H + +#include + +struct tcf_defact +{ + tca_gen(defact); + u32 datalen; + void *defdata; +}; + +#endif diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 3d1d902..9c118ba 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -506,3 +506,13 @@ config NET_CLS_POLICE Say Y to support traffic policing (bandwidth limits). Needed for ingress and egress rate limiting. +config NET_ACT_SIMP + tristate "Simple action" + depends on NET_CLS_ACT + ---help--- + You must have new iproute2 to use this feature. + This adds a very simple action for demonstration purposes + The idea is to give action authors a basic example to look at. + All this action will do is print on the console the configured + policy string followed by _ then packet count. + diff --git a/net/sched/Makefile b/net/sched/Makefile index 431e557..eb3fe58 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -6,13 +6,14 @@ obj-y := sch_generic.o obj-$(CONFIG_NET_SCHED) += sch_api.o sch_fifo.o obj-$(CONFIG_NET_CLS) += cls_api.o -obj-$(CONFIG_NET_CLS_ACT) += act_api.o +obj-$(CONFIG_NET_CLS_ACT) += act_api.o obj-$(CONFIG_NET_ACT_POLICE) += police.o obj-$(CONFIG_NET_CLS_POLICE) += police.o -obj-$(CONFIG_NET_ACT_GACT) += gact.o -obj-$(CONFIG_NET_ACT_MIRRED) += mirred.o -obj-$(CONFIG_NET_ACT_IPT) += ipt.o -obj-$(CONFIG_NET_ACT_PEDIT) += pedit.o +obj-$(CONFIG_NET_ACT_GACT) += gact.o +obj-$(CONFIG_NET_ACT_MIRRED) += mirred.o +obj-$(CONFIG_NET_ACT_IPT) += ipt.o +obj-$(CONFIG_NET_ACT_PEDIT) += pedit.o +obj-$(CONFIG_NET_ACT_SIMP) += simple.o obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o obj-$(CONFIG_NET_SCH_HPFQ) += sch_hpfq.o diff --git a/net/sched/simple.c b/net/sched/simple.c new file mode 100644 index 0000000..b0d3d15 --- /dev/null +++ b/net/sched/simple.c @@ -0,0 +1,107 @@ +/* + * net/sched/simp.c Simple example of an action + * + * 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. + * + * Authors: Jamal Hadi Salim (2005) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TCA_ACT_SIMP 22 + +/* XXX: Hide all these common elements under some macro + * probably +*/ +#include +#include + +/* use generic hash table with 8 buckets */ +#define MY_TAB_SIZE 8 +#define MY_TAB_MASK (MY_TAB_SIZE - 1) +static u32 idx_gen; +static struct tcf_defact *tcf_simp_ht[MY_TAB_SIZE]; +static DEFINE_RWLOCK(simp_lock); + +/* override the defaults */ +#define tcf_st tcf_defact +#define tc_st tc_defact +#define tcf_t_lock simp_lock +#define tcf_ht tcf_simp_ht + +#define CONFIG_NET_ACT_INIT 1 +#include +#include + +static int tcf_simp(struct sk_buff **pskb, struct tc_action *a) +{ + struct sk_buff *skb = *pskb; + struct tcf_defact *p = PRIV(a, defact); + + spin_lock(&p->lock); + p->tm.lastuse = jiffies; + p->bstats.bytes += skb->len; + p->bstats.packets++; + + /* print policy string followed by _ then packet count + * Example if this was the 3rd packet and the string was "hello" + * then it would look like "hello_3" (without quotes) + **/ + printk("simple: %s_%d\n", (char *)p->defdata, p->bstats.packets); + spin_unlock(&p->lock); + return p->action; +} + +static struct tc_action_ops act_simp_ops = { + .kind = "simple", + .type = TCA_ACT_SIMP, + .capab = TCA_CAP_NONE, + .owner = THIS_MODULE, + .act = tcf_simp, + tca_use_default_ops +}; + +MODULE_AUTHOR("Jamal Hadi Salim(2005)"); +MODULE_DESCRIPTION("Simple example action"); +MODULE_LICENSE("GPL"); + +static int __init simp_init_module(void) +{ + int ret = tcf_register_action(&act_simp_ops); + if (!ret) + printk("Simple TC action Loaded\n"); + return ret; +} + +static void __exit simp_cleanup_module(void) +{ + tcf_unregister_action(&act_simp_ops); +} + +module_init(simp_init_module); +module_exit(simp_cleanup_module); -- cgit v0.10.2 From af191367a752625b9f05a25a9a76c727b9b17cab Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Sun, 24 Apr 2005 20:12:36 -0700 Subject: [NET]: Document ->hard_start_xmit() locking in comments. Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 42344d9..7bd4cd4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1214,6 +1214,19 @@ int __skb_linearize(struct sk_buff *skb, int gfp_mask) * A negative errno code is returned on a failure. A success does not * guarantee the frame will be transmitted as it may be dropped due * to congestion or traffic shaping. + * + * ----------------------------------------------------------------------------------- + * I notice this method can also return errors from the queue disciplines, + * including NET_XMIT_DROP, which is a positive value. So, errors can also + * be positive. + * + * Regardless of the return value, the skb is consumed, so it is currently + * difficult to retry a send to this method. (You can bump the ref count + * before sending to hold a reference for retry if you are careful.) + * + * When calling this method, interrupts MUST be enabled. This is because + * the BH enable code must have IRQs enabled so that it will not deadlock. + * --BLG */ int dev_queue_xmit(struct sk_buff *skb) -- cgit v0.10.2 From aa77d26961fa4ecb11fe4209578dcd62ad15819d Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Sun, 24 Apr 2005 20:13:19 -0700 Subject: [NET]: Document ->hard_start_xmit() locking in netdevices.txt Signed-off-by: David S. Miller diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt index 1509f3a..3c0a5ba 100644 --- a/Documentation/networking/netdevices.txt +++ b/Documentation/networking/netdevices.txt @@ -51,6 +51,8 @@ dev->hard_start_xmit: set_multicast_list Context: BHs disabled Notes: netif_queue_stopped() is guaranteed false + Interrupts must be enabled when calling hard_start_xmit. + (Interrupts must also be enabled when enabling the BH handler.) Return codes: o NETDEV_TX_OK everything ok. o NETDEV_TX_BUSY Cannot transmit packet, try later -- cgit v0.10.2 From 0d3d077cd4f1154e63a9858e47fe3fb1ad0c03e5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 24 Apr 2005 20:16:19 -0700 Subject: [SELINUX]: Fix ipv6_skip_exthdr() invocation causing OOPS. The SELinux hooks invoke ipv6_skip_exthdr() with an incorrect length final argument. However, the length argument turns out to be superfluous. I was just reading ipv6_skip_exthdr and it occured to me that we can get rid of len altogether. The only place where len is used is to check whether the skb has two bytes for ipv6_opt_hdr. This check is done by skb_header_pointer/skb_copy_bits anyway. Now it might appear that we've made the code slower by deferring the check to skb_copy_bits. However, this check should not trigger in the common case so this is OK. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 87c45cb..771b47e 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -416,7 +416,7 @@ extern void ipv6_push_frag_opts(struct sk_buff *skb, u8 *proto); extern int ipv6_skip_exthdr(const struct sk_buff *, int start, - u8 *nexthdrp, int len); + u8 *nexthdrp); extern int ipv6_ext_hdr(u8 nexthdr); diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c index 6dda815..315bc1f 100644 --- a/net/ipv6/exthdrs_core.c +++ b/net/ipv6/exthdrs_core.c @@ -41,8 +41,8 @@ int ipv6_ext_hdr(u8 nexthdr) * when Linux implements ESP (and maybe AUTH) headers. * --AK * - * This function parses (probably truncated) exthdr set "hdr" - * of length "len". "nexthdrp" initially points to some place, + * This function parses (probably truncated) exthdr set "hdr". + * "nexthdrp" initially points to some place, * where type of the first header can be found. * * It skips all well-known exthdrs, and returns pointer to the start @@ -63,7 +63,7 @@ int ipv6_ext_hdr(u8 nexthdr) * --ANK (980726) */ -int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, int len) +int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp) { u8 nexthdr = *nexthdrp; @@ -71,13 +71,11 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, int len struct ipv6_opt_hdr _hdr, *hp; int hdrlen; - if (len < (int)sizeof(struct ipv6_opt_hdr)) - return -1; if (nexthdr == NEXTHDR_NONE) return -1; hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); if (hp == NULL) - BUG(); + return -1; if (nexthdr == NEXTHDR_FRAGMENT) { unsigned short _frag_off, *fp; fp = skb_header_pointer(skb, @@ -97,7 +95,6 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, int len hdrlen = ipv6_optlen(hp); nexthdr = hp->nexthdr; - len -= hdrlen; start += hdrlen; } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 87b9082..8e0f569 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -135,7 +135,7 @@ static int is_ineligible(struct sk_buff *skb) if (len < 0) return 1; - ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len); + ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr); if (ptr < 0) return 0; if (nexthdr == IPPROTO_ICMPV6) { @@ -514,7 +514,7 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr; if (ipv6_ext_hdr(nexthdr)) { /* now skip over extension headers */ - inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, skb->len - sizeof(struct ipv6hdr)); + inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr); if (inner_offset<0) return; } else { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2ae7d3c..0d37814 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2855,8 +2855,7 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad nexthdr = ip6->nexthdr; offset += sizeof(_ipv6h); - offset = ipv6_skip_exthdr(skb, offset, &nexthdr, - skb->tail - skb->head - offset); + offset = ipv6_skip_exthdr(skb, offset, &nexthdr); if (offset < 0) goto out; -- cgit v0.10.2 From c5c13fafd6548fe36b8fe9285c1912fcf96379f4 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sun, 24 Apr 2005 20:19:54 -0700 Subject: [PKT_SCHED]: improve hashing performance of cls_fw Calculate hashtable size to fit into a page instead of a hardcoded 256 buckets hash table. Results in a 1024 buckets hashtable on most systems. Replace old naive extract-8-lsb-bits algorithm with a better algorithm xor'ing 3 or 4 bit fields at the size of the hashtable array index in order to improve distribution if the majority of the lower bits are unused while keeping zero collision behaviour for the most common use case. Thanks to Wang Jian for bringing this issue to attention and to Eran Mann for the initial idea for this new algorithm. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index fdfc83a..29d8b9a 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -46,9 +46,11 @@ #include #include +#define HTSIZE (PAGE_SIZE/sizeof(struct fw_filter *)) + struct fw_head { - struct fw_filter *ht[256]; + struct fw_filter *ht[HTSIZE]; }; struct fw_filter @@ -69,7 +71,28 @@ static struct tcf_ext_map fw_ext_map = { static __inline__ int fw_hash(u32 handle) { - return handle&0xFF; + if (HTSIZE == 4096) + return ((handle >> 24) & 0xFFF) ^ + ((handle >> 12) & 0xFFF) ^ + (handle & 0xFFF); + else if (HTSIZE == 2048) + return ((handle >> 22) & 0x7FF) ^ + ((handle >> 11) & 0x7FF) ^ + (handle & 0x7FF); + else if (HTSIZE == 1024) + return ((handle >> 20) & 0x3FF) ^ + ((handle >> 10) & 0x3FF) ^ + (handle & 0x3FF); + else if (HTSIZE == 512) + return (handle >> 27) ^ + ((handle >> 18) & 0x1FF) ^ + ((handle >> 9) & 0x1FF) ^ + (handle & 0x1FF); + else if (HTSIZE == 256) { + u8 *t = (u8 *) &handle; + return t[0] ^ t[1] ^ t[2] ^ t[3]; + } else + return handle & (HTSIZE - 1); } static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp, @@ -152,7 +175,7 @@ static void fw_destroy(struct tcf_proto *tp) if (head == NULL) return; - for (h=0; h<256; h++) { + for (h=0; hht[h]) != NULL) { head->ht[h] = f->next; fw_delete_filter(tp, f); @@ -291,7 +314,7 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) if (arg->stop) return; - for (h = 0; h < 256; h++) { + for (h = 0; h < HTSIZE; h++) { struct fw_filter *f; for (f = head->ht[h]; f; f = f->next) { -- cgit v0.10.2 From edec231a8a652384cb6d61e648338aa5155f2b72 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 24 Apr 2005 20:22:28 -0700 Subject: [IPV6]: export inet6_sock_nr Please apply, SCTP/DCCP needs this when INET_REFCNT_DEBUG is set. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 768b117..53a6680 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -88,6 +88,7 @@ int sysctl_ipv6_bindv6only; #ifdef INET_REFCNT_DEBUG atomic_t inet6_sock_nr; +EXPORT_SYMBOL(inet6_sock_nr); #endif /* The inetsw table contains everything that inet_create needs to -- cgit v0.10.2 From 10158286e7b5347dce2285895c95419b9f6f8b63 Mon Sep 17 00:00:00 2001 From: Tom 'spot' Callaway Date: Sun, 24 Apr 2005 20:35:20 -0700 Subject: [SPARC]: module version cleanups Minor cleanups for sparc specific drivers (sunbmac, sunqe, sunlance, sunhme, esp) so that they have a full module version definition that is consistent with other upstream drivers. Signed-off-by: Tom 'spot' Callaway Signed-off-by: David S. Miller diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 025dcd8..f88f5e3 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -37,8 +37,18 @@ #include "sunbmac.h" +#define DRV_NAME "sunbmac" +#define DRV_VERSION "2.0" +#define DRV_RELDATE "11/24/03" +#define DRV_AUTHOR "David S. Miller (davem@redhat.com)" + static char version[] __initdata = - "sunbmac.c:v2.0 24/Nov/03 David S. Miller (davem@redhat.com)\n"; + DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; + +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION("Sun BigMAC 100baseT ethernet driver"); +MODULE_LICENSE("GPL"); #undef DEBUG_PROBE #undef DEBUG_TX @@ -1321,4 +1331,3 @@ static void __exit bigmac_cleanup(void) module_init(bigmac_probe); module_exit(bigmac_cleanup); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index d837b3c..f02fe41 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -13,9 +13,6 @@ * argument : macaddr=0x00,0x10,0x20,0x30,0x40,0x50 */ -static char version[] = - "sunhme.c:v2.02 24/Aug/2003 David S. Miller (davem@redhat.com)\n"; - #include #include #include @@ -67,15 +64,24 @@ static char version[] = #include "sunhme.h" +#define DRV_NAME "sunhme" +#define DRV_VERSION "2.02" +#define DRV_RELDATE "8/24/03" +#define DRV_AUTHOR "David S. Miller (davem@redhat.com)" + +static char version[] = + DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; -#define DRV_NAME "sunhme" +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION("Sun HappyMealEthernet(HME) 10/100baseT ethernet driver"); +MODULE_LICENSE("GPL"); static int macaddr[6]; /* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */ module_param_array(macaddr, int, NULL, 0); MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set"); -MODULE_LICENSE("GPL"); static struct happy_meal *root_happy_dev; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 62d464c..b7d87d4 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -69,9 +69,6 @@ #undef DEBUG_DRIVER -static char version[] = - "sunlance.c:v2.02 24/Aug/03 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; - static char lancestr[] = "LANCE"; #include @@ -108,6 +105,19 @@ static char lancestr[] = "LANCE"; #include /* For tpe-link-test? setting */ #include +#define DRV_NAME "sunlance" +#define DRV_VERSION "2.02" +#define DRV_RELDATE "8/24/03" +#define DRV_AUTHOR "Miguel de Icaza (miguel@nuclecu.unam.mx)" + +static char version[] = + DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; + +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION("Sun Lance ethernet driver"); +MODULE_LICENSE("GPL"); + /* Define: 2^4 Tx buffers and 2^4 Rx buffers */ #ifndef LANCE_LOG_TX_BUFFERS #define LANCE_LOG_TX_BUFFERS 4 @@ -1611,4 +1621,3 @@ static void __exit sparc_lance_cleanup(void) module_init(sparc_lance_probe); module_exit(sparc_lance_cleanup); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 37ef1b8..1f2323b 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -7,9 +7,6 @@ * Copyright (C) 1996, 1999, 2003 David S. Miller (davem@redhat.com) */ -static char version[] = - "sunqe.c:v3.0 8/24/03 David S. Miller (davem@redhat.com)\n"; - #include #include #include @@ -43,6 +40,19 @@ static char version[] = #include "sunqe.h" +#define DRV_NAME "sunqe" +#define DRV_VERSION "3.0" +#define DRV_RELDATE "8/24/03" +#define DRV_AUTHOR "David S. Miller (davem@redhat.com)" + +static char version[] = + DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; + +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION("Sun QuadEthernet 10baseT SBUS card driver"); +MODULE_LICENSE("GPL"); + static struct sunqec *root_qec_dev; static void qe_set_multicast(struct net_device *dev); @@ -1040,4 +1050,3 @@ static void __exit qec_cleanup(void) module_init(qec_probe); module_exit(qec_cleanup); -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index d8ab73b..891f97f 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -49,6 +49,8 @@ #include #include +#define DRV_VERSION "1.101" + #define DEBUG_ESP /* #define DEBUG_ESP_HME */ /* #define DEBUG_ESP_DATA */ @@ -4398,5 +4400,8 @@ static struct scsi_host_template driver_template = { #include "scsi_module.c" +MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver"); +MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); -- cgit v0.10.2 From a271c241a6036d4d583d0f47a02ba5f18b8b92b5 Mon Sep 17 00:00:00 2001 From: Tom 'spot' Callaway Date: Sun, 24 Apr 2005 20:38:02 -0700 Subject: [SPARC]: Stop-A printk cleanup This patch is incredibly trivial, but it does resolve some of the user confusion as to what "L1-A" actually is. Clarify printk message to refer to Stop-A (L1-A). Gentoo has a virtually identical patch in their kernel sources. Signed-off-by: Tom 'spot' Callaway Signed-off-by: David S. Miller diff --git a/kernel/panic.c b/kernel/panic.c index 0fa3f3a..081f746 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -102,9 +102,9 @@ NORET_TYPE void panic(const char * fmt, ...) #ifdef __sparc__ { extern int stop_a_enabled; - /* Make sure the user can actually press L1-A */ + /* Make sure the user can actually press Stop-A (L1-A) */ stop_a_enabled = 1; - printk(KERN_EMERG "Press L1-A to return to the boot prom\n"); + printk(KERN_EMERG "Press Stop-A (L1-A) to return to the boot prom\n"); } #endif #if defined(CONFIG_ARCH_S390) -- cgit v0.10.2 From 6ee7c15294985e4e722959fd4482df60cefd2cc8 Mon Sep 17 00:00:00 2001 From: Tom 'spot' Callaway Date: Sun, 24 Apr 2005 20:39:15 -0700 Subject: [SPARC]: TCX Framebuffer fixes Using the same logic as the other framebuffer fixes committed in 2.6.11, this is a set of fixes to make TCX functional on the console again. Adds the tcx_pan_display function, sets the all->info.var.{red,green,blue}.length values to 8, and runs fb_set_cmap. Also looks for the correct SUNW,tcx prom value. This patch just slipped through the cracks. Originally by: Georg Chini Signed-off-by: Tom 'spot' Callaway Signed-off-by: David S. Miller diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index e2fa9e1..1986a8b 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -36,6 +36,7 @@ static int tcx_blank(int, struct fb_info *); static int tcx_mmap(struct fb_info *, struct file *, struct vm_area_struct *); static int tcx_ioctl(struct inode *, struct file *, unsigned int, unsigned long, struct fb_info *); +static int tcx_pan_display(struct fb_var_screeninfo *, struct fb_info *); /* * Frame buffer operations @@ -45,6 +46,7 @@ static struct fb_ops tcx_ops = { .owner = THIS_MODULE, .fb_setcolreg = tcx_setcolreg, .fb_blank = tcx_blank, + .fb_pan_display = tcx_pan_display, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, @@ -153,6 +155,12 @@ static void tcx_reset (struct fb_info *info) spin_unlock_irqrestore(&par->lock, flags); } +static int tcx_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + tcx_reset(info); + return 0; +} + /** * tcx_setcolreg - Optional function. Sets a color register. * @regno: boolean, 0 copy local, 1 get_user() function @@ -366,6 +374,9 @@ static void tcx_init_one(struct sbus_dev *sdev) all->par.lowdepth = prom_getbool(sdev->prom_node, "tcx-8-bit"); sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); + all->info.var.red.length = 8; + all->info.var.green.length = 8; + all->info.var.blue.length = 8; linebytes = prom_getintdefault(sdev->prom_node, "linebytes", all->info.var.xres); @@ -439,6 +450,7 @@ static void tcx_init_one(struct sbus_dev *sdev) return; } + fb_set_cmap(&all->info.cmap, &all->info); tcx_init_fix(&all->info, linebytes); if (register_framebuffer(&all->info) < 0) { @@ -466,7 +478,7 @@ int __init tcx_init(void) return -ENODEV; for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "tcx")) + if (!strcmp(sdev->prom_name, "SUNW,tcx")) tcx_init_one(sdev); } -- cgit v0.10.2 From 77a6a22f697bbc59cd434ff999dc34162e240f16 Mon Sep 17 00:00:00 2001 From: Tom 'spot' Callaway Date: Sun, 24 Apr 2005 20:41:45 -0700 Subject: [SPARC]: Missing sparc32 ksyms This patch adds some missing sparc32 ksyms that are needed. Specifically, ___rw_read_enter, ___rw_read_exit, ___rw_write_enter, and sys_close. Signed-off-by: Tom 'spot' Callaway Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index f91b0e8..bfc04ca 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef CONFIG_PCI #include #endif @@ -89,6 +90,9 @@ extern void ___atomic24_sub(void); extern void ___set_bit(void); extern void ___clear_bit(void); extern void ___change_bit(void); +extern void ___rw_read_enter(void); +extern void ___rw_read_exit(void); +extern void ___rw_write_enter(void); /* Alias functions whose names begin with "." and export the aliases. * The module references will be fixed up by module_frob_arch_sections. @@ -121,9 +125,9 @@ EXPORT_SYMBOL(_do_write_unlock); #endif #else // XXX find what uses (or used) these. -// EXPORT_SYMBOL_PRIVATE(_rw_read_enter); -// EXPORT_SYMBOL_PRIVATE(_rw_read_exit); -// EXPORT_SYMBOL_PRIVATE(_rw_write_enter); +EXPORT_SYMBOL(___rw_read_enter); +EXPORT_SYMBOL(___rw_read_exit); +EXPORT_SYMBOL(___rw_write_enter); #endif /* semaphores */ EXPORT_SYMBOL(__up); @@ -332,3 +336,6 @@ EXPORT_SYMBOL(do_BUG); /* Sun Power Management Idle Handler */ EXPORT_SYMBOL(pm_idle); + +/* Binfmt_misc needs this */ +EXPORT_SYMBOL(sys_close); -- cgit v0.10.2 From f1dee7ea250bfef433fc46fd69a52b73349b24de Mon Sep 17 00:00:00 2001 From: Bob Breuer Date: Sun, 24 Apr 2005 20:42:45 -0700 Subject: [SPARC]: Enable sun logo on sparc32 This enables the sun linux logo to be selected on sparc32. Signed-off-by: Bob Breuer Signed-off-by: David S. Miller diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 849b47b..6ba10e3 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -45,7 +45,7 @@ config LOGO_SGI_CLUT224 config LOGO_SUN_CLUT224 bool "224-color Sun Linux logo" - depends on LOGO && (SPARC || SPARC64) + depends on LOGO && (SPARC32 || SPARC64) default y config LOGO_SUPERH_MONO -- cgit v0.10.2 From 962bd5604bf8a4d31d9204e7daf260ea93084bc0 Mon Sep 17 00:00:00 2001 From: Tom 'spot' Callaway Date: Sun, 24 Apr 2005 20:45:06 -0700 Subject: [SPARC]: More sparc32 ksyms cleanups The sparc32 ksyms is missing a few more symbols, these are primarily related to SMP, and will be needed as SMP gets beaten back into functionality. Specifically, add __cpu_data (PER_CPU), cpu_online_map, and phys_cpu_present_map. This patch assumes that the earlier "linux-2.6.11-sparc-fixksyms.patch" is applied, otherwise, it will apply with fuzz. Signed-off-by: Tom 'spot' Callaway Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index bfc04ca..1bd430d 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -148,6 +148,9 @@ EXPORT_SYMBOL(___set_bit); EXPORT_SYMBOL(___clear_bit); EXPORT_SYMBOL(___change_bit); +/* Per-CPU information table */ +EXPORT_PER_CPU_SYMBOL(__cpu_data); + #ifdef CONFIG_SMP /* IRQ implementation. */ EXPORT_SYMBOL(synchronize_irq); @@ -155,6 +158,10 @@ EXPORT_SYMBOL(synchronize_irq); /* Misc SMP information */ EXPORT_SYMBOL(__cpu_number_map); EXPORT_SYMBOL(__cpu_logical_map); + +/* CPU online map and active count. */ +EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL(phys_cpu_present_map); #endif EXPORT_SYMBOL(__udelay); -- cgit v0.10.2 From 205a7edad99d68d57dfcbf9bdda1a6fb7c33169e Mon Sep 17 00:00:00 2001 From: Tom 'spot' Callaway Date: Sun, 24 Apr 2005 20:46:00 -0700 Subject: [SPARC]: Fix mxcc warning Peter Jones uncovered this one while we were debugging the framebuffer issues. There are some references to -1 in the mxcc asm code, which should be 0xffffffff. This patch gets rid of the -1s. Signed-off-by: Tom 'spot' Callaway Signed-off-by: David S. Miller diff --git a/include/asm-sparc/mxcc.h b/include/asm-sparc/mxcc.h index efe4e84..60ef9d6 100644 --- a/include/asm-sparc/mxcc.h +++ b/include/asm-sparc/mxcc.h @@ -115,8 +115,8 @@ extern __inline__ unsigned long mxcc_get_creg(void) { unsigned long mxcc_control; - __asm__ __volatile__("set -1, %%g2\n\t" - "set -1, %%g3\n\t" + __asm__ __volatile__("set 0xffffffff, %%g2\n\t" + "set 0xffffffff, %%g3\n\t" "stda %%g2, [%1] %2\n\t" "lda [%3] %2, %0\n\t" : "=r" (mxcc_control) : -- cgit v0.10.2 From 24dc6ead53f8fcae4b1908c4ea3fea75ee844a6d Mon Sep 17 00:00:00 2001 From: Tom 'spot' Callaway Date: Sun, 24 Apr 2005 20:46:49 -0700 Subject: [SPARC]: dump_stack for sparc Bob Breuer wrote a patch to add dump_stack for sparc. Supposedly, this was applied, but it doesn't exist in 2.6.11. This is the same patch, rediffed against 2.6.11. Signed-off-by: Tom 'spot' Callaway Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 143fe2f..066e253 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -333,6 +333,17 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp) printk("\n"); } +void dump_stack(void) +{ + unsigned long *ksp; + + __asm__ __volatile__("mov %%fp, %0" + : "=r" (ksp)); + show_stack(current, ksp); +} + +EXPORT_SYMBOL(dump_stack); + /* * Note: sparc64 has a pretty intricated thread_saved_pc, check it out. */ -- cgit v0.10.2 From 9a59c1860d01b3dea9ab01d5cefb9d5c52042e6d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 24 Apr 2005 21:04:02 -0700 Subject: [SPARC64]: Fix SMP build. Kill build failures in the SMP+!PREEMPT case introduced by Al Viro's spinlock.h changes. Signed-off-by: David S. Miller diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h index d1f91a4..db7581b 100644 --- a/include/asm-sparc64/spinlock.h +++ b/include/asm-sparc64/spinlock.h @@ -44,7 +44,7 @@ typedef struct { #define spin_unlock_wait(lp) \ do { membar("#LoadLoad"); \ -} while(lp->lock) +} while((lp)->lock) static inline void _raw_spin_lock(spinlock_t *lock) { @@ -149,7 +149,7 @@ typedef struct { unsigned int break_lock; #endif } rwlock_t; -#define RW_LOCK_UNLOCKED {0,} +#define RW_LOCK_UNLOCKED (rwlock_t) {0,} #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) static void inline __read_lock(rwlock_t *lock) -- cgit v0.10.2 From 9090e001f28de4bccae232f1b78e78fad5132ecb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 07:55:57 -0700 Subject: [PATCH] ppc user annotations: sigcontext sigcontext.regs is a userland pointer Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 645eae1..d500f5e 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -632,7 +632,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) || __put_user(oldset->sig[0], &sc->oldmask) || __put_user(oldset->sig[1], &sc->_unused[3]) - || __put_user((struct pt_regs *)frame, &sc->regs) + || __put_user((struct pt_regs __user *)frame, &sc->regs) || __put_user(sig, &sc->signal)) goto badframe; diff --git a/include/asm-ppc/sigcontext.h b/include/asm-ppc/sigcontext.h index fc5e358..f82dccc 100644 --- a/include/asm-ppc/sigcontext.h +++ b/include/asm-ppc/sigcontext.h @@ -9,7 +9,7 @@ struct sigcontext { int signal; unsigned long handler; unsigned long oldmask; - struct pt_regs *regs; + struct pt_regs __user *regs; }; #endif -- cgit v0.10.2 From 92a11f9e7cb876e6cf9080e4a1642142cb9221b2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 07:55:57 -0700 Subject: [PATCH] ppc iomem annotations: ->io_base_virt * ->io_base_virt in struct pci_controller is iomem pointer. Marked as such. Most of the places that used it are already annotated to expect iomem. * places that did gratitious (and wrong) casts a-la isa_io_base = (unsigned long)ioremap(...); hose->io_base_virt = (void *)isa_io_base; turned into hose->io_base_virt = ioremap(...); isa_io_base = (unsigned long)hose->io_base_virt; * pci_bus_io_base() annotated as returning iomem pointer. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 98f94b6..47a1530 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1432,7 +1432,7 @@ pci_bus_to_hose(int bus) return NULL; } -void* +void __iomem * pci_bus_io_base(unsigned int bus) { struct pci_controller *hose; diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c index f63bca8..55120c3 100644 --- a/arch/ppc/platforms/4xx/ebony.c +++ b/arch/ppc/platforms/4xx/ebony.c @@ -210,9 +210,8 @@ ebony_setup_hose(void) hose->io_space.end = EBONY_PCI_UPPER_IO; hose->mem_space.start = EBONY_PCI_LOWER_MEM; hose->mem_space.end = EBONY_PCI_UPPER_MEM; - isa_io_base = - (unsigned long)ioremap64(EBONY_PCI_IO_BASE, EBONY_PCI_IO_SIZE); - hose->io_base_virt = (void *)isa_io_base; + hose->io_base_virt = ioremap64(EBONY_PCI_IO_BASE, EBONY_PCI_IO_SIZE); + isa_io_base = (unsigned long)hose->io_base_virt; setup_indirect_pci(hose, EBONY_PCI_CFGA_PLB32, diff --git a/arch/ppc/platforms/4xx/luan.c b/arch/ppc/platforms/4xx/luan.c index 1df2339..95359f7 100644 --- a/arch/ppc/platforms/4xx/luan.c +++ b/arch/ppc/platforms/4xx/luan.c @@ -223,9 +223,8 @@ luan_setup_hose(struct pci_controller *hose, hose->io_space.end = LUAN_PCIX_UPPER_IO; hose->mem_space.start = lower_mem; hose->mem_space.end = upper_mem; - isa_io_base = - (unsigned long)ioremap64(pcix_io_base, PCIX_IO_SIZE); - hose->io_base_virt = (void *)isa_io_base; + hose->io_base_virt = ioremap64(pcix_io_base, PCIX_IO_SIZE); + isa_io_base = (unsigned long) hose->io_base_virt; setup_indirect_pci(hose, cfga, cfgd); hose->set_cfg_type = 1; diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c index 28de707..5f82a6b 100644 --- a/arch/ppc/platforms/4xx/ocotea.c +++ b/arch/ppc/platforms/4xx/ocotea.c @@ -227,9 +227,8 @@ ocotea_setup_hose(void) hose->io_space.end = OCOTEA_PCI_UPPER_IO; hose->mem_space.start = OCOTEA_PCI_LOWER_MEM; hose->mem_space.end = OCOTEA_PCI_UPPER_MEM; - isa_io_base = - (unsigned long)ioremap64(OCOTEA_PCI_IO_BASE, OCOTEA_PCI_IO_SIZE); - hose->io_base_virt = (void *)isa_io_base; + hose->io_base_virt = ioremap64(OCOTEA_PCI_IO_BASE, OCOTEA_PCI_IO_SIZE); + isa_io_base = (unsigned long) hose->io_base_virt; setup_indirect_pci(hose, OCOTEA_PCI_CFGA_PLB32, diff --git a/arch/ppc/syslib/m8260_pci.c b/arch/ppc/syslib/m8260_pci.c index bd564fb..057cc3f 100644 --- a/arch/ppc/syslib/m8260_pci.c +++ b/arch/ppc/syslib/m8260_pci.c @@ -171,10 +171,9 @@ void __init m8260_find_bridges(void) m8260_setup_pci(hose); hose->pci_mem_offset = MPC826x_PCI_MEM_OFFSET; - isa_io_base = - (unsigned long) ioremap(MPC826x_PCI_IO_BASE, + hose->io_base_virt = ioremap(MPC826x_PCI_IO_BASE, MPC826x_PCI_IO_SIZE); - hose->io_base_virt = (void *) isa_io_base; + isa_io_base = (unsigned long) hose->io_base_virt; /* setup resources */ pci_init_resource(&hose->mem_resources[0], diff --git a/arch/ppc/syslib/mpc52xx_pci.c b/arch/ppc/syslib/mpc52xx_pci.c index c723efd..59cf3e8 100644 --- a/arch/ppc/syslib/mpc52xx_pci.c +++ b/arch/ppc/syslib/mpc52xx_pci.c @@ -205,13 +205,11 @@ mpc52xx_find_bridges(void) hose->pci_mem_offset = MPC52xx_PCI_MEM_OFFSET; - isa_io_base = - (unsigned long) ioremap(MPC52xx_PCI_IO_BASE, - MPC52xx_PCI_IO_SIZE); - hose->io_base_virt = (void *) isa_io_base; + hose->io_base_virt = ioremap(MPC52xx_PCI_IO_BASE, MPC52xx_PCI_IO_SIZE); + isa_io_base = (unsigned long) hose->io_base_virt; hose->cfg_addr = &pci_regs->car; - hose->cfg_data = (void __iomem *) isa_io_base; + hose->cfg_data = hose->io_base_virt; /* Setup resources */ pci_init_resource(&hose->mem_resources[0], diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c index 81f1968..152c3ef 100644 --- a/arch/ppc/syslib/ppc85xx_setup.c +++ b/arch/ppc/syslib/ppc85xx_setup.c @@ -280,16 +280,14 @@ mpc85xx_setup_hose(void) hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO; hose_a->io_base_phys = MPC85XX_PCI1_IO_BASE; #ifdef CONFIG_85xx_PCI2 - isa_io_base = - (unsigned long) ioremap(MPC85XX_PCI1_IO_BASE, + hose_a->io_base_virt = ioremap(MPC85XX_PCI1_IO_BASE, MPC85XX_PCI1_IO_SIZE + MPC85XX_PCI2_IO_SIZE); #else - isa_io_base = - (unsigned long) ioremap(MPC85XX_PCI1_IO_BASE, + hose_a->io_base_virt = ioremap(MPC85XX_PCI1_IO_BASE, MPC85XX_PCI1_IO_SIZE); #endif - hose_a->io_base_virt = (void *) isa_io_base; + isa_io_base = (unsigned long)hose_a->io_base_virt; /* setup resources */ pci_init_resource(&hose_a->mem_resources[0], @@ -329,8 +327,8 @@ mpc85xx_setup_hose(void) hose_b->io_space.start = MPC85XX_PCI2_LOWER_IO; hose_b->io_space.end = MPC85XX_PCI2_UPPER_IO; hose_b->io_base_phys = MPC85XX_PCI2_IO_BASE; - hose_b->io_base_virt = (void *) isa_io_base + MPC85XX_PCI1_IO_SIZE; - + hose_b->io_base_virt = hose_a->io_base_virt + MPC85XX_PCI1_IO_SIZE; + /* setup resources */ pci_init_resource(&hose_b->mem_resources[0], MPC85XX_PCI2_LOWER_MEM, diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h index 78e9be6..ffa4234 100644 --- a/include/asm-ppc/pci-bridge.h +++ b/include/asm-ppc/pci-bridge.h @@ -12,7 +12,7 @@ struct pci_controller; * pci_io_base returns the memory address at which you can access * the I/O space for PCI bus number `bus' (or NULL on error). */ -extern void *pci_bus_io_base(unsigned int bus); +extern void __iomem *pci_bus_io_base(unsigned int bus); extern unsigned long pci_bus_io_base_phys(unsigned int bus); extern unsigned long pci_bus_mem_base_phys(unsigned int bus); @@ -48,7 +48,7 @@ struct pci_controller { int last_busno; int bus_offset; - void *io_base_virt; + void __iomem *io_base_virt; unsigned long io_base_phys; /* Some machines (PReP) have a non 1:1 mapping of -- cgit v0.10.2 From ba724a373a7184dce869e8adb79a0a03d91fbdd8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 07:55:58 -0700 Subject: [PATCH] ppc iomem annotations: ebony_setup_pcix() Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c index 55120c3..cd11734 100644 --- a/arch/ppc/platforms/4xx/ebony.c +++ b/arch/ppc/platforms/4xx/ebony.c @@ -149,7 +149,7 @@ ebony_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) static void __init ebony_setup_pcix(void) { - void *pcix_reg_base; + void __iomem *pcix_reg_base; pcix_reg_base = ioremap64(PCIX0_REG_BASE, PCIX_REG_SIZE); -- cgit v0.10.2 From d01daf72f0a238c5ccfba7bf82999e384927412e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 07:55:58 -0700 Subject: [PATCH] ppc iomem annotations: pmac_low_i2c Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/pmac_low_i2c.c b/arch/ppc/platforms/pmac_low_i2c.c index d07579f..08583fc 100644 --- a/arch/ppc/platforms/pmac_low_i2c.c +++ b/arch/ppc/platforms/pmac_low_i2c.c @@ -54,7 +54,7 @@ struct low_i2c_host int mode; /* Current mode */ int channel; /* Current channel */ int num_channels; /* Number of channels */ - unsigned long base; /* For keywest-i2c, base address */ + void __iomem * base; /* For keywest-i2c, base address */ int bsteps; /* And register stepping */ int speed; /* And speed */ }; @@ -154,14 +154,12 @@ static const char *__kw_state_names[] = { static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg) { - return in_8(((volatile u8 *)host->base) - + (((unsigned)reg) << host->bsteps)); + return in_8(host->base + (((unsigned)reg) << host->bsteps)); } static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val) { - out_8(((volatile u8 *)host->base) - + (((unsigned)reg) << host->bsteps), val); + out_8(host->base + (((unsigned)reg) << host->bsteps), val); (void)__kw_read_reg(host, reg_subaddr); } @@ -370,7 +368,7 @@ static void keywest_low_i2c_add(struct device_node *np) break; } host->mode = pmac_low_i2c_mode_std; - host->base = (unsigned long)ioremap(np->addrs[0].address + aoffset, + host->base = ioremap(np->addrs[0].address + aoffset, np->addrs[0].size); host->func = keywest_low_i2c_func; } -- cgit v0.10.2 From 91de1fff2d431fec1162333a1e4fad9a53cd5b9e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 07:55:58 -0700 Subject: [PATCH] ppc sparse annotations: emulate_string_inst() replaced declaration of EA from u32 to unsigned long - this beast is used only to cast it to (userland) pointer and proper integer type for that is unsigned long. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 002322a..361865c 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -403,7 +403,7 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) u8 rA = (instword >> 16) & 0x1f; u8 NB_RB = (instword >> 11) & 0x1f; u32 num_bytes; - u32 EA; + unsigned long EA; int pos = 0; /* Early out if we are an invalid form of lswx */ -- cgit v0.10.2 From dc074a8a32bc12e19436b087f01f4a4700e9b9c0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 07:55:58 -0700 Subject: [PATCH] ppc iomem annotations: mv643xx_eth void * __iomem replaced with intended void __iomem *. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 7e94d45..0405e1f 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -99,7 +99,7 @@ static spinlock_t mv643xx_eth_phy_lock = SPIN_LOCK_UNLOCKED; static inline u32 mv_read(int offset) { - void *__iomem reg_base; + void __iomem *reg_base; reg_base = mv643xx_eth_shared_base - MV643XX_ETH_SHARED_REGS; @@ -108,7 +108,7 @@ static inline u32 mv_read(int offset) static inline void mv_write(int offset, u32 data) { - void * __iomem reg_base; + void __iomem *reg_base; reg_base = mv643xx_eth_shared_base - MV643XX_ETH_SHARED_REGS; writel(data, reg_base + offset); -- cgit v0.10.2 From 056de2fa12febe02597f971eb6ea8f2cc9c9b06e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 07:55:59 -0700 Subject: [PATCH] ppc user annotations: debug_setconetext(2) 3rd argument of sys_debug_setcontext() is also a userland pointer. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index d500f5e..7c8437da 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -511,7 +511,7 @@ int sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, } int sys_debug_setcontext(struct ucontext __user *ctx, - int ndbg, struct sig_dbg_op *dbg, + int ndbg, struct sig_dbg_op __user *dbg, int r6, int r7, int r8, struct pt_regs *regs) { -- cgit v0.10.2 From 25ee7e3832951cf5896b194f6cd929a44863f419 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 25 Apr 2005 08:18:14 -0700 Subject: [PATCH] fs/aio.c: make some code static This patch makes some needlessly global code static. Signed-off-by: Adrian Bunk Acked-by: Benjamin LaHaise Signed-off-by: Linus Torvalds diff --git a/fs/aio.c b/fs/aio.c index d06a2667..a82214d 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -40,8 +40,8 @@ #define dprintk(x...) do { ; } while (0) #endif -long aio_run = 0; /* for testing only */ -long aio_wakeups = 0; /* for testing only */ +static long aio_run = 0; /* for testing only */ +static long aio_wakeups = 0; /* for testing only */ /*------ sysctl variables----*/ atomic_t aio_nr = ATOMIC_INIT(0); /* current system wide number of aio requests */ @@ -58,7 +58,7 @@ static void aio_fput_routine(void *); static DECLARE_WORK(fput_work, aio_fput_routine, NULL); static DEFINE_SPINLOCK(fput_lock); -LIST_HEAD(fput_head); +static LIST_HEAD(fput_head); static void aio_kick_handler(void *); @@ -290,7 +290,7 @@ static void aio_cancel_all(struct kioctx *ctx) spin_unlock_irq(&ctx->ctx_lock); } -void wait_for_all_aios(struct kioctx *ctx) +static void wait_for_all_aios(struct kioctx *ctx) { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); @@ -592,7 +592,7 @@ static void use_mm(struct mm_struct *mm) * Comments: Called with ctx->ctx_lock held. This nests * task_lock instead ctx_lock. */ -void unuse_mm(struct mm_struct *mm) +static void unuse_mm(struct mm_struct *mm) { struct task_struct *tsk = current; @@ -879,7 +879,7 @@ static void aio_kick_handler(void *data) * and if required activate the aio work queue to process * it */ -void queue_kicked_iocb(struct kiocb *iocb) +static void queue_kicked_iocb(struct kiocb *iocb) { struct kioctx *ctx = iocb->ki_ctx; unsigned long flags; @@ -1401,7 +1401,7 @@ static ssize_t aio_fsync(struct kiocb *iocb) * Performs the initial checks and aio retry method * setup for the kiocb at the time of io submission. */ -ssize_t aio_setup_iocb(struct kiocb *kiocb) +static ssize_t aio_setup_iocb(struct kiocb *kiocb) { struct file *file = kiocb->ki_filp; ssize_t ret = 0; @@ -1470,7 +1470,8 @@ ssize_t aio_setup_iocb(struct kiocb *kiocb) * because this callback isn't used for wait queues which * are nested inside ioctx lock (i.e. ctx->wait) */ -int aio_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key) +static int aio_wake_function(wait_queue_t *wait, unsigned mode, + int sync, void *key) { struct kiocb *iocb = container_of(wait, struct kiocb, ki_wait); @@ -1620,7 +1621,8 @@ asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr, * Finds a given iocb for cancellation. * MUST be called with ctx->ctx_lock held. */ -struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb __user *iocb, u32 key) +static struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb __user *iocb, + u32 key) { struct list_head *pos; /* TODO: use a hash or array, this sucks. */ -- cgit v0.10.2 From a3342421363642d03b2ae3ecd27e3041de043e99 Mon Sep 17 00:00:00 2001 From: Lucas Correia Villa Real Date: Mon, 25 Apr 2005 18:36:50 +0100 Subject: [PATCH] ARM: 2640/1: Adds DRAM/BANKSIZE_MASK definitions for S3C2400 Patch from Lucas Correia Villa Real Adds DRAM refresh definitions and sets the BANKSIZE_MASK for the S3C2400 on include/asm-arm/arch-s3c2400/regs-mem.h Signed-off-by: Lucas Correia Villa Real Signed-off-by: Ben Dooks Signed-off-by: Russell King diff --git a/include/asm-arm/arch-s3c2410/regs-mem.h b/include/asm-arm/arch-s3c2410/regs-mem.h index 1a1328a..a2d7d0c 100644 --- a/include/asm-arm/arch-s3c2410/regs-mem.h +++ b/include/asm-arm/arch-s3c2410/regs-mem.h @@ -12,6 +12,7 @@ * Changelog: * 29-Sep-2004 BJD Initial include for Linux * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA + * 04-Apr-2005 LCVR Added S3C2400 DRAM/BANKSIZE_MASK definitions * */ @@ -183,6 +184,12 @@ #define S3C2410_REFRESH_TRP_3clk (1<<20) #define S3C2410_REFRESH_TRP_4clk (2<<20) +#define S3C2400_REFRESH_DRAM_TRP_MASK (3<<20) +#define S3C2400_REFRESH_DRAM_TRP_1_5clk (0<<20) +#define S3C2400_REFRESH_DRAM_TRP_2_5clk (1<<20) +#define S3C2400_REFRESH_DRAM_TRP_3_5clk (2<<20) +#define S3C2400_REFRESH_DRAM_TRP_4_5clk (3<<20) + #define S3C2410_REFRESH_TSRC_MASK (3<<18) #define S3C2410_REFRESH_TSRC_4clk (0<<18) #define S3C2410_REFRESH_TSRC_5clk (1<<18) @@ -205,6 +212,7 @@ #define S3C2410_BANKSIZE_4M (0x5 << 0) #define S3C2410_BANKSIZE_2M (0x4 << 0) #define S3C2410_BANKSIZE_MASK (0x7 << 0) +#define S3C2400_BANKSIZE_MASK (0x4 << 0) #define S3C2410_BANKSIZE_SCLK_EN (1<<4) #define S3C2410_BANKSIZE_SCKE_EN (1<<5) #define S3C2410_BANKSIZE_BURST (1<<7) -- cgit v0.10.2 From b7ebcc108a1754a1d044b49c0acf977a7e86ae71 Mon Sep 17 00:00:00 2001 From: Lucas Correia Villa Real Date: Mon, 25 Apr 2005 18:40:31 +0100 Subject: [PATCH] ARM: 2641/1: Adds S3C2400_SPPIN_nCS to arch-s3c2410/regs-spi.h Patch from Lucas Correia Villa Real Adds a define to the SPI Card Select bit on the S3C2400 into include/asm-arm/arch-s3c2410/regs-spi.h Signed-off-by: Lucas Correia Villa Real Signed-off-by: Russell King diff --git a/include/asm-arm/arch-s3c2410/regs-spi.h b/include/asm-arm/arch-s3c2410/regs-spi.h index cb502a8..3382178 100644 --- a/include/asm-arm/arch-s3c2410/regs-spi.h +++ b/include/asm-arm/arch-s3c2410/regs-spi.h @@ -12,6 +12,7 @@ * 20-04-2004 KF Created file * 04-10-2004 BJD Removed VA address (no longer mapped) * tidied file for submission + * 03-04-2005 LCVR Added S3C2400_SPPIN_nCS definition */ #ifndef __ASM_ARCH_REGS_SPI_H @@ -46,6 +47,7 @@ #define S3C2410_SPPIN_ENMUL (1<<2) /* Multi Master Error detect */ #define S3C2410_SPPIN_RESERVED (1<<1) +#define S3C2400_SPPIN_nCS (1<<1) /* SPI Card Select */ #define S3C2410_SPPIN_KEEP (1<<0) /* Master Out keep */ -- cgit v0.10.2 From e955d82543fea76b02aa243b182e782f71bda82c Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Mon, 25 Apr 2005 11:26:03 -0700 Subject: [IA64-SGI] sn2-pci-dma-abstraction.patch Provide an abstraction of the altix pci dma runtime layer so that multiple pci-based bridges can be supported. Signed-off-by: Mark Maule Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/include/pci/pcibr_provider.h b/arch/ia64/sn/include/pci/pcibr_provider.h index b1f05ff..1cd291d 100644 --- a/arch/ia64/sn/include/pci/pcibr_provider.h +++ b/arch/ia64/sn/include/pci/pcibr_provider.h @@ -123,9 +123,11 @@ pcibr_lock(struct pcibus_info *pcibus_info) } #define pcibr_unlock(pcibus_info, flag) spin_unlock_irqrestore(&pcibus_info->pbi_lock, flag) +extern int pcibr_init_provider(void); extern void *pcibr_bus_fixup(struct pcibus_bussoft *); -extern uint64_t pcibr_dma_map(struct pcidev_info *, unsigned long, size_t, unsigned int); -extern void pcibr_dma_unmap(struct pcidev_info *, dma_addr_t, int); +extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t); +extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t); +extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int); /* * prototypes for the bridge asic register access routines in pcibr_reg.c diff --git a/arch/ia64/sn/include/pci/pcibus_provider_defs.h b/arch/ia64/sn/include/pci/pcibus_provider_defs.h index 0706561..f546b4e 100644 --- a/arch/ia64/sn/include/pci/pcibus_provider_defs.h +++ b/arch/ia64/sn/include/pci/pcibus_provider_defs.h @@ -18,6 +18,8 @@ #define PCIIO_ASIC_TYPE_PIC 2 #define PCIIO_ASIC_TYPE_TIOCP 3 +#define PCIIO_ASIC_MAX_TYPES 4 + /* * Common pciio bus provider data. There should be one of these as the * first field in any pciio based provider soft structure (e.g. pcibr_soft @@ -35,9 +37,15 @@ struct pcibus_bussoft { }; /* - * DMA mapping flags + * SN pci bus indirection */ -#define SN_PCIDMA_CONSISTENT 0x0001 +struct sn_pcibus_provider { + dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t); + dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t); + void (*dma_unmap)(struct pci_dev *, dma_addr_t, int); + void * (*bus_fixup)(struct pcibus_bussoft *); +}; +extern struct sn_pcibus_provider *sn_pci_provider[]; #endif /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */ diff --git a/arch/ia64/sn/include/pci/pcidev.h b/arch/ia64/sn/include/pci/pcidev.h index 81eb95d..ed4031d 100644 --- a/arch/ia64/sn/include/pci/pcidev.h +++ b/arch/ia64/sn/include/pci/pcidev.h @@ -32,6 +32,9 @@ extern struct sn_irq_info **sn_irq; #define SN_PCIDEV_BUSSOFT(pci_dev) \ (SN_PCIDEV_INFO(pci_dev)->pdi_host_pcidev_info->pdi_pcibus_info) +#define SN_PCIDEV_BUSPROVIDER(pci_dev) \ + (SN_PCIDEV_INFO(pci_dev)->pdi_provider) + #define PCIIO_BUS_NONE 255 /* bus 255 reserved */ #define PCIIO_SLOT_NONE 255 #define PCIIO_FUNC_NONE 255 @@ -46,6 +49,7 @@ struct pcidev_info { struct pci_dev *pdi_linux_pcidev; /* Kernel pci_dev */ struct sn_irq_info *pdi_sn_irq_info; + struct sn_pcibus_provider *pdi_provider; /* sn pci ops */ }; extern void sn_irq_fixup(struct pci_dev *pci_dev, diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 0018808..3e5e4a9 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -34,6 +34,37 @@ struct brick { int sn_ioif_inited = 0; /* SN I/O infrastructure initialized? */ +struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ + +/* + * Hooks and struct for unsupported pci providers + */ + +static dma_addr_t +sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size) +{ + return 0; +} + +static void +sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction) +{ + return; +} + +static void * +sn_default_pci_bus_fixup(struct pcibus_bussoft *soft) +{ + return NULL; +} + +static struct sn_pcibus_provider sn_pci_default_provider = { + .dma_map = sn_default_pci_map, + .dma_map_consistent = sn_default_pci_map, + .dma_unmap = sn_default_pci_unmap, + .bus_fixup = sn_default_pci_bus_fixup, +}; + /* * Retrieve the DMA Flush List given nasid. This list is needed * to implement the WAR - Flush DMA data on PIO Reads. @@ -201,6 +232,7 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) struct sn_irq_info *sn_irq_info; struct pci_dev *host_pci_dev; int status = 0; + struct pcibus_bussoft *bs; dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); if (SN_PCIDEV_INFO(dev) <= 0) @@ -241,6 +273,7 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) } /* set up host bus linkages */ + bs = SN_PCIBUS_BUSSOFT(dev->bus); host_pci_dev = pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32, SN_PCIDEV_INFO(dev)-> @@ -248,10 +281,16 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev); SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev; - SN_PCIDEV_INFO(dev)->pdi_pcibus_info = SN_PCIBUS_BUSSOFT(dev->bus); + SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs; + + if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { + SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type]; + } else { + SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider; + } /* Only set up IRQ stuff if this device has a host bus context */ - if (SN_PCIDEV_BUSSOFT(dev) && sn_irq_info->irq_irq) { + if (bs && sn_irq_info->irq_irq) { SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info; dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq; sn_irq_fixup(dev, sn_irq_info); @@ -271,6 +310,7 @@ static void sn_pci_controller_fixup(int segment, int busnum) struct pcibus_bussoft *prom_bussoft_ptr; struct hubdev_info *hubdev_info; void *provider_soft; + struct sn_pcibus_provider *provider; status = sal_get_pcibus_info((u64) segment, (u64) busnum, @@ -291,16 +331,22 @@ static void sn_pci_controller_fixup(int segment, int busnum) /* * Per-provider fixup. Copies the contents from prom to local * area and links SN_PCIBUS_BUSSOFT(). - * - * Note: Provider is responsible for ensuring that prom_bussoft_ptr - * represents an asic-type that it can handle. */ - if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) { - return; /* no further fixup necessary */ + if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) { + return; /* unsupported asic type */ + } + + provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; + if (provider == NULL) { + return; /* no provider registerd for this asic */ + } + + provider_soft = NULL; + if (provider->bus_fixup) { + provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr); } - provider_soft = pcibr_bus_fixup(prom_bussoft_ptr); if (provider_soft == NULL) { return; /* fixup failed or not applicable */ } @@ -339,6 +385,16 @@ static int __init sn_pci_init(void) return 0; /* + * prime sn_pci_provider[]. Individial provider init routines will + * override their respective default entries. + */ + + for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++) + sn_pci_provider[i] = &sn_pci_default_provider; + + pcibr_init_provider(); + + /* * This is needed to avoid bounce limit checks in the blk layer */ ia64_max_iommu_merge_mask = ~PAGE_MASK; diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index f680824..c2b92b9 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c @@ -14,7 +14,6 @@ #include #include "pci/pcibus_provider_defs.h" #include "pci/pcidev.h" -#include "pci/pcibr_provider.h" #define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) #define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) @@ -79,7 +78,8 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size, { void *cpuaddr; unsigned long phys_addr; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); + struct pci_dev *pdev = to_pci_dev(dev); + struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); BUG_ON(dev->bus != &pci_bus_type); @@ -102,8 +102,7 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size, * resources. */ - *dma_handle = pcibr_dma_map(pcidev_info, phys_addr, size, - SN_PCIDMA_CONSISTENT); + *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size); if (!*dma_handle) { printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); free_pages((unsigned long)cpuaddr, get_order(size)); @@ -127,11 +126,12 @@ EXPORT_SYMBOL(sn_dma_alloc_coherent); void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle) { - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); + struct pci_dev *pdev = to_pci_dev(dev); + struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); BUG_ON(dev->bus != &pci_bus_type); - pcibr_dma_unmap(pcidev_info, dma_handle, 0); + provider->dma_unmap(pdev, dma_handle, 0); free_pages((unsigned long)cpu_addr, get_order(size)); } EXPORT_SYMBOL(sn_dma_free_coherent); @@ -159,12 +159,13 @@ dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, { dma_addr_t dma_addr; unsigned long phys_addr; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); + struct pci_dev *pdev = to_pci_dev(dev); + struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); BUG_ON(dev->bus != &pci_bus_type); phys_addr = __pa(cpu_addr); - dma_addr = pcibr_dma_map(pcidev_info, phys_addr, size, 0); + dma_addr = provider->dma_map(pdev, phys_addr, size); if (!dma_addr) { printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); return 0; @@ -187,10 +188,12 @@ EXPORT_SYMBOL(sn_dma_map_single); void sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, int direction) { - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); + struct pci_dev *pdev = to_pci_dev(dev); + struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); BUG_ON(dev->bus != &pci_bus_type); - pcibr_dma_unmap(pcidev_info, dma_addr, direction); + + provider->dma_unmap(pdev, dma_addr, direction); } EXPORT_SYMBOL(sn_dma_unmap_single); @@ -207,12 +210,13 @@ void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, int direction) { int i; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); + struct pci_dev *pdev = to_pci_dev(dev); + struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); BUG_ON(dev->bus != &pci_bus_type); for (i = 0; i < nhwentries; i++, sg++) { - pcibr_dma_unmap(pcidev_info, sg->dma_address, direction); + provider->dma_unmap(pdev, sg->dma_address, direction); sg->dma_address = (dma_addr_t) NULL; sg->dma_length = 0; } @@ -233,7 +237,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries, { unsigned long phys_addr; struct scatterlist *saved_sg = sg; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); + struct pci_dev *pdev = to_pci_dev(dev); + struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); int i; BUG_ON(dev->bus != &pci_bus_type); @@ -243,8 +248,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries, */ for (i = 0; i < nhwentries; i++, sg++) { phys_addr = SG_ENT_PHYS_ADDRESS(sg); - sg->dma_address = pcibr_dma_map(pcidev_info, phys_addr, - sg->length, 0); + sg->dma_address = provider->dma_map(pdev, + phys_addr, sg->length); if (!sg->dma_address) { printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c index b1d66ac..3c305f4 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c @@ -40,7 +40,7 @@ extern int sn_ioif_inited; * we do not have to allocate entries in the PMU. */ -static uint64_t +static dma_addr_t pcibr_dmamap_ate32(struct pcidev_info *info, uint64_t paddr, size_t req_size, uint64_t flags) { @@ -109,7 +109,7 @@ pcibr_dmamap_ate32(struct pcidev_info *info, return pci_addr; } -static uint64_t +static dma_addr_t pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr, uint64_t dma_attributes) { @@ -141,7 +141,7 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr, } -static uint64_t +static dma_addr_t pcibr_dmatrans_direct32(struct pcidev_info * info, uint64_t paddr, size_t req_size, uint64_t flags) { @@ -180,11 +180,11 @@ pcibr_dmatrans_direct32(struct pcidev_info * info, * DMA mappings for Direct 64 and 32 do not have any DMA maps. */ void -pcibr_dma_unmap(struct pcidev_info *pcidev_info, dma_addr_t dma_handle, - int direction) +pcibr_dma_unmap(struct pci_dev *hwdev, dma_addr_t dma_handle, int direction) { - struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info-> - pdi_pcibus_info; + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); + struct pcibus_info *pcibus_info = + (struct pcibus_info *)pcidev_info->pdi_pcibus_info; if (IS_PCI32_MAPPED(dma_handle)) { int ate_index; @@ -316,64 +316,63 @@ void sn_dma_flush(uint64_t addr) } /* - * Wrapper DMA interface. Called from pci_dma.c routines. + * DMA interfaces. Called from pci_dma.c routines. */ -uint64_t -pcibr_dma_map(struct pcidev_info * pcidev_info, unsigned long phys_addr, - size_t size, unsigned int flags) +dma_addr_t +pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) { dma_addr_t dma_handle; - struct pci_dev *pcidev = pcidev_info->pdi_linux_pcidev; - - if (flags & SN_PCIDMA_CONSISTENT) { - /* sn_pci_alloc_consistent interfaces */ - if (pcidev->dev.coherent_dma_mask == ~0UL) { - dma_handle = - pcibr_dmatrans_direct64(pcidev_info, phys_addr, - PCI64_ATTR_BAR); - } else { - dma_handle = - (dma_addr_t) pcibr_dmamap_ate32(pcidev_info, - phys_addr, size, - PCI32_ATE_BAR); - } - } else { - /* map_sg/map_single interfaces */ + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); - /* SN cannot support DMA addresses smaller than 32 bits. */ - if (pcidev->dma_mask < 0x7fffffff) { - return 0; - } + /* SN cannot support DMA addresses smaller than 32 bits. */ + if (hwdev->dma_mask < 0x7fffffff) { + return 0; + } - if (pcidev->dma_mask == ~0UL) { + if (hwdev->dma_mask == ~0UL) { + /* + * Handle the most common case: 64 bit cards. This + * call should always succeed. + */ + + dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, + PCI64_ATTR_PREF); + } else { + /* Handle 32-63 bit cards via direct mapping */ + dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr, + size, 0); + if (!dma_handle) { /* - * Handle the most common case: 64 bit cards. This - * call should always succeed. + * It is a 32 bit card and we cannot do direct mapping, + * so we use an ATE. */ - dma_handle = - pcibr_dmatrans_direct64(pcidev_info, phys_addr, - PCI64_ATTR_PREF); - } else { - /* Handle 32-63 bit cards via direct mapping */ - dma_handle = - pcibr_dmatrans_direct32(pcidev_info, phys_addr, - size, 0); - if (!dma_handle) { - /* - * It is a 32 bit card and we cannot do direct mapping, - * so we use an ATE. - */ - - dma_handle = - pcibr_dmamap_ate32(pcidev_info, phys_addr, - size, PCI32_ATE_PREF); - } + dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr, + size, PCI32_ATE_PREF); } } return dma_handle; } +dma_addr_t +pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr, + size_t size) +{ + dma_addr_t dma_handle; + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); + + if (hwdev->dev.coherent_dma_mask == ~0UL) { + dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, + PCI64_ATTR_BAR); + } else { + dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info, + phys_addr, size, + PCI32_ATE_BAR); + } + + return dma_handle; +} + EXPORT_SYMBOL(sn_dma_flush); diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c index 92bd278..539ab1f 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c @@ -168,3 +168,23 @@ void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info) pcibr_force_interrupt(sn_irq_info); } } + +/* + * Provider entries for PIC/CP + */ + +struct sn_pcibus_provider pcibr_provider = { + .dma_map = pcibr_dma_map, + .dma_map_consistent = pcibr_dma_map_consistent, + .dma_unmap = pcibr_dma_unmap, + .bus_fixup = pcibr_bus_fixup, +}; + +int +pcibr_init_provider(void) +{ + sn_pci_provider[PCIIO_ASIC_TYPE_PIC] = &pcibr_provider; + sn_pci_provider[PCIIO_ASIC_TYPE_TIOCP] = &pcibr_provider; + + return 0; +} -- cgit v0.10.2 From 9b08ebd167a3f3812131a54512f92c3c6738ad03 Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Mon, 25 Apr 2005 11:32:16 -0700 Subject: [IA64-SGI] sn2-move-pci-headers.patch Move a couple of headers out of arch/ia64/sn/include/pci and into include/asm-ia64/sn. Signed-off-by: Mark Maule Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/include/pci/pcibus_provider_defs.h b/arch/ia64/sn/include/pci/pcibus_provider_defs.h deleted file mode 100644 index f546b4e..0000000 --- a/arch/ia64/sn/include/pci/pcibus_provider_defs.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H -#define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H - -/* - * SN pci asic types. Do not ever renumber these or reuse values. The - * values must agree with what prom thinks they are. - */ - -#define PCIIO_ASIC_TYPE_UNKNOWN 0 -#define PCIIO_ASIC_TYPE_PPB 1 -#define PCIIO_ASIC_TYPE_PIC 2 -#define PCIIO_ASIC_TYPE_TIOCP 3 - -#define PCIIO_ASIC_MAX_TYPES 4 - -/* - * Common pciio bus provider data. There should be one of these as the - * first field in any pciio based provider soft structure (e.g. pcibr_soft - * tioca_soft, etc). - */ - -struct pcibus_bussoft { - uint32_t bs_asic_type; /* chipset type */ - uint32_t bs_xid; /* xwidget id */ - uint64_t bs_persist_busnum; /* Persistent Bus Number */ - uint64_t bs_legacy_io; /* legacy io pio addr */ - uint64_t bs_legacy_mem; /* legacy mem pio addr */ - uint64_t bs_base; /* widget base */ - struct xwidget_info *bs_xwidget_info; -}; - -/* - * SN pci bus indirection - */ - -struct sn_pcibus_provider { - dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t); - dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t); - void (*dma_unmap)(struct pci_dev *, dma_addr_t, int); - void * (*bus_fixup)(struct pcibus_bussoft *); -}; - -extern struct sn_pcibus_provider *sn_pci_provider[]; -#endif /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */ diff --git a/arch/ia64/sn/include/pci/pcidev.h b/arch/ia64/sn/include/pci/pcidev.h deleted file mode 100644 index ed4031d..0000000 --- a/arch/ia64/sn/include/pci/pcidev.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PCI_PCIDEV_H -#define _ASM_IA64_SN_PCI_PCIDEV_H - -#include - -extern struct sn_irq_info **sn_irq; - -#define SN_PCIDEV_INFO(pci_dev) \ - ((struct pcidev_info *)(pci_dev)->sysdata) - -/* - * Given a pci_bus, return the sn pcibus_bussoft struct. Note that - * this only works for root busses, not for busses represented by PPB's. - */ - -#define SN_PCIBUS_BUSSOFT(pci_bus) \ - ((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data)) - -/* - * Given a struct pci_dev, return the sn pcibus_bussoft struct. Note - * that this is not equivalent to SN_PCIBUS_BUSSOFT(pci_dev->bus) due - * due to possible PPB's in the path. - */ - -#define SN_PCIDEV_BUSSOFT(pci_dev) \ - (SN_PCIDEV_INFO(pci_dev)->pdi_host_pcidev_info->pdi_pcibus_info) - -#define SN_PCIDEV_BUSPROVIDER(pci_dev) \ - (SN_PCIDEV_INFO(pci_dev)->pdi_provider) - -#define PCIIO_BUS_NONE 255 /* bus 255 reserved */ -#define PCIIO_SLOT_NONE 255 -#define PCIIO_FUNC_NONE 255 -#define PCIIO_VENDOR_ID_NONE (-1) - -struct pcidev_info { - uint64_t pdi_pio_mapped_addr[7]; /* 6 BARs PLUS 1 ROM */ - uint64_t pdi_slot_host_handle; /* Bus and devfn Host pci_dev */ - - struct pcibus_bussoft *pdi_pcibus_info; /* Kernel common bus soft */ - struct pcidev_info *pdi_host_pcidev_info; /* Kernel Host pci_dev */ - struct pci_dev *pdi_linux_pcidev; /* Kernel pci_dev */ - - struct sn_irq_info *pdi_sn_irq_info; - struct sn_pcibus_provider *pdi_provider; /* sn pci ops */ -}; - -extern void sn_irq_fixup(struct pci_dev *pci_dev, - struct sn_irq_info *sn_irq_info); - -#endif /* _ASM_IA64_SN_PCI_PCIDEV_H */ diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 3e5e4a9..9f9d046 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -11,8 +11,8 @@ #include #include #include -#include "pci/pcibus_provider_defs.h" -#include "pci/pcidev.h" +#include +#include #include "pci/pcibr_provider.h" #include "xtalk/xwidgetdev.h" #include diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index 3be4472..b52d329 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c @@ -13,8 +13,8 @@ #include #include #include "xtalk/xwidgetdev.h" -#include "pci/pcibus_provider_defs.h" -#include "pci/pcidev.h" +#include +#include #include "pci/pcibr_provider.h" #include #include diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index c2b92b9..5da9bdb 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c @@ -12,8 +12,8 @@ #include #include #include -#include "pci/pcibus_provider_defs.h" -#include "pci/pcidev.h" +#include +#include #define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) #define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c index 9d68546..0e47bce8 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_ate.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_ate.c @@ -8,8 +8,8 @@ #include #include -#include "pci/pcibus_provider_defs.h" -#include "pci/pcidev.h" +#include +#include #include "pci/pcibr_provider.h" int pcibr_invalidate_ate = 0; /* by default don't invalidate ATE on free */ diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c index 3c305f4..c906859 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c @@ -12,8 +12,8 @@ #include #include "xtalk/xwidgetdev.h" #include "xtalk/hubdev.h" -#include "pci/pcibus_provider_defs.h" -#include "pci/pcidev.h" +#include +#include #include "pci/tiocp.h" #include "pci/pic.h" #include "pci/pcibr_provider.h" diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c index 539ab1f..3893999 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c @@ -13,8 +13,8 @@ #include "xtalk/xwidgetdev.h" #include #include "xtalk/hubdev.h" -#include "pci/pcibus_provider_defs.h" -#include "pci/pcidev.h" +#include +#include #include "pci/pcibr_provider.h" #include diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c index 74a74a7..865c11c 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_reg.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_reg.c @@ -8,8 +8,8 @@ #include #include -#include "pci/pcibus_provider_defs.h" -#include "pci/pcidev.h" +#include +#include #include "pci/tiocp.h" #include "pci/pic.h" #include "pci/pcibr_provider.h" diff --git a/include/asm-ia64/sn/pcibus_provider_defs.h b/include/asm-ia64/sn/pcibus_provider_defs.h new file mode 100644 index 0000000..f546b4e --- /dev/null +++ b/include/asm-ia64/sn/pcibus_provider_defs.h @@ -0,0 +1,51 @@ +/* + * 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. + * + * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. + */ +#ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H +#define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H + +/* + * SN pci asic types. Do not ever renumber these or reuse values. The + * values must agree with what prom thinks they are. + */ + +#define PCIIO_ASIC_TYPE_UNKNOWN 0 +#define PCIIO_ASIC_TYPE_PPB 1 +#define PCIIO_ASIC_TYPE_PIC 2 +#define PCIIO_ASIC_TYPE_TIOCP 3 + +#define PCIIO_ASIC_MAX_TYPES 4 + +/* + * Common pciio bus provider data. There should be one of these as the + * first field in any pciio based provider soft structure (e.g. pcibr_soft + * tioca_soft, etc). + */ + +struct pcibus_bussoft { + uint32_t bs_asic_type; /* chipset type */ + uint32_t bs_xid; /* xwidget id */ + uint64_t bs_persist_busnum; /* Persistent Bus Number */ + uint64_t bs_legacy_io; /* legacy io pio addr */ + uint64_t bs_legacy_mem; /* legacy mem pio addr */ + uint64_t bs_base; /* widget base */ + struct xwidget_info *bs_xwidget_info; +}; + +/* + * SN pci bus indirection + */ + +struct sn_pcibus_provider { + dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t); + dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t); + void (*dma_unmap)(struct pci_dev *, dma_addr_t, int); + void * (*bus_fixup)(struct pcibus_bussoft *); +}; + +extern struct sn_pcibus_provider *sn_pci_provider[]; +#endif /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */ diff --git a/include/asm-ia64/sn/pcidev.h b/include/asm-ia64/sn/pcidev.h new file mode 100644 index 0000000..ed4031d --- /dev/null +++ b/include/asm-ia64/sn/pcidev.h @@ -0,0 +1,58 @@ +/* + * 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. + * + * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. + */ +#ifndef _ASM_IA64_SN_PCI_PCIDEV_H +#define _ASM_IA64_SN_PCI_PCIDEV_H + +#include + +extern struct sn_irq_info **sn_irq; + +#define SN_PCIDEV_INFO(pci_dev) \ + ((struct pcidev_info *)(pci_dev)->sysdata) + +/* + * Given a pci_bus, return the sn pcibus_bussoft struct. Note that + * this only works for root busses, not for busses represented by PPB's. + */ + +#define SN_PCIBUS_BUSSOFT(pci_bus) \ + ((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data)) + +/* + * Given a struct pci_dev, return the sn pcibus_bussoft struct. Note + * that this is not equivalent to SN_PCIBUS_BUSSOFT(pci_dev->bus) due + * due to possible PPB's in the path. + */ + +#define SN_PCIDEV_BUSSOFT(pci_dev) \ + (SN_PCIDEV_INFO(pci_dev)->pdi_host_pcidev_info->pdi_pcibus_info) + +#define SN_PCIDEV_BUSPROVIDER(pci_dev) \ + (SN_PCIDEV_INFO(pci_dev)->pdi_provider) + +#define PCIIO_BUS_NONE 255 /* bus 255 reserved */ +#define PCIIO_SLOT_NONE 255 +#define PCIIO_FUNC_NONE 255 +#define PCIIO_VENDOR_ID_NONE (-1) + +struct pcidev_info { + uint64_t pdi_pio_mapped_addr[7]; /* 6 BARs PLUS 1 ROM */ + uint64_t pdi_slot_host_handle; /* Bus and devfn Host pci_dev */ + + struct pcibus_bussoft *pdi_pcibus_info; /* Kernel common bus soft */ + struct pcidev_info *pdi_host_pcidev_info; /* Kernel Host pci_dev */ + struct pci_dev *pdi_linux_pcidev; /* Kernel pci_dev */ + + struct sn_irq_info *pdi_sn_irq_info; + struct sn_pcibus_provider *pdi_provider; /* sn pci ops */ +}; + +extern void sn_irq_fixup(struct pci_dev *pci_dev, + struct sn_irq_info *sn_irq_info); + +#endif /* _ASM_IA64_SN_PCI_PCIDEV_H */ -- cgit v0.10.2 From 9c90bdde77f7b7a42f7ebb900275d459ce2bac05 Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Mon, 25 Apr 2005 11:35:54 -0700 Subject: [IA64-SGI] altix: tioca chip driver (agp) Provide a driver for the altix TIOCA AGP chipset. An agpgart backend will be provided as a separate patch. Signed-off-by: Mark Maule Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 9f9d046..18160a0 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -19,6 +19,7 @@ #include "xtalk/hubdev.h" #include #include +#include char master_baseio_wid; nasid_t master_nasid = INVALID_NASID; /* Partition Master */ @@ -393,6 +394,7 @@ static int __init sn_pci_init(void) sn_pci_provider[i] = &sn_pci_default_provider; pcibr_init_provider(); + tioca_init_provider(); /* * This is needed to avoid bounce limit checks in the blk layer diff --git a/arch/ia64/sn/pci/Makefile b/arch/ia64/sn/pci/Makefile index b5dca00..2f915bc 100644 --- a/arch/ia64/sn/pci/Makefile +++ b/arch/ia64/sn/pci/Makefile @@ -7,4 +7,4 @@ # # Makefile for the sn pci general routines. -obj-y := pci_dma.o pcibr/ +obj-y := pci_dma.o tioca_provider.o pcibr/ diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c new file mode 100644 index 0000000..2234d61 --- /dev/null +++ b/arch/ia64/sn/pci/tioca_provider.c @@ -0,0 +1,668 @@ +/* + * 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. + * + * Copyright (C) 2003-2005 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +uint32_t tioca_gart_found; +EXPORT_SYMBOL(tioca_gart_found); /* used by agp-sgi */ + +LIST_HEAD(tioca_list); +EXPORT_SYMBOL(tioca_list); /* used by agp-sgi */ + +static int tioca_gart_init(struct tioca_kernel *); + +/** + * tioca_gart_init - Initialize SGI TIOCA GART + * @tioca_common: ptr to common prom/kernel struct identifying the + * + * If the indicated tioca has devices present, initialize its associated + * GART MMR's and kernel memory. + */ +static int +tioca_gart_init(struct tioca_kernel *tioca_kern) +{ + uint64_t ap_reg; + uint64_t offset; + struct page *tmp; + struct tioca_common *tioca_common; + volatile struct tioca *ca_base; + + tioca_common = tioca_kern->ca_common; + ca_base = (struct tioca *)tioca_common->ca_common.bs_base; + + if (list_empty(tioca_kern->ca_devices)) + return 0; + + ap_reg = 0; + + /* + * Validate aperature size + */ + + switch (CA_APERATURE_SIZE >> 20) { + case 4: + ap_reg |= (0x3ff << CA_GART_AP_SIZE_SHFT); /* 4MB */ + break; + case 8: + ap_reg |= (0x3fe << CA_GART_AP_SIZE_SHFT); /* 8MB */ + break; + case 16: + ap_reg |= (0x3fc << CA_GART_AP_SIZE_SHFT); /* 16MB */ + break; + case 32: + ap_reg |= (0x3f8 << CA_GART_AP_SIZE_SHFT); /* 32 MB */ + break; + case 64: + ap_reg |= (0x3f0 << CA_GART_AP_SIZE_SHFT); /* 64 MB */ + break; + case 128: + ap_reg |= (0x3e0 << CA_GART_AP_SIZE_SHFT); /* 128 MB */ + break; + case 256: + ap_reg |= (0x3c0 << CA_GART_AP_SIZE_SHFT); /* 256 MB */ + break; + case 512: + ap_reg |= (0x380 << CA_GART_AP_SIZE_SHFT); /* 512 MB */ + break; + case 1024: + ap_reg |= (0x300 << CA_GART_AP_SIZE_SHFT); /* 1GB */ + break; + case 2048: + ap_reg |= (0x200 << CA_GART_AP_SIZE_SHFT); /* 2GB */ + break; + case 4096: + ap_reg |= (0x000 << CA_GART_AP_SIZE_SHFT); /* 4 GB */ + break; + default: + printk(KERN_ERR "%s: Invalid CA_APERATURE_SIZE " + "0x%lx\n", __FUNCTION__, (ulong) CA_APERATURE_SIZE); + return -1; + } + + /* + * Set up other aperature parameters + */ + + if (PAGE_SIZE >= 16384) { + tioca_kern->ca_ap_pagesize = 16384; + ap_reg |= CA_GART_PAGE_SIZE; + } else { + tioca_kern->ca_ap_pagesize = 4096; + } + + tioca_kern->ca_ap_size = CA_APERATURE_SIZE; + tioca_kern->ca_ap_bus_base = CA_APERATURE_BASE; + tioca_kern->ca_gart_entries = + tioca_kern->ca_ap_size / tioca_kern->ca_ap_pagesize; + + ap_reg |= (CA_GART_AP_ENB_AGP | CA_GART_AP_ENB_PCI); + ap_reg |= tioca_kern->ca_ap_bus_base; + + /* + * Allocate and set up the GART + */ + + tioca_kern->ca_gart_size = tioca_kern->ca_gart_entries * sizeof(u64); + tmp = + alloc_pages_node(tioca_kern->ca_closest_node, + GFP_KERNEL | __GFP_ZERO, + get_order(tioca_kern->ca_gart_size)); + + if (!tmp) { + printk(KERN_ERR "%s: Could not allocate " + "%lu bytes (order %d) for GART\n", + __FUNCTION__, + tioca_kern->ca_gart_size, + get_order(tioca_kern->ca_gart_size)); + return -ENOMEM; + } + + tioca_kern->ca_gart = page_address(tmp); + tioca_kern->ca_gart_coretalk_addr = + PHYS_TO_TIODMA(virt_to_phys(tioca_kern->ca_gart)); + + /* + * Compute PCI/AGP convenience fields + */ + + offset = CA_PCI32_MAPPED_BASE - CA_APERATURE_BASE; + tioca_kern->ca_pciap_base = CA_PCI32_MAPPED_BASE; + tioca_kern->ca_pciap_size = CA_PCI32_MAPPED_SIZE; + tioca_kern->ca_pcigart_start = offset / tioca_kern->ca_ap_pagesize; + tioca_kern->ca_pcigart_base = + tioca_kern->ca_gart_coretalk_addr + offset; + tioca_kern->ca_pcigart = + &tioca_kern->ca_gart[tioca_kern->ca_pcigart_start]; + tioca_kern->ca_pcigart_entries = + tioca_kern->ca_pciap_size / tioca_kern->ca_ap_pagesize; + tioca_kern->ca_pcigart_pagemap = + kcalloc(1, tioca_kern->ca_pcigart_entries / 8, GFP_KERNEL); + if (!tioca_kern->ca_pcigart_pagemap) { + free_pages((unsigned long)tioca_kern->ca_gart, + get_order(tioca_kern->ca_gart_size)); + return -1; + } + + offset = CA_AGP_MAPPED_BASE - CA_APERATURE_BASE; + tioca_kern->ca_gfxap_base = CA_AGP_MAPPED_BASE; + tioca_kern->ca_gfxap_size = CA_AGP_MAPPED_SIZE; + tioca_kern->ca_gfxgart_start = offset / tioca_kern->ca_ap_pagesize; + tioca_kern->ca_gfxgart_base = + tioca_kern->ca_gart_coretalk_addr + offset; + tioca_kern->ca_gfxgart = + &tioca_kern->ca_gart[tioca_kern->ca_gfxgart_start]; + tioca_kern->ca_gfxgart_entries = + tioca_kern->ca_gfxap_size / tioca_kern->ca_ap_pagesize; + + /* + * various control settings: + * use agp op-combining + * use GET semantics to fetch memory + * participate in coherency domain + * prefetch TLB entries + */ + + ca_base->ca_control1 |= CA_AGPDMA_OP_ENB_COMBDELAY; /* PV895469 ? */ + ca_base->ca_control2 &= ~(CA_GART_MEM_PARAM); + ca_base->ca_control2 |= (0x2ull << CA_GART_MEM_PARAM_SHFT); + tioca_kern->ca_gart_iscoherent = 1; + ca_base->ca_control2 |= + (CA_GART_WR_PREFETCH_ENB | CA_GART_RD_PREFETCH_ENB); + + /* + * Unmask GART fetch error interrupts. Clear residual errors first. + */ + + ca_base->ca_int_status_alias = CA_GART_FETCH_ERR; + ca_base->ca_mult_error_alias = CA_GART_FETCH_ERR; + ca_base->ca_int_mask &= ~CA_GART_FETCH_ERR; + + /* + * Program the aperature and gart registers in TIOCA + */ + + ca_base->ca_gart_aperature = ap_reg; + ca_base->ca_gart_ptr_table = tioca_kern->ca_gart_coretalk_addr | 1; + + return 0; +} + +/** + * tioca_fastwrite_enable - enable AGP FW for a tioca and its functions + * @tioca_kernel: structure representing the CA + * + * Given a CA, scan all attached functions making sure they all support + * FastWrite. If so, enable FastWrite for all functions and the CA itself. + */ + +void +tioca_fastwrite_enable(struct tioca_kernel *tioca_kern) +{ + int cap_ptr; + uint64_t ca_control1; + uint32_t reg; + struct tioca *tioca_base; + struct pci_dev *pdev; + struct tioca_common *common; + + common = tioca_kern->ca_common; + + /* + * Scan all vga controllers on this bus making sure they all + * suport FW. If not, return. + */ + + list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) { + if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) + continue; + + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (!cap_ptr) + return; /* no AGP CAP means no FW */ + + pci_read_config_dword(pdev, cap_ptr + PCI_AGP_STATUS, ®); + if (!(reg & PCI_AGP_STATUS_FW)) + return; /* function doesn't support FW */ + } + + /* + * Set fw for all vga fn's + */ + + list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) { + if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) + continue; + + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); + pci_read_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, ®); + reg |= PCI_AGP_COMMAND_FW; + pci_write_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, reg); + } + + /* + * Set ca's fw to match + */ + + tioca_base = (struct tioca *)common->ca_common.bs_base; + ca_control1 = tioca_base->ca_control1; + ca_control1 |= CA_AGP_FW_ENABLE; + tioca_base->ca_control1 = ca_control1; +} + +EXPORT_SYMBOL(tioca_fastwrite_enable); /* used by agp-sgi */ + +/** + * tioca_dma_d64 - create a DMA mapping using 64-bit direct mode + * @paddr: system physical address + * + * Map @paddr into 64-bit CA bus space. No device context is necessary. + * Bits 53:0 come from the coretalk address. We just need to mask in the + * following optional bits of the 64-bit pci address: + * + * 63:60 - Coretalk Packet Type - 0x1 for Mem Get/Put (coherent) + * 0x2 for PIO (non-coherent) + * We will always use 0x1 + * 55:55 - Swap bytes Currently unused + */ +static uint64_t +tioca_dma_d64(unsigned long paddr) +{ + dma_addr_t bus_addr; + + bus_addr = PHYS_TO_TIODMA(paddr); + + BUG_ON(!bus_addr); + BUG_ON(bus_addr >> 54); + + /* Set upper nibble to Cache Coherent Memory op */ + bus_addr |= (1UL << 60); + + return bus_addr; +} + +/** + * tioca_dma_d48 - create a DMA mapping using 48-bit direct mode + * @pdev: linux pci_dev representing the function + * @paddr: system physical address + * + * Map @paddr into 64-bit bus space of the CA associated with @pcidev_info. + * + * The CA agp 48 bit direct address falls out as follows: + * + * When direct mapping AGP addresses, the 48 bit AGP address is + * constructed as follows: + * + * [47:40] - Low 8 bits of the page Node ID extracted from coretalk + * address [47:40]. The upper 8 node bits are fixed + * and come from the xxx register bits [5:0] + * [39:38] - Chiplet ID extracted from coretalk address [39:38] + * [37:00] - node offset extracted from coretalk address [37:00] + * + * Since the node id in general will be non-zero, and the chiplet id + * will always be non-zero, it follows that the device must support + * a dma mask of at least 0xffffffffff (40 bits) to target node 0 + * and in general should be 0xffffffffffff (48 bits) to target nodes + * up to 255. Nodes above 255 need the support of the xxx register, + * and so a given CA can only directly target nodes in the range + * xxx - xxx+255. + */ +static uint64_t +tioca_dma_d48(struct pci_dev *pdev, uint64_t paddr) +{ + struct tioca_common *tioca_common; + struct tioca *ca_base; + uint64_t ct_addr; + dma_addr_t bus_addr; + uint32_t node_upper; + uint64_t agp_dma_extn; + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); + + tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; + ca_base = (struct tioca *)tioca_common->ca_common.bs_base; + + ct_addr = PHYS_TO_TIODMA(paddr); + if (!ct_addr) + return 0; + + bus_addr = (dma_addr_t) (ct_addr & 0xffffffffffff); + node_upper = ct_addr >> 48; + + if (node_upper > 64) { + printk(KERN_ERR "%s: coretalk addr 0x%p node id out " + "of range\n", __FUNCTION__, (void *)ct_addr); + return 0; + } + + agp_dma_extn = ca_base->ca_agp_dma_addr_extn; + if (node_upper != (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)) { + printk(KERN_ERR "%s: coretalk upper node (%u) " + "mismatch with ca_agp_dma_addr_extn (%lu)\n", + __FUNCTION__, + node_upper, (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)); + return 0; + } + + return bus_addr; +} + +/** + * tioca_dma_mapped - create a DMA mapping using a CA GART + * @pdev: linux pci_dev representing the function + * @paddr: host physical address to map + * @req_size: len (bytes) to map + * + * Map @paddr into CA address space using the GART mechanism. The mapped + * dma_addr_t is guarenteed to be contiguous in CA bus space. + */ +static dma_addr_t +tioca_dma_mapped(struct pci_dev *pdev, uint64_t paddr, size_t req_size) +{ + int i, ps, ps_shift, entry, entries, mapsize, last_entry; + uint64_t xio_addr, end_xio_addr; + struct tioca_common *tioca_common; + struct tioca_kernel *tioca_kern; + dma_addr_t bus_addr = 0; + struct tioca_dmamap *ca_dmamap; + void *map; + unsigned long flags; + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);; + + tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; + tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private; + + xio_addr = PHYS_TO_TIODMA(paddr); + if (!xio_addr) + return 0; + + spin_lock_irqsave(&tioca_kern->ca_lock, flags); + + /* + * allocate a map struct + */ + + ca_dmamap = kcalloc(1, sizeof(struct tioca_dmamap), GFP_ATOMIC); + if (!ca_dmamap) + goto map_return; + + /* + * Locate free entries that can hold req_size. Account for + * unaligned start/length when allocating. + */ + + ps = tioca_kern->ca_ap_pagesize; /* will be power of 2 */ + ps_shift = ffs(ps) - 1; + end_xio_addr = xio_addr + req_size - 1; + + entries = (end_xio_addr >> ps_shift) - (xio_addr >> ps_shift) + 1; + + map = tioca_kern->ca_pcigart_pagemap; + mapsize = tioca_kern->ca_pcigart_entries; + + entry = find_first_zero_bit(map, mapsize); + while (entry < mapsize) { + last_entry = find_next_bit(map, mapsize, entry); + + if (last_entry - entry >= entries) + break; + + entry = find_next_zero_bit(map, mapsize, last_entry); + } + + if (entry > mapsize) + goto map_return; + + for (i = 0; i < entries; i++) + set_bit(entry + i, map); + + bus_addr = tioca_kern->ca_pciap_base + (entry * ps); + + ca_dmamap->cad_dma_addr = bus_addr; + ca_dmamap->cad_gart_size = entries; + ca_dmamap->cad_gart_entry = entry; + list_add(&ca_dmamap->cad_list, &tioca_kern->ca_list); + + if (xio_addr % ps) { + tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr); + bus_addr += xio_addr & (ps - 1); + xio_addr &= ~(ps - 1); + xio_addr += ps; + entry++; + } + + while (xio_addr < end_xio_addr) { + tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr); + xio_addr += ps; + entry++; + } + + tioca_tlbflush(tioca_kern); + +map_return: + spin_unlock_irqrestore(&tioca_kern->ca_lock, flags); + return bus_addr; +} + +/** + * tioca_dma_unmap - release CA mapping resources + * @pdev: linux pci_dev representing the function + * @bus_addr: bus address returned by an earlier tioca_dma_map + * @dir: mapping direction (unused) + * + * Locate mapping resources associated with @bus_addr and release them. + * For mappings created using the direct modes (64 or 48) there are no + * resources to release. + */ +void +tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) +{ + int i, entry; + struct tioca_common *tioca_common; + struct tioca_kernel *tioca_kern; + struct tioca_dmamap *map; + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); + unsigned long flags; + + tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; + tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private; + + /* return straight away if this isn't be a mapped address */ + + if (bus_addr < tioca_kern->ca_pciap_base || + bus_addr >= (tioca_kern->ca_pciap_base + tioca_kern->ca_pciap_size)) + return; + + spin_lock_irqsave(&tioca_kern->ca_lock, flags); + + list_for_each_entry(map, &tioca_kern->ca_dmamaps, cad_list) + if (map->cad_dma_addr == bus_addr) + break; + + BUG_ON(map == NULL); + + entry = map->cad_gart_entry; + + for (i = 0; i < map->cad_gart_size; i++, entry++) { + clear_bit(entry, tioca_kern->ca_pcigart_pagemap); + tioca_kern->ca_pcigart[entry] = 0; + } + tioca_tlbflush(tioca_kern); + + list_del(&map->cad_list); + spin_unlock_irqrestore(&tioca_kern->ca_lock, flags); + kfree(map); +} + +/** + * tioca_dma_map - map pages for PCI DMA + * @pdev: linux pci_dev representing the function + * @paddr: host physical address to map + * @byte_count: bytes to map + * + * This is the main wrapper for mapping host physical pages to CA PCI space. + * The mapping mode used is based on the devices dma_mask. As a last resort + * use the GART mapped mode. + */ +uint64_t +tioca_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count) +{ + uint64_t mapaddr; + + /* + * If card is 64 or 48 bit addresable, use a direct mapping. 32 + * bit direct is so restrictive w.r.t. where the memory resides that + * we don't use it even though CA has some support. + */ + + if (pdev->dma_mask == ~0UL) + mapaddr = tioca_dma_d64(paddr); + else if (pdev->dma_mask == 0xffffffffffffUL) + mapaddr = tioca_dma_d48(pdev, paddr); + else + mapaddr = 0; + + /* Last resort ... use PCI portion of CA GART */ + + if (mapaddr == 0) + mapaddr = tioca_dma_mapped(pdev, paddr, byte_count); + + return mapaddr; +} + +/** + * tioca_error_intr_handler - SGI TIO CA error interrupt handler + * @irq: unused + * @arg: pointer to tioca_common struct for the given CA + * @pt: unused + * + * Handle a CA error interrupt. Simply a wrapper around a SAL call which + * defers processing to the SGI prom. + */ +static irqreturn_t +tioca_error_intr_handler(int irq, void *arg, struct pt_regs *pt) +{ + struct tioca_common *soft = arg; + struct ia64_sal_retval ret_stuff; + uint64_t segment; + uint64_t busnum; + ret_stuff.status = 0; + ret_stuff.v0 = 0; + + segment = 0; + busnum = soft->ca_common.bs_persist_busnum; + + SAL_CALL_NOLOCK(ret_stuff, + (u64) SN_SAL_IOIF_ERROR_INTERRUPT, + segment, busnum, 0, 0, 0, 0, 0); + + return IRQ_HANDLED; +} + +/** + * tioca_bus_fixup - perform final PCI fixup for a TIO CA bus + * @prom_bussoft: Common prom/kernel struct representing the bus + * + * Replicates the tioca_common pointed to by @prom_bussoft in kernel + * space. Allocates and initializes a kernel-only area for a given CA, + * and sets up an irq for handling CA error interrupts. + * + * On successful setup, returns the kernel version of tioca_common back to + * the caller. + */ +void * +tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft) +{ + struct tioca_common *tioca_common; + struct tioca_kernel *tioca_kern; + struct pci_bus *bus; + + /* sanity check prom rev */ + + if (sn_sal_rev_major() < 4 || + (sn_sal_rev_major() == 4 && sn_sal_rev_minor() < 6)) { + printk + (KERN_ERR "%s: SGI prom rev 4.06 or greater required " + "for tioca support\n", __FUNCTION__); + return NULL; + } + + /* + * Allocate kernel bus soft and copy from prom. + */ + + tioca_common = kcalloc(1, sizeof(struct tioca_common), GFP_KERNEL); + if (!tioca_common) + return NULL; + + memcpy(tioca_common, prom_bussoft, sizeof(struct tioca_common)); + tioca_common->ca_common.bs_base |= __IA64_UNCACHED_OFFSET; + + /* init kernel-private area */ + + tioca_kern = kcalloc(1, sizeof(struct tioca_kernel), GFP_KERNEL); + if (!tioca_kern) { + kfree(tioca_common); + return NULL; + } + + tioca_kern->ca_common = tioca_common; + spin_lock_init(&tioca_kern->ca_lock); + INIT_LIST_HEAD(&tioca_kern->ca_dmamaps); + tioca_kern->ca_closest_node = + nasid_to_cnodeid(tioca_common->ca_closest_nasid); + tioca_common->ca_kernel_private = (uint64_t) tioca_kern; + + bus = pci_find_bus(0, tioca_common->ca_common.bs_persist_busnum); + BUG_ON(!bus); + tioca_kern->ca_devices = &bus->devices; + + /* init GART */ + + if (tioca_gart_init(tioca_kern) < 0) { + kfree(tioca_kern); + kfree(tioca_common); + return NULL; + } + + tioca_gart_found++; + list_add(&tioca_kern->ca_list, &tioca_list); + + if (request_irq(SGI_TIOCA_ERROR, + tioca_error_intr_handler, + SA_SHIRQ, "TIOCA error", (void *)tioca_common)) + printk(KERN_WARNING + "%s: Unable to get irq %d. " + "Error interrupts won't be routed for TIOCA bus %d\n", + __FUNCTION__, SGI_TIOCA_ERROR, + (int)tioca_common->ca_common.bs_persist_busnum); + + return tioca_common; +} + +static struct sn_pcibus_provider tioca_pci_interfaces = { + .dma_map = tioca_dma_map, + .dma_map_consistent = tioca_dma_map, + .dma_unmap = tioca_dma_unmap, + .bus_fixup = tioca_bus_fixup, +}; + +/** + * tioca_init_provider - init SN PCI provider ops for TIO CA + */ +int +tioca_init_provider(void) +{ + sn_pci_provider[PCIIO_ASIC_TYPE_TIOCA] = &tioca_pci_interfaces; + return 0; +} diff --git a/include/asm-ia64/sn/pcibus_provider_defs.h b/include/asm-ia64/sn/pcibus_provider_defs.h index f546b4e..04e27d5 100644 --- a/include/asm-ia64/sn/pcibus_provider_defs.h +++ b/include/asm-ia64/sn/pcibus_provider_defs.h @@ -17,8 +17,9 @@ #define PCIIO_ASIC_TYPE_PPB 1 #define PCIIO_ASIC_TYPE_PIC 2 #define PCIIO_ASIC_TYPE_TIOCP 3 +#define PCIIO_ASIC_TYPE_TIOCA 4 -#define PCIIO_ASIC_MAX_TYPES 4 +#define PCIIO_ASIC_MAX_TYPES 5 /* * Common pciio bus provider data. There should be one of these as the diff --git a/include/asm-ia64/sn/tioca.h b/include/asm-ia64/sn/tioca.h new file mode 100644 index 0000000..bc1aacf --- /dev/null +++ b/include/asm-ia64/sn/tioca.h @@ -0,0 +1,596 @@ +#ifndef _ASM_IA64_SN_TIO_TIOCA_H +#define _ASM_IA64_SN_TIO_TIOCA_H + +/* + * 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. + * + * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved. + */ + + +#define TIOCA_PART_NUM 0xE020 +#define TIOCA_MFGR_NUM 0x24 +#define TIOCA_REV_A 0x1 + +/* + * Register layout for TIO:CA. See below for bitmasks for each register. + */ + +struct tioca { + uint64_t ca_id; /* 0x000000 */ + uint64_t ca_control1; /* 0x000008 */ + uint64_t ca_control2; /* 0x000010 */ + uint64_t ca_status1; /* 0x000018 */ + uint64_t ca_status2; /* 0x000020 */ + uint64_t ca_gart_aperature; /* 0x000028 */ + uint64_t ca_gfx_detach; /* 0x000030 */ + uint64_t ca_inta_dest_addr; /* 0x000038 */ + uint64_t ca_intb_dest_addr; /* 0x000040 */ + uint64_t ca_err_int_dest_addr; /* 0x000048 */ + uint64_t ca_int_status; /* 0x000050 */ + uint64_t ca_int_status_alias; /* 0x000058 */ + uint64_t ca_mult_error; /* 0x000060 */ + uint64_t ca_mult_error_alias; /* 0x000068 */ + uint64_t ca_first_error; /* 0x000070 */ + uint64_t ca_int_mask; /* 0x000078 */ + uint64_t ca_crm_pkterr_type; /* 0x000080 */ + uint64_t ca_crm_pkterr_type_alias; /* 0x000088 */ + uint64_t ca_crm_ct_error_detail_1; /* 0x000090 */ + uint64_t ca_crm_ct_error_detail_2; /* 0x000098 */ + uint64_t ca_crm_tnumto; /* 0x0000A0 */ + uint64_t ca_gart_err; /* 0x0000A8 */ + uint64_t ca_pcierr_type; /* 0x0000B0 */ + uint64_t ca_pcierr_addr; /* 0x0000B8 */ + + uint64_t ca_pad_0000C0[3]; /* 0x0000{C0..D0} */ + + uint64_t ca_pci_rd_buf_flush; /* 0x0000D8 */ + uint64_t ca_pci_dma_addr_extn; /* 0x0000E0 */ + uint64_t ca_agp_dma_addr_extn; /* 0x0000E8 */ + uint64_t ca_force_inta; /* 0x0000F0 */ + uint64_t ca_force_intb; /* 0x0000F8 */ + uint64_t ca_debug_vector_sel; /* 0x000100 */ + uint64_t ca_debug_mux_core_sel; /* 0x000108 */ + uint64_t ca_debug_mux_pci_sel; /* 0x000110 */ + uint64_t ca_debug_domain_sel; /* 0x000118 */ + + uint64_t ca_pad_000120[28]; /* 0x0001{20..F8} */ + + uint64_t ca_gart_ptr_table; /* 0x200 */ + uint64_t ca_gart_tlb_addr[8]; /* 0x2{08..40} */ +}; + +/* + * Mask/shift definitions for TIO:CA registers. The convention here is + * to mainly use the names as they appear in the "TIO AEGIS Programmers' + * Reference" with a CA_ prefix added. Some exceptions were made to fix + * duplicate field names or to generalize fields that are common to + * different registers (ca_debug_mux_core_sel and ca_debug_mux_pci_sel for + * example). + * + * Fields consisting of a single bit have a single #define have a single + * macro declaration to mask the bit. Fields consisting of multiple bits + * have two declarations: one to mask the proper bits in a register, and + * a second with the suffix "_SHFT" to identify how far the mask needs to + * be shifted right to get its base value. + */ + +/* ==== ca_control1 */ +#define CA_SYS_BIG_END (1ull << 0) +#define CA_DMA_AGP_SWAP (1ull << 1) +#define CA_DMA_PCI_SWAP (1ull << 2) +#define CA_PIO_IO_SWAP (1ull << 3) +#define CA_PIO_MEM_SWAP (1ull << 4) +#define CA_GFX_WR_SWAP (1ull << 5) +#define CA_AGP_FW_ENABLE (1ull << 6) +#define CA_AGP_CAL_CYCLE (0x7ull << 7) +#define CA_AGP_CAL_CYCLE_SHFT 7 +#define CA_AGP_CAL_PRSCL_BYP (1ull << 10) +#define CA_AGP_INIT_CAL_ENB (1ull << 11) +#define CA_INJ_ADDR_PERR (1ull << 12) +#define CA_INJ_DATA_PERR (1ull << 13) + /* bits 15:14 unused */ +#define CA_PCIM_IO_NBE_AD (0x7ull << 16) +#define CA_PCIM_IO_NBE_AD_SHFT 16 +#define CA_PCIM_FAST_BTB_ENB (1ull << 19) + /* bits 23:20 unused */ +#define CA_PIO_ADDR_OFFSET (0xffull << 24) +#define CA_PIO_ADDR_OFFSET_SHFT 24 + /* bits 35:32 unused */ +#define CA_AGPDMA_OP_COMBDELAY (0x1full << 36) +#define CA_AGPDMA_OP_COMBDELAY_SHFT 36 + /* bit 41 unused */ +#define CA_AGPDMA_OP_ENB_COMBDELAY (1ull << 42) +#define CA_PCI_INT_LPCNT (0xffull << 44) +#define CA_PCI_INT_LPCNT_SHFT 44 + /* bits 63:52 unused */ + +/* ==== ca_control2 */ +#define CA_AGP_LATENCY_TO (0xffull << 0) +#define CA_AGP_LATENCY_TO_SHFT 0 +#define CA_PCI_LATENCY_TO (0xffull << 8) +#define CA_PCI_LATENCY_TO_SHFT 8 +#define CA_PCI_MAX_RETRY (0x3ffull << 16) +#define CA_PCI_MAX_RETRY_SHFT 16 + /* bits 27:26 unused */ +#define CA_RT_INT_EN (0x3ull << 28) +#define CA_RT_INT_EN_SHFT 28 +#define CA_MSI_INT_ENB (1ull << 30) +#define CA_PCI_ARB_ERR_ENB (1ull << 31) +#define CA_GART_MEM_PARAM (0x3ull << 32) +#define CA_GART_MEM_PARAM_SHFT 32 +#define CA_GART_RD_PREFETCH_ENB (1ull << 34) +#define CA_GART_WR_PREFETCH_ENB (1ull << 35) +#define CA_GART_FLUSH_TLB (1ull << 36) + /* bits 39:37 unused */ +#define CA_CRM_TNUMTO_PERIOD (0x1fffull << 40) +#define CA_CRM_TNUMTO_PERIOD_SHFT 40 + /* bits 55:53 unused */ +#define CA_CRM_TNUMTO_ENB (1ull << 56) +#define CA_CRM_PRESCALER_BYP (1ull << 57) + /* bits 59:58 unused */ +#define CA_CRM_MAX_CREDIT (0x7ull << 60) +#define CA_CRM_MAX_CREDIT_SHFT 60 + /* bit 63 unused */ + +/* ==== ca_status1 */ +#define CA_CORELET_ID (0x3ull << 0) +#define CA_CORELET_ID_SHFT 0 +#define CA_INTA_N (1ull << 2) +#define CA_INTB_N (1ull << 3) +#define CA_CRM_CREDIT_AVAIL (0x7ull << 4) +#define CA_CRM_CREDIT_AVAIL_SHFT 4 + /* bit 7 unused */ +#define CA_CRM_SPACE_AVAIL (0x7full << 8) +#define CA_CRM_SPACE_AVAIL_SHFT 8 + /* bit 15 unused */ +#define CA_GART_TLB_VAL (0xffull << 16) +#define CA_GART_TLB_VAL_SHFT 16 + /* bits 63:24 unused */ + +/* ==== ca_status2 */ +#define CA_GFX_CREDIT_AVAIL (0xffull << 0) +#define CA_GFX_CREDIT_AVAIL_SHFT 0 +#define CA_GFX_OPQ_AVAIL (0xffull << 8) +#define CA_GFX_OPQ_AVAIL_SHFT 8 +#define CA_GFX_WRBUFF_AVAIL (0xffull << 16) +#define CA_GFX_WRBUFF_AVAIL_SHFT 16 +#define CA_ADMA_OPQ_AVAIL (0xffull << 24) +#define CA_ADMA_OPQ_AVAIL_SHFT 24 +#define CA_ADMA_WRBUFF_AVAIL (0xffull << 32) +#define CA_ADMA_WRBUFF_AVAIL_SHFT 32 +#define CA_ADMA_RDBUFF_AVAIL (0x7full << 40) +#define CA_ADMA_RDBUFF_AVAIL_SHFT 40 +#define CA_PCI_PIO_OP_STAT (1ull << 47) +#define CA_PDMA_OPQ_AVAIL (0xfull << 48) +#define CA_PDMA_OPQ_AVAIL_SHFT 48 +#define CA_PDMA_WRBUFF_AVAIL (0xfull << 52) +#define CA_PDMA_WRBUFF_AVAIL_SHFT 52 +#define CA_PDMA_RDBUFF_AVAIL (0x3ull << 56) +#define CA_PDMA_RDBUFF_AVAIL_SHFT 56 + /* bits 63:58 unused */ + +/* ==== ca_gart_aperature */ +#define CA_GART_AP_ENB_AGP (1ull << 0) +#define CA_GART_PAGE_SIZE (1ull << 1) +#define CA_GART_AP_ENB_PCI (1ull << 2) + /* bits 11:3 unused */ +#define CA_GART_AP_SIZE (0x3ffull << 12) +#define CA_GART_AP_SIZE_SHFT 12 +#define CA_GART_AP_BASE (0x3ffffffffffull << 22) +#define CA_GART_AP_BASE_SHFT 22 + +/* ==== ca_inta_dest_addr + ==== ca_intb_dest_addr + ==== ca_err_int_dest_addr */ + /* bits 2:0 unused */ +#define CA_INT_DEST_ADDR (0x7ffffffffffffull << 3) +#define CA_INT_DEST_ADDR_SHFT 3 + /* bits 55:54 unused */ +#define CA_INT_DEST_VECT (0xffull << 56) +#define CA_INT_DEST_VECT_SHFT 56 + +/* ==== ca_int_status */ +/* ==== ca_int_status_alias */ +/* ==== ca_mult_error */ +/* ==== ca_mult_error_alias */ +/* ==== ca_first_error */ +/* ==== ca_int_mask */ +#define CA_PCI_ERR (1ull << 0) + /* bits 3:1 unused */ +#define CA_GART_FETCH_ERR (1ull << 4) +#define CA_GFX_WR_OVFLW (1ull << 5) +#define CA_PIO_REQ_OVFLW (1ull << 6) +#define CA_CRM_PKTERR (1ull << 7) +#define CA_CRM_DVERR (1ull << 8) +#define CA_TNUMTO (1ull << 9) +#define CA_CXM_RSP_CRED_OVFLW (1ull << 10) +#define CA_CXM_REQ_CRED_OVFLW (1ull << 11) +#define CA_PIO_INVALID_ADDR (1ull << 12) +#define CA_PCI_ARB_TO (1ull << 13) +#define CA_AGP_REQ_OFLOW (1ull << 14) +#define CA_SBA_TYPE1_ERR (1ull << 15) + /* bit 16 unused */ +#define CA_INTA (1ull << 17) +#define CA_INTB (1ull << 18) +#define CA_MULT_INTA (1ull << 19) +#define CA_MULT_INTB (1ull << 20) +#define CA_GFX_CREDIT_OVFLW (1ull << 21) + /* bits 63:22 unused */ + +/* ==== ca_crm_pkterr_type */ +/* ==== ca_crm_pkterr_type_alias */ +#define CA_CRM_PKTERR_SBERR_HDR (1ull << 0) +#define CA_CRM_PKTERR_DIDN (1ull << 1) +#define CA_CRM_PKTERR_PACTYPE (1ull << 2) +#define CA_CRM_PKTERR_INV_TNUM (1ull << 3) +#define CA_CRM_PKTERR_ADDR_RNG (1ull << 4) +#define CA_CRM_PKTERR_ADDR_ALGN (1ull << 5) +#define CA_CRM_PKTERR_HDR_PARAM (1ull << 6) +#define CA_CRM_PKTERR_CW_ERR (1ull << 7) +#define CA_CRM_PKTERR_SBERR_NH (1ull << 8) +#define CA_CRM_PKTERR_EARLY_TERM (1ull << 9) +#define CA_CRM_PKTERR_EARLY_TAIL (1ull << 10) +#define CA_CRM_PKTERR_MSSNG_TAIL (1ull << 11) +#define CA_CRM_PKTERR_MSSNG_HDR (1ull << 12) + /* bits 15:13 unused */ +#define CA_FIRST_CRM_PKTERR_SBERR_HDR (1ull << 16) +#define CA_FIRST_CRM_PKTERR_DIDN (1ull << 17) +#define CA_FIRST_CRM_PKTERR_PACTYPE (1ull << 18) +#define CA_FIRST_CRM_PKTERR_INV_TNUM (1ull << 19) +#define CA_FIRST_CRM_PKTERR_ADDR_RNG (1ull << 20) +#define CA_FIRST_CRM_PKTERR_ADDR_ALGN (1ull << 21) +#define CA_FIRST_CRM_PKTERR_HDR_PARAM (1ull << 22) +#define CA_FIRST_CRM_PKTERR_CW_ERR (1ull << 23) +#define CA_FIRST_CRM_PKTERR_SBERR_NH (1ull << 24) +#define CA_FIRST_CRM_PKTERR_EARLY_TERM (1ull << 25) +#define CA_FIRST_CRM_PKTERR_EARLY_TAIL (1ull << 26) +#define CA_FIRST_CRM_PKTERR_MSSNG_TAIL (1ull << 27) +#define CA_FIRST_CRM_PKTERR_MSSNG_HDR (1ull << 28) + /* bits 63:29 unused */ + +/* ==== ca_crm_ct_error_detail_1 */ +#define CA_PKT_TYPE (0xfull << 0) +#define CA_PKT_TYPE_SHFT 0 +#define CA_SRC_ID (0x3ull << 4) +#define CA_SRC_ID_SHFT 4 +#define CA_DATA_SZ (0x3ull << 6) +#define CA_DATA_SZ_SHFT 6 +#define CA_TNUM (0xffull << 8) +#define CA_TNUM_SHFT 8 +#define CA_DW_DATA_EN (0xffull << 16) +#define CA_DW_DATA_EN_SHFT 16 +#define CA_GFX_CRED (0xffull << 24) +#define CA_GFX_CRED_SHFT 24 +#define CA_MEM_RD_PARAM (0x3ull << 32) +#define CA_MEM_RD_PARAM_SHFT 32 +#define CA_PIO_OP (1ull << 34) +#define CA_CW_ERR (1ull << 35) + /* bits 62:36 unused */ +#define CA_VALID (1ull << 63) + +/* ==== ca_crm_ct_error_detail_2 */ + /* bits 2:0 unused */ +#define CA_PKT_ADDR (0x1fffffffffffffull << 3) +#define CA_PKT_ADDR_SHFT 3 + /* bits 63:56 unused */ + +/* ==== ca_crm_tnumto */ +#define CA_CRM_TNUMTO_VAL (0xffull << 0) +#define CA_CRM_TNUMTO_VAL_SHFT 0 +#define CA_CRM_TNUMTO_WR (1ull << 8) + /* bits 63:9 unused */ + +/* ==== ca_gart_err */ +#define CA_GART_ERR_SOURCE (0x3ull << 0) +#define CA_GART_ERR_SOURCE_SHFT 0 + /* bits 3:2 unused */ +#define CA_GART_ERR_ADDR (0xfffffffffull << 4) +#define CA_GART_ERR_ADDR_SHFT 4 + /* bits 63:40 unused */ + +/* ==== ca_pcierr_type */ +#define CA_PCIERR_DATA (0xffffffffull << 0) +#define CA_PCIERR_DATA_SHFT 0 +#define CA_PCIERR_ENB (0xfull << 32) +#define CA_PCIERR_ENB_SHFT 32 +#define CA_PCIERR_CMD (0xfull << 36) +#define CA_PCIERR_CMD_SHFT 36 +#define CA_PCIERR_A64 (1ull << 40) +#define CA_PCIERR_SLV_SERR (1ull << 41) +#define CA_PCIERR_SLV_WR_PERR (1ull << 42) +#define CA_PCIERR_SLV_RD_PERR (1ull << 43) +#define CA_PCIERR_MST_SERR (1ull << 44) +#define CA_PCIERR_MST_WR_PERR (1ull << 45) +#define CA_PCIERR_MST_RD_PERR (1ull << 46) +#define CA_PCIERR_MST_MABT (1ull << 47) +#define CA_PCIERR_MST_TABT (1ull << 48) +#define CA_PCIERR_MST_RETRY_TOUT (1ull << 49) + +#define CA_PCIERR_TYPES \ + (CA_PCIERR_A64|CA_PCIERR_SLV_SERR| \ + CA_PCIERR_SLV_WR_PERR|CA_PCIERR_SLV_RD_PERR| \ + CA_PCIERR_MST_SERR|CA_PCIERR_MST_WR_PERR|CA_PCIERR_MST_RD_PERR| \ + CA_PCIERR_MST_MABT|CA_PCIERR_MST_TABT|CA_PCIERR_MST_RETRY_TOUT) + + /* bits 63:50 unused */ + +/* ==== ca_pci_dma_addr_extn */ +#define CA_UPPER_NODE_OFFSET (0x3full << 0) +#define CA_UPPER_NODE_OFFSET_SHFT 0 + /* bits 7:6 unused */ +#define CA_CHIPLET_ID (0x3ull << 8) +#define CA_CHIPLET_ID_SHFT 8 + /* bits 11:10 unused */ +#define CA_PCI_DMA_NODE_ID (0xffffull << 12) +#define CA_PCI_DMA_NODE_ID_SHFT 12 + /* bits 27:26 unused */ +#define CA_PCI_DMA_PIO_MEM_TYPE (1ull << 28) + /* bits 63:29 unused */ + + +/* ==== ca_agp_dma_addr_extn */ + /* bits 19:0 unused */ +#define CA_AGP_DMA_NODE_ID (0xffffull << 20) +#define CA_AGP_DMA_NODE_ID_SHFT 20 + /* bits 27:26 unused */ +#define CA_AGP_DMA_PIO_MEM_TYPE (1ull << 28) + /* bits 63:29 unused */ + +/* ==== ca_debug_vector_sel */ +#define CA_DEBUG_MN_VSEL (0xfull << 0) +#define CA_DEBUG_MN_VSEL_SHFT 0 +#define CA_DEBUG_PP_VSEL (0xfull << 4) +#define CA_DEBUG_PP_VSEL_SHFT 4 +#define CA_DEBUG_GW_VSEL (0xfull << 8) +#define CA_DEBUG_GW_VSEL_SHFT 8 +#define CA_DEBUG_GT_VSEL (0xfull << 12) +#define CA_DEBUG_GT_VSEL_SHFT 12 +#define CA_DEBUG_PD_VSEL (0xfull << 16) +#define CA_DEBUG_PD_VSEL_SHFT 16 +#define CA_DEBUG_AD_VSEL (0xfull << 20) +#define CA_DEBUG_AD_VSEL_SHFT 20 +#define CA_DEBUG_CX_VSEL (0xfull << 24) +#define CA_DEBUG_CX_VSEL_SHFT 24 +#define CA_DEBUG_CR_VSEL (0xfull << 28) +#define CA_DEBUG_CR_VSEL_SHFT 28 +#define CA_DEBUG_BA_VSEL (0xfull << 32) +#define CA_DEBUG_BA_VSEL_SHFT 32 +#define CA_DEBUG_PE_VSEL (0xfull << 36) +#define CA_DEBUG_PE_VSEL_SHFT 36 +#define CA_DEBUG_BO_VSEL (0xfull << 40) +#define CA_DEBUG_BO_VSEL_SHFT 40 +#define CA_DEBUG_BI_VSEL (0xfull << 44) +#define CA_DEBUG_BI_VSEL_SHFT 44 +#define CA_DEBUG_AS_VSEL (0xfull << 48) +#define CA_DEBUG_AS_VSEL_SHFT 48 +#define CA_DEBUG_PS_VSEL (0xfull << 52) +#define CA_DEBUG_PS_VSEL_SHFT 52 +#define CA_DEBUG_PM_VSEL (0xfull << 56) +#define CA_DEBUG_PM_VSEL_SHFT 56 + /* bits 63:60 unused */ + +/* ==== ca_debug_mux_core_sel */ +/* ==== ca_debug_mux_pci_sel */ +#define CA_DEBUG_MSEL0 (0x7ull << 0) +#define CA_DEBUG_MSEL0_SHFT 0 + /* bit 3 unused */ +#define CA_DEBUG_NSEL0 (0x7ull << 4) +#define CA_DEBUG_NSEL0_SHFT 4 + /* bit 7 unused */ +#define CA_DEBUG_MSEL1 (0x7ull << 8) +#define CA_DEBUG_MSEL1_SHFT 8 + /* bit 11 unused */ +#define CA_DEBUG_NSEL1 (0x7ull << 12) +#define CA_DEBUG_NSEL1_SHFT 12 + /* bit 15 unused */ +#define CA_DEBUG_MSEL2 (0x7ull << 16) +#define CA_DEBUG_MSEL2_SHFT 16 + /* bit 19 unused */ +#define CA_DEBUG_NSEL2 (0x7ull << 20) +#define CA_DEBUG_NSEL2_SHFT 20 + /* bit 23 unused */ +#define CA_DEBUG_MSEL3 (0x7ull << 24) +#define CA_DEBUG_MSEL3_SHFT 24 + /* bit 27 unused */ +#define CA_DEBUG_NSEL3 (0x7ull << 28) +#define CA_DEBUG_NSEL3_SHFT 28 + /* bit 31 unused */ +#define CA_DEBUG_MSEL4 (0x7ull << 32) +#define CA_DEBUG_MSEL4_SHFT 32 + /* bit 35 unused */ +#define CA_DEBUG_NSEL4 (0x7ull << 36) +#define CA_DEBUG_NSEL4_SHFT 36 + /* bit 39 unused */ +#define CA_DEBUG_MSEL5 (0x7ull << 40) +#define CA_DEBUG_MSEL5_SHFT 40 + /* bit 43 unused */ +#define CA_DEBUG_NSEL5 (0x7ull << 44) +#define CA_DEBUG_NSEL5_SHFT 44 + /* bit 47 unused */ +#define CA_DEBUG_MSEL6 (0x7ull << 48) +#define CA_DEBUG_MSEL6_SHFT 48 + /* bit 51 unused */ +#define CA_DEBUG_NSEL6 (0x7ull << 52) +#define CA_DEBUG_NSEL6_SHFT 52 + /* bit 55 unused */ +#define CA_DEBUG_MSEL7 (0x7ull << 56) +#define CA_DEBUG_MSEL7_SHFT 56 + /* bit 59 unused */ +#define CA_DEBUG_NSEL7 (0x7ull << 60) +#define CA_DEBUG_NSEL7_SHFT 60 + /* bit 63 unused */ + + +/* ==== ca_debug_domain_sel */ +#define CA_DEBUG_DOMAIN_L (1ull << 0) +#define CA_DEBUG_DOMAIN_H (1ull << 1) + /* bits 63:2 unused */ + +/* ==== ca_gart_ptr_table */ +#define CA_GART_PTR_VAL (1ull << 0) + /* bits 11:1 unused */ +#define CA_GART_PTR_ADDR (0xfffffffffffull << 12) +#define CA_GART_PTR_ADDR_SHFT 12 + /* bits 63:56 unused */ + +/* ==== ca_gart_tlb_addr[0-7] */ +#define CA_GART_TLB_ADDR (0xffffffffffffffull << 0) +#define CA_GART_TLB_ADDR_SHFT 0 + /* bits 62:56 unused */ +#define CA_GART_TLB_ENTRY_VAL (1ull << 63) + +/* + * PIO address space ranges for TIO:CA + */ + +/* CA internal registers */ +#define CA_PIO_ADMIN 0x00000000 +#define CA_PIO_ADMIN_LEN 0x00010000 + +/* GFX Write Buffer - Diagnostics */ +#define CA_PIO_GFX 0x00010000 +#define CA_PIO_GFX_LEN 0x00010000 + +/* AGP DMA Write Buffer - Diagnostics */ +#define CA_PIO_AGP_DMAWRITE 0x00020000 +#define CA_PIO_AGP_DMAWRITE_LEN 0x00010000 + +/* AGP DMA READ Buffer - Diagnostics */ +#define CA_PIO_AGP_DMAREAD 0x00030000 +#define CA_PIO_AGP_DMAREAD_LEN 0x00010000 + +/* PCI Config Type 0 */ +#define CA_PIO_PCI_TYPE0_CONFIG 0x01000000 +#define CA_PIO_PCI_TYPE0_CONFIG_LEN 0x01000000 + +/* PCI Config Type 1 */ +#define CA_PIO_PCI_TYPE1_CONFIG 0x02000000 +#define CA_PIO_PCI_TYPE1_CONFIG_LEN 0x01000000 + +/* PCI I/O Cycles - mapped to PCI Address 0x00000000-0x04ffffff */ +#define CA_PIO_PCI_IO 0x03000000 +#define CA_PIO_PCI_IO_LEN 0x05000000 + +/* PCI MEM Cycles - mapped to PCI with CA_PIO_ADDR_OFFSET of ca_control1 */ +/* use Fast Write if enabled and coretalk packet type is a GFX request */ +#define CA_PIO_PCI_MEM_OFFSET 0x08000000 +#define CA_PIO_PCI_MEM_OFFSET_LEN 0x08000000 + +/* PCI MEM Cycles - mapped to PCI Address 0x00000000-0xbfffffff */ +/* use Fast Write if enabled and coretalk packet type is a GFX request */ +#define CA_PIO_PCI_MEM 0x40000000 +#define CA_PIO_PCI_MEM_LEN 0xc0000000 + +/* + * DMA space + * + * The CA aperature (ie. bus address range) mapped by the GART is segmented into + * two parts. The lower portion of the aperature is used for mapping 32 bit + * PCI addresses which are managed by the dma interfaces in this file. The + * upper poprtion of the aperature is used for mapping 48 bit AGP addresses. + * The AGP portion of the aperature is managed by the agpgart_be.c driver + * in drivers/linux/agp. There are ca-specific hooks in that driver to + * manipulate the gart, but management of the AGP portion of the aperature + * is the responsibility of that driver. + * + * CA allows three main types of DMA mapping: + * + * PCI 64-bit Managed by this driver + * PCI 32-bit Managed by this driver + * AGP 48-bit Managed by hooks in the /dev/agpgart driver + * + * All of the above can optionally be remapped through the GART. The following + * table lists the combinations of addressing types and GART remapping that + * is currently supported by the driver (h/w supports all, s/w limits this): + * + * PCI64 PCI32 AGP48 + * GART no yes yes + * Direct yes yes no + * + * GART remapping of PCI64 is not done because there is no need to. The + * 64 bit PCI address holds all of the information necessary to target any + * memory in the system. + * + * AGP48 is always mapped through the GART. Management of the AGP48 portion + * of the aperature is the responsibility of code in the agpgart_be driver. + * + * The non-64 bit bus address space will currently be partitioned like this: + * + * 0xffff_ffff_ffff +-------- + * | AGP48 direct + * | Space managed by this driver + * CA_AGP_DIRECT_BASE +-------- + * | AGP GART mapped (gfx aperature) + * | Space managed by /dev/agpgart driver + * | This range is exposed to the agpgart + * | driver as the "graphics aperature" + * CA_AGP_MAPPED_BASE +----- + * | PCI GART mapped + * | Space managed by this driver + * CA_PCI32_MAPPED_BASE +---- + * | PCI32 direct + * | Space managed by this driver + * 0xC000_0000 +-------- + * (CA_PCI32_DIRECT_BASE) + * + * The bus address range CA_PCI32_MAPPED_BASE through CA_AGP_DIRECT_BASE + * is what we call the CA aperature. Addresses falling in this range will + * be remapped using the GART. + * + * The bus address range CA_AGP_MAPPED_BASE through CA_AGP_DIRECT_BASE + * is what we call the graphics aperature. This is a subset of the CA + * aperature and is under the control of the agpgart_be driver. + * + * CA_PCI32_MAPPED_BASE, CA_AGP_MAPPED_BASE, and CA_AGP_DIRECT_BASE are + * somewhat arbitrary values. The known constraints on choosing these is: + * + * 1) CA_AGP_DIRECT_BASE-CA_PCI32_MAPPED_BASE+1 (the CA aperature size) + * must be one of the values supported by the ca_gart_aperature register. + * Currently valid values are: 4MB through 4096MB in powers of 2 increments + * + * 2) CA_AGP_DIRECT_BASE-CA_AGP_MAPPED_BASE+1 (the gfx aperature size) + * must be in MB units since that's what the agpgart driver assumes. + */ + +/* + * Define Bus DMA ranges. These are configurable (see constraints above) + * and will probably need tuning based on experience. + */ + + +/* + * 11/24/03 + * CA has an addressing glitch w.r.t. PCI direct 32 bit DMA that makes it + * generally unusable. The problem is that for PCI direct 32 + * DMA's, all 32 bits of the bus address are used to form the lower 32 bits + * of the coretalk address, and coretalk bits 38:32 come from a register. + * Since only PCI bus addresses 0xC0000000-0xFFFFFFFF (1GB) are available + * for DMA (the rest is allocated to PIO), host node addresses need to be + * such that their lower 32 bits fall in the 0xC0000000-0xffffffff range + * as well. So there can be no PCI32 direct DMA below 3GB!! For this + * reason we set the CA_PCI32_DIRECT_SIZE to 0 which essentially makes + * tioca_dma_direct32() a noop but preserves the code flow should this issue + * be fixed in a respin. + * + * For now, all PCI32 DMA's must be mapped through the GART. + */ + +#define CA_PCI32_DIRECT_BASE 0xC0000000UL /* BASE not configurable */ +#define CA_PCI32_DIRECT_SIZE 0x00000000UL /* 0 MB */ + +#define CA_PCI32_MAPPED_BASE 0xC0000000UL +#define CA_PCI32_MAPPED_SIZE 0x40000000UL /* 2GB */ + +#define CA_AGP_MAPPED_BASE 0x80000000UL +#define CA_AGP_MAPPED_SIZE 0x40000000UL /* 2GB */ + +#define CA_AGP_DIRECT_BASE 0x40000000UL /* 2GB */ +#define CA_AGP_DIRECT_SIZE 0x40000000UL + +#define CA_APERATURE_BASE (CA_AGP_MAPPED_BASE) +#define CA_APERATURE_SIZE (CA_AGP_MAPPED_SIZE+CA_PCI32_MAPPED_SIZE) + +#endif /* _ASM_IA64_SN_TIO_TIOCA_H */ diff --git a/include/asm-ia64/sn/tioca_provider.h b/include/asm-ia64/sn/tioca_provider.h new file mode 100644 index 0000000..b6acc22 --- /dev/null +++ b/include/asm-ia64/sn/tioca_provider.h @@ -0,0 +1,206 @@ +/* + * 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. + * + * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved. + */ + +#ifndef _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H +#define _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H + +#include + +/* + * WAR enables + * Defines for individual WARs. Each is a bitmask of applicable + * part revision numbers. (1 << 1) == rev A, (1 << 2) == rev B, + * (3 << 1) == (rev A or rev B), etc + */ + +#define TIOCA_WAR_ENABLED(pv, tioca_common) \ + ((1 << tioca_common->ca_rev) & pv) + + /* TIO:ICE:FRZ:Freezer loses a PIO data ucred on PIO RD RSP with CW error */ +#define PV907908 (1 << 1) + /* ATI config space problems after BIOS execution starts */ +#define PV908234 (1 << 1) + /* CA:AGPDMA write request data mismatch with ABC1CL merge */ +#define PV895469 (1 << 1) + /* TIO:CA TLB invalidate of written GART entries possibly not occuring in CA*/ +#define PV910244 (1 << 1) + +struct tioca_dmamap{ + struct list_head cad_list; /* headed by ca_list */ + + dma_addr_t cad_dma_addr; /* Linux dma handle */ + uint cad_gart_entry; /* start entry in ca_gart_pagemap */ + uint cad_gart_size; /* #entries for this map */ +}; + +/* + * Kernel only fields. Prom may look at this stuff for debugging only. + * Access this structure through the ca_kernel_private ptr. + */ + +struct tioca_common ; + +struct tioca_kernel { + struct tioca_common *ca_common; /* tioca this belongs to */ + struct list_head ca_list; /* list of all ca's */ + struct list_head ca_dmamaps; + spinlock_t ca_lock; /* Kernel lock */ + cnodeid_t ca_closest_node; + struct list_head *ca_devices; /* bus->devices */ + + /* + * General GART stuff + */ + uint64_t ca_ap_size; /* size of aperature in bytes */ + uint32_t ca_gart_entries; /* # uint64_t entries in gart */ + uint32_t ca_ap_pagesize; /* aperature page size in bytes */ + uint64_t ca_ap_bus_base; /* bus address of CA aperature */ + uint64_t ca_gart_size; /* gart size in bytes */ + uint64_t *ca_gart; /* gart table vaddr */ + uint64_t ca_gart_coretalk_addr; /* gart coretalk addr */ + uint8_t ca_gart_iscoherent; /* used in tioca_tlbflush */ + + /* PCI GART convenience values */ + uint64_t ca_pciap_base; /* pci aperature bus base address */ + uint64_t ca_pciap_size; /* pci aperature size (bytes) */ + uint64_t ca_pcigart_base; /* gfx GART bus base address */ + uint64_t *ca_pcigart; /* gfx GART vm address */ + uint32_t ca_pcigart_entries; + uint32_t ca_pcigart_start; /* PCI start index in ca_gart */ + void *ca_pcigart_pagemap; + + /* AGP GART convenience values */ + uint64_t ca_gfxap_base; /* gfx aperature bus base address */ + uint64_t ca_gfxap_size; /* gfx aperature size (bytes) */ + uint64_t ca_gfxgart_base; /* gfx GART bus base address */ + uint64_t *ca_gfxgart; /* gfx GART vm address */ + uint32_t ca_gfxgart_entries; + uint32_t ca_gfxgart_start; /* agpgart start index in ca_gart */ +}; + +/* + * Common tioca info shared between kernel and prom + * + * DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES + * TO THE PROM VERSION. + */ + +struct tioca_common { + struct pcibus_bussoft ca_common; /* common pciio header */ + + uint32_t ca_rev; + uint32_t ca_closest_nasid; + + uint64_t ca_prom_private; + uint64_t ca_kernel_private; +}; + +/** + * tioca_paddr_to_gart - Convert an SGI coretalk address to a CA GART entry + * @paddr: page address to convert + * + * Convert a system [coretalk] address to a GART entry. GART entries are + * formed using the following: + * + * data = ( (1<<63) | ( (REMAP_NODE_ID << 40) | (MD_CHIPLET_ID << 38) | + * (REMAP_SYS_ADDR) ) >> 12 ) + * + * DATA written to 1 GART TABLE Entry in system memory is remapped system + * addr for 1 page + * + * The data is for coretalk address format right shifted 12 bits with a + * valid bit. + * + * GART_TABLE_ENTRY [ 25:0 ] -- REMAP_SYS_ADDRESS[37:12]. + * GART_TABLE_ENTRY [ 27:26 ] -- SHUB MD chiplet id. + * GART_TABLE_ENTRY [ 41:28 ] -- REMAP_NODE_ID. + * GART_TABLE_ENTRY [ 63 ] -- Valid Bit + */ +static inline u64 +tioca_paddr_to_gart(unsigned long paddr) +{ + /* + * We are assuming right now that paddr already has the correct + * format since the address from xtalk_dmaXXX should already have + * NODE_ID, CHIPLET_ID, and SYS_ADDR in the correct locations. + */ + + return ((paddr) >> 12) | (1UL << 63); +} + +/** + * tioca_physpage_to_gart - Map a host physical page for SGI CA based DMA + * @page_addr: system page address to map + */ + +static inline unsigned long +tioca_physpage_to_gart(uint64_t page_addr) +{ + uint64_t coretalk_addr; + + coretalk_addr = PHYS_TO_TIODMA(page_addr); + if (!coretalk_addr) { + return 0; + } + + return tioca_paddr_to_gart(coretalk_addr); +} + +/** + * tioca_tlbflush - invalidate cached SGI CA GART TLB entries + * @tioca_kernel: CA context + * + * Invalidate tlb entries for a given CA GART. Main complexity is to account + * for revA bug. + */ +static inline void +tioca_tlbflush(struct tioca_kernel *tioca_kernel) +{ + volatile uint64_t tmp; + volatile struct tioca *ca_base; + struct tioca_common *tioca_common; + + tioca_common = tioca_kernel->ca_common; + ca_base = (struct tioca *)tioca_common->ca_common.bs_base; + + /* + * Explicit flushes not needed if GART is in cached mode + */ + if (tioca_kernel->ca_gart_iscoherent) { + if (TIOCA_WAR_ENABLED(PV910244, tioca_common)) { + /* + * PV910244: RevA CA needs explicit flushes. + * Need to put GART into uncached mode before + * flushing otherwise the explicit flush is ignored. + * + * Alternate WAR would be to leave GART cached and + * touch every CL aligned GART entry. + */ + + ca_base->ca_control2 &= ~(CA_GART_MEM_PARAM); + ca_base->ca_control2 |= CA_GART_FLUSH_TLB; + ca_base->ca_control2 |= + (0x2ull << CA_GART_MEM_PARAM_SHFT); + tmp = ca_base->ca_control2; + } + + return; + } + + /* + * Gart in uncached mode ... need an explicit flush. + */ + + ca_base->ca_control2 |= CA_GART_FLUSH_TLB; + tmp = ca_base->ca_control2; +} + +extern uint32_t tioca_gart_found; +extern int tioca_init_provider(void); +extern void tioca_fastwrite_enable(struct tioca_kernel *tioca_kern); +#endif /* _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H */ -- cgit v0.10.2 From bf1cf98fa941fea5e630e341db4a294d531aaa3e Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Mon, 25 Apr 2005 11:42:39 -0700 Subject: [IA64-SGI] Change SAL call request code for SN systems Change the value of the SAL call number for a new SAL request. The initial implementation in the PROM did not match what the OS expected. Since the OS can run on PROMs that do not implement the new call, changing the call number avoids the issue. New PROMs will implement the new call number. (This avoids problems with the 4.05 PROM). Signed-off-by: Jack Steiner Signed-off-by: Tony Luck diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index 88c31b5..81a1cf1 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -35,8 +35,8 @@ #define SN_SAL_PRINT_ERROR 0x02000012 #define SN_SAL_SET_ERROR_HANDLING_FEATURES 0x0200001a // reentrant #define SN_SAL_GET_FIT_COMPT 0x0200001b // reentrant -#define SN_SAL_GET_SN_INFO 0x0200001c #define SN_SAL_GET_SAPIC_INFO 0x0200001d +#define SN_SAL_GET_SN_INFO 0x0200001e #define SN_SAL_CONSOLE_PUTC 0x02000021 #define SN_SAL_CONSOLE_GETC 0x02000022 #define SN_SAL_CONSOLE_PUTS 0x02000023 -- cgit v0.10.2 From 8297511530b0d2a281c796e738683951a59a020c Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Mon, 25 Apr 2005 11:44:02 -0700 Subject: [IA64] add missing cpu_relax() in ITC syncing code Call cpu_relax() in busy-waiting loops of the ITC-syncing code. Signed-off-by: David Mosberger-Tang Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index ca1536d..dbc6b61 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -1,7 +1,7 @@ /* * SMP boot-related support * - * Copyright (C) 1998-2003 Hewlett-Packard Co + * Copyright (C) 1998-2003, 2005 Hewlett-Packard Co * David Mosberger-Tang * * 01/05/16 Rohit Seth Moved SMP booting functions from smp.c to here. @@ -156,7 +156,8 @@ sync_master (void *arg) local_irq_save(flags); { for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) { - while (!go[MASTER]); + while (!go[MASTER]) + cpu_relax(); go[MASTER] = 0; go[SLAVE] = ia64_get_itc(); } @@ -179,7 +180,8 @@ get_delta (long *rt, long *master) for (i = 0; i < NUM_ITERS; ++i) { t0 = ia64_get_itc(); go[MASTER] = 1; - while (!(tm = go[SLAVE])); + while (!(tm = go[SLAVE])) + cpu_relax(); go[SLAVE] = 0; t1 = ia64_get_itc(); @@ -258,7 +260,8 @@ ia64_sync_itc (unsigned int master) return; } - while (go[MASTER]); /* wait for master to be ready */ + while (go[MASTER]) + cpu_relax(); /* wait for master to be ready */ spin_lock_irqsave(&itc_sync_lock, flags); { -- cgit v0.10.2 From e8d1cb2f280aa53e1c75c8b5fcbf80b3481d0caa Mon Sep 17 00:00:00 2001 From: Keith Owens Date: Mon, 25 Apr 2005 11:45:26 -0700 Subject: [IA64] Tighten up unw_unwind_to_user check Detect user space by the unwind frame with predicate PRED_USER_STACK set, instead of a user space IP. Tighten up the last ditch check for running off the top of the kernel stack. Based on a suggestion by David Mosberger, reworked to fit the current tree. This survives my stress test which used to break 2.6.9 kernels. Unlike 2.6.11, the stress test now unwinds to the correct point, so gdb can get the user space registers. Signed-off-by: Keith Owens Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index d494ff6..2776a07 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -1943,23 +1943,30 @@ EXPORT_SYMBOL(unw_unwind); int unw_unwind_to_user (struct unw_frame_info *info) { - unsigned long ip, sp; + unsigned long ip, sp, pr = 0; while (unw_unwind(info) >= 0) { - if (unw_get_rp(info, &ip) < 0) { - unw_get_ip(info, &ip); - UNW_DPRINT(0, "unwind.%s: failed to read return pointer (ip=0x%lx)\n", - __FUNCTION__, ip); - return -1; - } unw_get_sp(info, &sp); - if (sp >= (unsigned long)info->task + IA64_STK_OFFSET) + if ((long)((unsigned long)info->task + IA64_STK_OFFSET - sp) + < IA64_PT_REGS_SIZE) { + UNW_DPRINT(0, "unwind.%s: ran off the top of the kernel stack\n", + __FUNCTION__); break; - if (ip < FIXADDR_USER_END) + } + if (unw_is_intr_frame(info) && + (pr & (1UL << PRED_USER_STACK))) return 0; + if (unw_get_pr (info, &pr) < 0) { + unw_get_rp(info, &ip); + UNW_DPRINT(0, "unwind.%s: failed to read " + "predicate register (ip=0x%lx)\n", + __FUNCTION__, ip); + return -1; + } } unw_get_ip(info, &ip); - UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", __FUNCTION__, ip); + UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", + __FUNCTION__, ip); return -1; } EXPORT_SYMBOL(unw_unwind_to_user); -- cgit v0.10.2 From f649a3bfd1b0ad8872312ed1c223d69b74406e1f Mon Sep 17 00:00:00 2001 From: Yasuyuki KOZAKAI Date: Mon, 25 Apr 2005 12:00:04 -0700 Subject: [NETFILTER]: Fix truncated sequence numbers in FTP helper Signed-off-by: Yasuyuki KOZAKAI Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index 12b88cb..dd86503 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c @@ -252,7 +252,7 @@ static int find_pattern(const char *data, size_t dlen, } /* Look up to see if we're just after a \n. */ -static int find_nl_seq(u16 seq, const struct ip_ct_ftp_master *info, int dir) +static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir) { unsigned int i; @@ -263,7 +263,7 @@ static int find_nl_seq(u16 seq, const struct ip_ct_ftp_master *info, int dir) } /* We don't update if it's older than what we have. */ -static void update_nl_seq(u16 nl_seq, struct ip_ct_ftp_master *info, int dir) +static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir) { unsigned int i, oldest = NUM_SEQ_TO_REMEMBER; -- cgit v0.10.2 From b31e5b1bb53b99dfd5e890aa07e943aff114ae1c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 25 Apr 2005 12:01:07 -0700 Subject: [NETFILTER]: Drop conntrack reference when packet leaves IP In the event a raw socket is created for sending purposes only, the creator never bothers to check the socket's receive queue. But we continue to add skbs to its queue until it fills up. Unfortunately, if ip_conntrack is loaded on the box, each skb we add to the queue potentially holds a reference to a conntrack. If the user attempts to unload ip_conntrack, we will spin around forever since the queued skbs are pinned. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 30ab7b6..38f6953 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -195,6 +195,8 @@ static inline int ip_finish_output2(struct sk_buff *skb) nf_debug_ip_finish_output2(skb); #endif /*CONFIG_NETFILTER_DEBUG*/ + nf_reset(skb); + if (hh) { int hh_alen; diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 0c29ccf..46ca45f 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -431,13 +431,6 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { -#if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE) - /* Previously seen (loopback)? Ignore. Do this before - fragment check. */ - if ((*pskb)->nfct) - return NF_ACCEPT; -#endif - /* Gather fragments. */ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { *pskb = ip_ct_gather_frags(*pskb, -- cgit v0.10.2 From cbdbf00aaf0addd391259f94aaa8e7dc1bfc9081 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 25 Apr 2005 12:15:01 -0700 Subject: [PKT_SCHED]: Eliminate unnecessary includes in simple.c Noted by Al Viro. Signed-off-by: David S. Miller diff --git a/net/sched/simple.c b/net/sched/simple.c index b0d3d15..3ab4c67 100644 --- a/net/sched/simple.c +++ b/net/sched/simple.c @@ -10,27 +10,13 @@ * */ -#include -#include -#include #include -#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include -#include -#include -#include -#include #include #define TCA_ACT_SIMP 22 -- cgit v0.10.2 From 30325d17715302a60c9afdaacaafaeb056b7e880 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Mon, 25 Apr 2005 13:03:16 -0700 Subject: [IA64] speed up syscall path a bit more Recently I noticed that clearing ar.ssd/ar.csd right before srlz.d is causing significant stalling in the syscall path. The patch below fixes that by moving the register-writes after srlz.d. On a Madison, this drops break-based getpid() from 241 to 226 cycles (-15 cycles). Signed-off-by: David Mosberger-Tang Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 0272c01..73e23da 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -728,12 +728,8 @@ ENTRY(ia64_leave_syscall) mov f8=f0 // clear f8 ;; ld8 r30=[r2],16 // M0|1 load cr.ifs - mov.m ar.ssd=r0 // M2 clear ar.ssd - cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs - ;; ld8 r25=[r3],16 // M0|1 load ar.unat - mov.m ar.csd=r0 // M2 clear ar.csd - mov r22=r0 // clear r22 + cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs ;; ld8 r26=[r2],PT(B0)-PT(AR_PFS) // M0|1 load ar.pfs (pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled @@ -756,11 +752,15 @@ ENTRY(ia64_leave_syscall) mov f7=f0 // clear f7 ;; ld8.fill r12=[r2] // restore r12 (sp) + mov.m ar.ssd=r0 // M2 clear ar.ssd + mov r22=r0 // clear r22 + ld8.fill r15=[r3] // restore r15 +(pUStk) st1 [r14]=r17 addl r3=THIS_CPU(ia64_phys_stacked_size_p8),r0 ;; (pUStk) ld4 r3=[r3] // r3 = cpu_data->phys_stacked_size_p8 -(pUStk) st1 [r14]=r17 + mov.m ar.csd=r0 // M2 clear ar.csd mov b6=r18 // I0 restore b6 ;; mov r14=r0 // clear r14 -- cgit v0.10.2 From 4a5c13c7eb0d55bfd2cf3100c55f1e3d8df37576 Mon Sep 17 00:00:00 2001 From: Mark Goodwin Date: Mon, 25 Apr 2005 13:04:22 -0700 Subject: [IA64-SGI] Altix SN topology support for new chipsets and pci topology please accept this patch to the Altix SN platform topology export interface to support new chipsets and to export PCI topology. This follows on top of Jack Steiner's patch dated March 1st ("New chipset support for SN platform"). Signed-off-by: Mark Goodwin Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index 1973564..3bff991 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include static void *sn_hwperf_salheap = NULL; static int sn_hwperf_obj_cnt = 0; @@ -81,26 +83,45 @@ out: return e; } +static int sn_hwperf_location_to_bpos(char *location, + int *rack, int *bay, int *slot, int *slab) +{ + char type; + + /* first scan for an old style geoid string */ + if (sscanf(location, "%03d%c%02d#%d", + rack, &type, bay, slab) == 4) + *slot = 0; + else /* scan for a new bladed geoid string */ + if (sscanf(location, "%03d%c%02d^%02d#%d", + rack, &type, bay, slot, slab) != 5) + return -1; + /* success */ + return 0; +} + static int sn_hwperf_geoid_to_cnode(char *location) { int cnode; geoid_t geoid; moduleid_t module_id; - char type; - int rack, slot, slab; - int this_rack, this_slot, this_slab; + int rack, bay, slot, slab; + int this_rack, this_bay, this_slot, this_slab; - if (sscanf(location, "%03d%c%02d#%d", &rack, &type, &slot, &slab) != 4) + if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab)) return -1; for (cnode = 0; cnode < numionodes; cnode++) { geoid = cnodeid_get_geoid(cnode); module_id = geo_module(geoid); this_rack = MODULE_GET_RACK(module_id); - this_slot = MODULE_GET_BPOS(module_id); + this_bay = MODULE_GET_BPOS(module_id); + this_slot = 0; /* XXX */ this_slab = geo_slab(geoid); - if (rack == this_rack && slot == this_slot && slab == this_slab) + if (rack == this_rack && bay == this_bay && + slot == this_slot && slab == this_slab) { break; + } } return cnode < numionodes ? cnode : -1; @@ -153,11 +174,29 @@ static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj, return slabname; } +static void print_pci_topology(struct seq_file *s, + struct sn_hwperf_object_info *obj, int *ordinal, + char *pci_topo_buf, int len) +{ + char *p1; + char *p2; + + for (p1=pci_topo_buf; *p1 && p1 < pci_topo_buf + len;) { + if (!(p2 = strchr(p1, '\n'))) + break; + *p2 = '\0'; + seq_printf(s, "pcibus %d %s-%s\n", + *ordinal, obj->location, p1); + (*ordinal)++; + p1 = p2 + 1; + } +} + static int sn_topology_show(struct seq_file *s, void *d) { int sz; int pt; - int e; + int e = 0; int i; int j; const char *slabname; @@ -169,11 +208,46 @@ static int sn_topology_show(struct seq_file *s, void *d) struct sn_hwperf_object_info *p; struct sn_hwperf_object_info *obj = d; /* this object */ struct sn_hwperf_object_info *objs = s->private; /* all objects */ + int rack, bay, slot, slab; + u8 shubtype; + u8 system_size; + u8 sharing_size; + u8 partid; + u8 coher; + u8 nasid_shift; + u8 region_size; + u16 nasid_mask; + int nasid_msb; + char *pci_topo_buf; + int pci_bus_ordinal = 0; + static int pci_topo_buf_len = 256; if (obj == objs) { - seq_printf(s, "# sn_topology version 1\n"); + seq_printf(s, "# sn_topology version 2\n"); seq_printf(s, "# objtype ordinal location partition" " [attribute value [, ...]]\n"); + + if (ia64_sn_get_sn_info(0, + &shubtype, &nasid_mask, &nasid_shift, &system_size, + &sharing_size, &partid, &coher, ®ion_size)) + BUG(); + for (nasid_msb=63; nasid_msb > 0; nasid_msb--) { + if (((u64)nasid_mask << nasid_shift) & (1ULL << nasid_msb)) + break; + } + seq_printf(s, "partition %u %s local " + "shubtype %s, " + "nasid_mask 0x%016lx, " + "nasid_bits %d:%d, " + "system_size %d, " + "sharing_size %d, " + "coherency_domain %d, " + "region_size %d\n", + + partid, system_utsname.nodename, + shubtype ? "shub2" : "shub1", + (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, + system_size, sharing_size, coher, region_size); } if (SN_HWPERF_FOREIGN(obj)) { @@ -181,7 +255,7 @@ static int sn_topology_show(struct seq_file *s, void *d) return 0; } - for (i = 0; obj->name[i]; i++) { + for (i = 0; i < SN_HWPERF_MAXSTRING && obj->name[i]; i++) { if (obj->name[i] == ' ') obj->name[i] = '_'; } @@ -221,6 +295,43 @@ static int sn_topology_show(struct seq_file *s, void *d) seq_putc(s, '\n'); } } + + /* + * PCI busses attached to this node, if any + */ + do { + if (!(pci_topo_buf = vmalloc(pci_topo_buf_len))) { + printk("sn_topology_show: kmalloc failed\n"); + break; + } + + if (sn_hwperf_location_to_bpos(obj->location, + &rack, &bay, &slot, &slab) != 0) + continue; + + e = ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab, + pci_topo_buf, pci_topo_buf_len); + + switch (e) { + case SALRET_NOT_IMPLEMENTED: + case SALRET_INVALID_ARG: + /* ignore, don't print anything */ + e = SN_HWPERF_OP_OK; + break; + + case SALRET_ERROR: + /* retry with a bigger buffer */ + pci_topo_buf_len += 256; + break; + + case SN_HWPERF_OP_OK: + /* export pci bus info */ + print_pci_topology(s, obj, &pci_bus_ordinal, + pci_topo_buf, pci_topo_buf_len); + break; + } + vfree(pci_topo_buf); + } while (e != SN_HWPERF_OP_OK && pci_topo_buf_len < 0x200000); } if (obj->ports) { @@ -397,6 +508,9 @@ static int sn_hwperf_map_err(int hwperf_err) break; case SN_HWPERF_OP_BUSY: + e = -EBUSY; + break; + case SN_HWPERF_OP_RECONFIGURE: e = -EAGAIN; break; @@ -549,6 +663,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) r = sn_hwperf_op_cpu(&op_info); if (r) { r = sn_hwperf_map_err(r); + a.v0 = v0; goto error; } break; diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index 81a1cf1..410d356 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -74,6 +74,7 @@ #define SN_SAL_IOIF_GET_PCIBUS_INFO 0x02000056 #define SN_SAL_IOIF_GET_PCIDEV_INFO 0x02000057 #define SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST 0x02000058 +#define SN_SAL_IOIF_GET_PCI_TOPOLOGY 0x02000059 #define SN_SAL_HUB_ERROR_INTERRUPT 0x02000060 @@ -1012,4 +1013,14 @@ ia64_sn_hwperf_op(nasid_t nasid, u64 opcode, u64 a0, u64 a1, u64 a2, return (int) rv.status; } +static inline int +ia64_sn_ioif_get_pci_topology(u64 rack, u64 bay, u64 slot, u64 slab, + char *buf, u64 len) +{ + struct ia64_sal_retval rv; + SAL_CALL_NOLOCK(rv, SN_SAL_IOIF_GET_PCI_TOPOLOGY, + rack, bay, slot, slab, buf, len, 0); + return (int) rv.status; +} + #endif /* _ASM_IA64_SN_SN_SAL_H */ -- cgit v0.10.2 From f1e2a1c8a1fe16db5f4a7c0c1551d6e1b97dcbb2 Mon Sep 17 00:00:00 2001 From: Mark Goodwin Date: Mon, 25 Apr 2005 13:05:08 -0700 Subject: [IA64-SGI] Altix SN topology fix potential infinite loop Fix infinite loop if sn_hwperf_location_to_bpos() fails. Signed-off-by: Mark Goodwin Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index 3bff991..e731fcb 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c @@ -300,14 +300,15 @@ static int sn_topology_show(struct seq_file *s, void *d) * PCI busses attached to this node, if any */ do { - if (!(pci_topo_buf = vmalloc(pci_topo_buf_len))) { - printk("sn_topology_show: kmalloc failed\n"); + if (sn_hwperf_location_to_bpos(obj->location, + &rack, &bay, &slot, &slab)) { break; } - if (sn_hwperf_location_to_bpos(obj->location, - &rack, &bay, &slot, &slab) != 0) - continue; + if (!(pci_topo_buf = vmalloc(pci_topo_buf_len))) { + printk("sn_topology_show: vmalloc failed\n"); + break; + } e = ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab, pci_topo_buf, pci_topo_buf_len); @@ -325,6 +326,7 @@ static int sn_topology_show(struct seq_file *s, void *d) break; case SN_HWPERF_OP_OK: + default: /* export pci bus info */ print_pci_topology(s, obj, &pci_bus_ordinal, pci_topo_buf, pci_topo_buf_len); -- cgit v0.10.2 From be539c73b54dcc9f54fb2c2b70e204c93b616c9b Mon Sep 17 00:00:00 2001 From: Colin Ngam Date: Mon, 25 Apr 2005 13:06:28 -0700 Subject: [IA64-SGI] Shub2 provides an addition of 2 External Interrupt events. Signed-off-by: Colin Ngam Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index b52d329..0f4e8138 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c @@ -82,20 +82,9 @@ static void sn_ack_irq(unsigned int irq) nasid = get_nasid(); event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED)); - if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) { - mask |= (1 << SH_EVENT_OCCURRED_UART_INT_SHFT); - } - if (event_occurred & SH_EVENT_OCCURRED_IPI_INT_MASK) { - mask |= (1 << SH_EVENT_OCCURRED_IPI_INT_SHFT); - } - if (event_occurred & SH_EVENT_OCCURRED_II_INT0_MASK) { - mask |= (1 << SH_EVENT_OCCURRED_II_INT0_SHFT); - } - if (event_occurred & SH_EVENT_OCCURRED_II_INT1_MASK) { - mask |= (1 << SH_EVENT_OCCURRED_II_INT1_SHFT); - } + mask = event_occurred & SH_ALL_INT_MASK; HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), - mask); + mask); __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs); move_irq(irq); diff --git a/include/asm-ia64/sn/shub_mmr.h b/include/asm-ia64/sn/shub_mmr.h index 5c2fcf1..6ec37e8 100644 --- a/include/asm-ia64/sn/shub_mmr.h +++ b/include/asm-ia64/sn/shub_mmr.h @@ -129,6 +129,23 @@ #define SH_EVENT_OCCURRED_II_INT1_SHFT 30 #define SH_EVENT_OCCURRED_II_INT1_MASK 0x0000000040000000 +/* SH2_EVENT_OCCURRED_EXTIO_INT2 */ +/* Description: Pending SHUB 2 EXT IO INT2 */ +#define SH2_EVENT_OCCURRED_EXTIO_INT2_SHFT 33 +#define SH2_EVENT_OCCURRED_EXTIO_INT2_MASK 0x0000000200000000 + +/* SH2_EVENT_OCCURRED_EXTIO_INT3 */ +/* Description: Pending SHUB 2 EXT IO INT3 */ +#define SH2_EVENT_OCCURRED_EXTIO_INT3_SHFT 34 +#define SH2_EVENT_OCCURRED_EXTIO_INT3_MASK 0x0000000400000000 + +#define SH_ALL_INT_MASK \ + (SH_EVENT_OCCURRED_UART_INT_MASK | SH_EVENT_OCCURRED_IPI_INT_MASK | \ + SH_EVENT_OCCURRED_II_INT0_MASK | SH_EVENT_OCCURRED_II_INT1_MASK | \ + SH_EVENT_OCCURRED_II_INT1_MASK | SH2_EVENT_OCCURRED_EXTIO_INT2_MASK | \ + SH2_EVENT_OCCURRED_EXTIO_INT3_MASK) + + /* ==================================================================== */ /* LEDS */ /* ==================================================================== */ -- cgit v0.10.2 From 658b32cad9ae087bd34f35a925fd75b76d663d4e Mon Sep 17 00:00:00 2001 From: Colin Ngam Date: Mon, 25 Apr 2005 13:07:00 -0700 Subject: [IA64-SGI] support variable length nasids in shub2 This patch enables our TIO IO chipset to support variable length nasids in Shub2 chipset. Signed-off-by: Colin Ngam Signed-off-by: Tony Luck diff --git a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h index c916bd2..ae0bc99 100644 --- a/include/asm-ia64/sn/addrs.h +++ b/include/asm-ia64/sn/addrs.h @@ -154,8 +154,9 @@ * the chiplet id is zero. If we implement TIO-TIO dma, we might need * to insert a chiplet id into this macro. However, it is our belief * right now that this chiplet id will be ICE, which is also zero. + * Nasid starts on bit 40. */ -#define PHYS_TO_TIODMA(x) ( (((u64)(x) & NASID_MASK) << 2) | NODE_OFFSET(x)) +#define PHYS_TO_TIODMA(x) ( (((u64)(NASID_GET(x))) << 40) | NODE_OFFSET(x)) #define PHYS_TO_DMA(x) ( (((u64)(x) & NASID_MASK) >> 2) | NODE_OFFSET(x)) -- cgit v0.10.2 From 4944930ab748942e41ea4dc313fcb0946aee3f17 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 25 Apr 2005 13:08:30 -0700 Subject: [IA64] perfmon: make pfm_sysctl a global, and other cleanup - make pfm_sysctl a global such that it is possible to enable/disable debug printk in sampling formats using PFM_DEBUG. - remove unused pfm_debug_var variable - fix a bug in pfm_handle_work where an BUG_ON() could be triggered. There is a path where pfm_handle_work() can be called with interrupts enabled, i.e., when TIF_NEED_RESCHED is set. The fix correct the masking and unmasking of interrupts in pfm_handle_work() such that we restore the interrupt mask as it was upon entry. signed-off-by: stephane eranian Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 71147be..376fcbc 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -480,14 +480,6 @@ typedef struct { #define PFM_CMD_ARG_MANY -1 /* cannot be zero */ typedef struct { - int debug; /* turn on/off debugging via syslog */ - int debug_ovfl; /* turn on/off debug printk in overflow handler */ - int fastctxsw; /* turn on/off fast (unsecure) ctxsw */ - int expert_mode; /* turn on/off value checking */ - int debug_pfm_read; -} pfm_sysctl_t; - -typedef struct { unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ unsigned long pfm_replay_ovfl_intr_count; /* keep track of replayed ovfl interrupts */ unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */ @@ -514,8 +506,8 @@ static LIST_HEAD(pfm_buffer_fmt_list); static pmu_config_t *pmu_conf; /* sysctl() controls */ -static pfm_sysctl_t pfm_sysctl; -int pfm_debug_var; +pfm_sysctl_t pfm_sysctl; +EXPORT_SYMBOL(pfm_sysctl); static ctl_table pfm_ctl_table[]={ {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, @@ -1576,7 +1568,7 @@ pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) goto abort_locked; } - DPRINT(("[%d] fd=%d type=%d\n", current->pid, msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type)); + DPRINT(("fd=%d type=%d\n", msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type)); ret = -EFAULT; if(copy_to_user(buf, msg, sizeof(pfm_msg_t)) == 0) ret = sizeof(pfm_msg_t); @@ -3695,8 +3687,6 @@ pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) pfm_sysctl.debug = m == 0 ? 0 : 1; - pfm_debug_var = pfm_sysctl.debug; - printk(KERN_INFO "perfmon debugging %s (timing reset)\n", pfm_sysctl.debug ? "on" : "off"); if (m == 0) { @@ -4996,13 +4986,21 @@ pfm_context_force_terminate(pfm_context_t *ctx, struct pt_regs *regs) } static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds); - + /* + * pfm_handle_work() can be called with interrupts enabled + * (TIF_NEED_RESCHED) or disabled. The down_interruptible + * call may sleep, therefore we must re-enable interrupts + * to avoid deadlocks. It is safe to do so because this function + * is called ONLY when returning to user level (PUStk=1), in which case + * there is no risk of kernel stack overflow due to deep + * interrupt nesting. + */ void pfm_handle_work(void) { pfm_context_t *ctx; struct pt_regs *regs; - unsigned long flags; + unsigned long flags, dummy_flags; unsigned long ovfl_regs; unsigned int reason; int ret; @@ -5039,18 +5037,15 @@ pfm_handle_work(void) //if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking; if (reason == PFM_TRAP_REASON_RESET) goto skip_blocking; + /* + * restore interrupt mask to what it was on entry. + * Could be enabled/diasbled. + */ UNPROTECT_CTX(ctx, flags); - /* - * pfm_handle_work() is currently called with interrupts disabled. - * The down_interruptible call may sleep, therefore we - * must re-enable interrupts to avoid deadlocks. It is - * safe to do so because this function is called ONLY - * when returning to user level (PUStk=1), in which case - * there is no risk of kernel stack overflow due to deep - * interrupt nesting. - */ - BUG_ON(flags & IA64_PSR_I); + /* + * force interrupt enable because of down_interruptible() + */ local_irq_enable(); DPRINT(("before block sleeping\n")); @@ -5064,12 +5059,12 @@ pfm_handle_work(void) DPRINT(("after block sleeping ret=%d\n", ret)); /* - * disable interrupts to restore state we had upon entering - * this function + * lock context and mask interrupts again + * We save flags into a dummy because we may have + * altered interrupts mask compared to entry in this + * function. */ - local_irq_disable(); - - PROTECT_CTX(ctx, flags); + PROTECT_CTX(ctx, dummy_flags); /* * we need to read the ovfl_regs only after wake-up @@ -5095,7 +5090,9 @@ skip_blocking: ctx->ctx_ovfl_regs[0] = 0UL; nothing_to_do: - + /* + * restore flags as they were upon entry + */ UNPROTECT_CTX(ctx, flags); } diff --git a/arch/ia64/kernel/perfmon_default_smpl.c b/arch/ia64/kernel/perfmon_default_smpl.c index 965d290..344941d 100644 --- a/arch/ia64/kernel/perfmon_default_smpl.c +++ b/arch/ia64/kernel/perfmon_default_smpl.c @@ -20,24 +20,17 @@ MODULE_AUTHOR("Stephane Eranian "); MODULE_DESCRIPTION("perfmon default sampling format"); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "debug"); - -MODULE_PARM(debug_ovfl, "i"); -MODULE_PARM_DESC(debug_ovfl, "debug ovfl"); - - #define DEFAULT_DEBUG 1 #ifdef DEFAULT_DEBUG #define DPRINT(a) \ do { \ - if (unlikely(debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ } while (0) #define DPRINT_ovfl(a) \ do { \ - if (unlikely(debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ } while (0) #else @@ -45,8 +38,6 @@ MODULE_PARM_DESC(debug_ovfl, "debug ovfl"); #define DPRINT_ovfl(a) #endif -static int debug, debug_ovfl; - static int default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data) { diff --git a/include/asm-ia64/perfmon.h b/include/asm-ia64/perfmon.h index 136c60e..ed5416c 100644 --- a/include/asm-ia64/perfmon.h +++ b/include/asm-ia64/perfmon.h @@ -254,6 +254,18 @@ extern int pfm_mod_write_dbrs(struct task_struct *task, void *req, unsigned int #define PFM_CPUINFO_DCR_PP 0x2 /* if set the system wide session has started */ #define PFM_CPUINFO_EXCL_IDLE 0x4 /* the system wide session excludes the idle task */ +/* + * sysctl control structure. visible to sampling formats + */ +typedef struct { + int debug; /* turn on/off debugging via syslog */ + int debug_ovfl; /* turn on/off debug printk in overflow handler */ + int fastctxsw; /* turn on/off fast (unsecure) ctxsw */ + int expert_mode; /* turn on/off value checking */ +} pfm_sysctl_t; +extern pfm_sysctl_t pfm_sysctl; + + #endif /* __KERNEL__ */ #endif /* _ASM_IA64_PERFMON_H */ -- cgit v0.10.2 From e1e19747ecce9117610b8f3b57a3e95734230319 Mon Sep 17 00:00:00 2001 From: Bruce Losure Date: Mon, 25 Apr 2005 13:09:41 -0700 Subject: [IA64-SGI] Bus driver for the CX port of SGI's TIO chip. This patch is to provide CX port infrastructure for SGI TIO-based h/w. Also a 'core services' driver for SGI FPGA-based h/w. Signed-off-by: Bruce Losure Signed-off-by: Tony Luck diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig index bfeb952..6ff7107 100644 --- a/arch/ia64/configs/sn2_defconfig +++ b/arch/ia64/configs/sn2_defconfig @@ -574,6 +574,8 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_N_HDLC is not set # CONFIG_STALDRV is not set CONFIG_SGI_SNSC=y +CONFIG_SGI_TIOCX=y +CONFIG_SGI_MBCS=m # # Serial drivers diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile index 6c7f4d9..4f381fb 100644 --- a/arch/ia64/sn/kernel/Makefile +++ b/arch/ia64/sn/kernel/Makefile @@ -10,3 +10,4 @@ obj-y += setup.o bte.o bte_error.o irq.o mca.o idle.o \ huberror.o io_init.o iomv.o klconflib.o sn2/ obj-$(CONFIG_IA64_GENERIC) += machvec.o +obj-$(CONFIG_SGI_TIOCX) += tiocx.o diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 096a120..97ac4ed 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -399,6 +399,20 @@ config SGI_SNSC controller communication from user space (you want this!), say Y. Otherwise, say N. +config SGI_TIOCX + bool "SGI TIO CX driver support" + depends on (IA64_SGI_SN2 || IA64_GENERIC) + help + If you have an SGI Altix and you have fpga devices attached + to your TIO, say Y here, otherwise say N. + +config SGI_MBCS + tristate "SGI FPGA Core Services driver support" + depends on (IA64_SGI_SN2 || IA64_GENERIC) + help + If you have an SGI Altix with an attached SABrick + say Y or M here, otherwise say N. + source "drivers/serial/Kconfig" config UNIX98_PTYS diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 54ed76a..3ea8cc8 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_MMTIMER) += mmtimer.o obj-$(CONFIG_VIOCONS) += viocons.o obj-$(CONFIG_VIOTAPE) += viotape.o obj-$(CONFIG_HVCS) += hvcs.o +obj-$(CONFIG_SGI_MBCS) += mbcs.o obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_TIPAR) += tipar.o diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c new file mode 100644 index 0000000..ec71005 --- /dev/null +++ b/drivers/char/mbcs.c @@ -0,0 +1,849 @@ +/* + * 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. + * + * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * MOATB Core Services driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mbcs.h" + +#define MBCS_DEBUG 0 +#if MBCS_DEBUG +#define DBG(fmt...) printk(KERN_ALERT fmt) +#else +#define DBG(fmt...) +#endif +int mbcs_major; + +LIST_HEAD(soft_list); + +/* + * file operations + */ +struct file_operations mbcs_ops = { + .open = mbcs_open, + .llseek = mbcs_sram_llseek, + .read = mbcs_sram_read, + .write = mbcs_sram_write, + .mmap = mbcs_gscr_mmap, +}; + +struct mbcs_callback_arg { + int minor; + struct cx_dev *cx_dev; +}; + +static inline void mbcs_getdma_init(struct getdma *gdma) +{ + memset(gdma, 0, sizeof(struct getdma)); + gdma->DoneIntEnable = 1; +} + +static inline void mbcs_putdma_init(struct putdma *pdma) +{ + memset(pdma, 0, sizeof(struct putdma)); + pdma->DoneIntEnable = 1; +} + +static inline void mbcs_algo_init(struct algoblock *algo_soft) +{ + memset(algo_soft, 0, sizeof(struct algoblock)); +} + +static inline void mbcs_getdma_set(void *mmr, + uint64_t hostAddr, + uint64_t localAddr, + uint64_t localRamSel, + uint64_t numPkts, + uint64_t amoEnable, + uint64_t intrEnable, + uint64_t peerIO, + uint64_t amoHostDest, + uint64_t amoModType, uint64_t intrHostDest, + uint64_t intrVector) +{ + union dma_control rdma_control; + union dma_amo_dest amo_dest; + union intr_dest intr_dest; + union dma_localaddr local_addr; + union dma_hostaddr host_addr; + + rdma_control.dma_control_reg = 0; + amo_dest.dma_amo_dest_reg = 0; + intr_dest.intr_dest_reg = 0; + local_addr.dma_localaddr_reg = 0; + host_addr.dma_hostaddr_reg = 0; + + host_addr.dma_sys_addr = hostAddr; + MBCS_MMR_SET(mmr, MBCS_RD_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg); + + local_addr.dma_ram_addr = localAddr; + local_addr.dma_ram_sel = localRamSel; + MBCS_MMR_SET(mmr, MBCS_RD_DMA_LOC_ADDR, local_addr.dma_localaddr_reg); + + rdma_control.dma_op_length = numPkts; + rdma_control.done_amo_en = amoEnable; + rdma_control.done_int_en = intrEnable; + rdma_control.pio_mem_n = peerIO; + MBCS_MMR_SET(mmr, MBCS_RD_DMA_CTRL, rdma_control.dma_control_reg); + + amo_dest.dma_amo_sys_addr = amoHostDest; + amo_dest.dma_amo_mod_type = amoModType; + MBCS_MMR_SET(mmr, MBCS_RD_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg); + + intr_dest.address = intrHostDest; + intr_dest.int_vector = intrVector; + MBCS_MMR_SET(mmr, MBCS_RD_DMA_INT_DEST, intr_dest.intr_dest_reg); + +} + +static inline void mbcs_putdma_set(void *mmr, + uint64_t hostAddr, + uint64_t localAddr, + uint64_t localRamSel, + uint64_t numPkts, + uint64_t amoEnable, + uint64_t intrEnable, + uint64_t peerIO, + uint64_t amoHostDest, + uint64_t amoModType, + uint64_t intrHostDest, uint64_t intrVector) +{ + union dma_control wdma_control; + union dma_amo_dest amo_dest; + union intr_dest intr_dest; + union dma_localaddr local_addr; + union dma_hostaddr host_addr; + + wdma_control.dma_control_reg = 0; + amo_dest.dma_amo_dest_reg = 0; + intr_dest.intr_dest_reg = 0; + local_addr.dma_localaddr_reg = 0; + host_addr.dma_hostaddr_reg = 0; + + host_addr.dma_sys_addr = hostAddr; + MBCS_MMR_SET(mmr, MBCS_WR_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg); + + local_addr.dma_ram_addr = localAddr; + local_addr.dma_ram_sel = localRamSel; + MBCS_MMR_SET(mmr, MBCS_WR_DMA_LOC_ADDR, local_addr.dma_localaddr_reg); + + wdma_control.dma_op_length = numPkts; + wdma_control.done_amo_en = amoEnable; + wdma_control.done_int_en = intrEnable; + wdma_control.pio_mem_n = peerIO; + MBCS_MMR_SET(mmr, MBCS_WR_DMA_CTRL, wdma_control.dma_control_reg); + + amo_dest.dma_amo_sys_addr = amoHostDest; + amo_dest.dma_amo_mod_type = amoModType; + MBCS_MMR_SET(mmr, MBCS_WR_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg); + + intr_dest.address = intrHostDest; + intr_dest.int_vector = intrVector; + MBCS_MMR_SET(mmr, MBCS_WR_DMA_INT_DEST, intr_dest.intr_dest_reg); + +} + +static inline void mbcs_algo_set(void *mmr, + uint64_t amoHostDest, + uint64_t amoModType, + uint64_t intrHostDest, + uint64_t intrVector, uint64_t algoStepCount) +{ + union dma_amo_dest amo_dest; + union intr_dest intr_dest; + union algo_step step; + + step.algo_step_reg = 0; + intr_dest.intr_dest_reg = 0; + amo_dest.dma_amo_dest_reg = 0; + + amo_dest.dma_amo_sys_addr = amoHostDest; + amo_dest.dma_amo_mod_type = amoModType; + MBCS_MMR_SET(mmr, MBCS_ALG_AMO_DEST, amo_dest.dma_amo_dest_reg); + + intr_dest.address = intrHostDest; + intr_dest.int_vector = intrVector; + MBCS_MMR_SET(mmr, MBCS_ALG_INT_DEST, intr_dest.intr_dest_reg); + + step.alg_step_cnt = algoStepCount; + MBCS_MMR_SET(mmr, MBCS_ALG_STEP, step.algo_step_reg); +} + +static inline int mbcs_getdma_start(struct mbcs_soft *soft) +{ + void *mmr_base; + struct getdma *gdma; + uint64_t numPkts; + union cm_control cm_control; + + mmr_base = soft->mmr_base; + gdma = &soft->getdma; + + /* check that host address got setup */ + if (!gdma->hostAddr) + return -1; + + numPkts = + (gdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE; + + /* program engine */ + mbcs_getdma_set(mmr_base, tiocx_dma_addr(gdma->hostAddr), + gdma->localAddr, + (gdma->localAddr < MB2) ? 0 : + (gdma->localAddr < MB4) ? 1 : + (gdma->localAddr < MB6) ? 2 : 3, + numPkts, + gdma->DoneAmoEnable, + gdma->DoneIntEnable, + gdma->peerIO, + gdma->amoHostDest, + gdma->amoModType, + gdma->intrHostDest, gdma->intrVector); + + /* start engine */ + cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); + cm_control.rd_dma_go = 1; + MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); + + return 0; + +} + +static inline int mbcs_putdma_start(struct mbcs_soft *soft) +{ + void *mmr_base; + struct putdma *pdma; + uint64_t numPkts; + union cm_control cm_control; + + mmr_base = soft->mmr_base; + pdma = &soft->putdma; + + /* check that host address got setup */ + if (!pdma->hostAddr) + return -1; + + numPkts = + (pdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE; + + /* program engine */ + mbcs_putdma_set(mmr_base, tiocx_dma_addr(pdma->hostAddr), + pdma->localAddr, + (pdma->localAddr < MB2) ? 0 : + (pdma->localAddr < MB4) ? 1 : + (pdma->localAddr < MB6) ? 2 : 3, + numPkts, + pdma->DoneAmoEnable, + pdma->DoneIntEnable, + pdma->peerIO, + pdma->amoHostDest, + pdma->amoModType, + pdma->intrHostDest, pdma->intrVector); + + /* start engine */ + cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); + cm_control.wr_dma_go = 1; + MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); + + return 0; + +} + +static inline int mbcs_algo_start(struct mbcs_soft *soft) +{ + struct algoblock *algo_soft = &soft->algo; + void *mmr_base = soft->mmr_base; + union cm_control cm_control; + + if (down_interruptible(&soft->algolock)) + return -ERESTARTSYS; + + atomic_set(&soft->algo_done, 0); + + mbcs_algo_set(mmr_base, + algo_soft->amoHostDest, + algo_soft->amoModType, + algo_soft->intrHostDest, + algo_soft->intrVector, algo_soft->algoStepCount); + + /* start algorithm */ + cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); + cm_control.alg_done_int_en = 1; + cm_control.alg_go = 1; + MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); + + up(&soft->algolock); + + return 0; +} + +static inline ssize_t +do_mbcs_sram_dmawrite(struct mbcs_soft *soft, uint64_t hostAddr, + size_t len, loff_t * off) +{ + int rv = 0; + + if (down_interruptible(&soft->dmawritelock)) + return -ERESTARTSYS; + + atomic_set(&soft->dmawrite_done, 0); + + soft->putdma.hostAddr = hostAddr; + soft->putdma.localAddr = *off; + soft->putdma.bytes = len; + + if (mbcs_putdma_start(soft) < 0) { + DBG(KERN_ALERT "do_mbcs_sram_dmawrite: " + "mbcs_putdma_start failed\n"); + rv = -EAGAIN; + goto dmawrite_exit; + } + + if (wait_event_interruptible(soft->dmawrite_queue, + atomic_read(&soft->dmawrite_done))) { + rv = -ERESTARTSYS; + goto dmawrite_exit; + } + + rv = len; + *off += len; + +dmawrite_exit: + up(&soft->dmawritelock); + + return rv; +} + +static inline ssize_t +do_mbcs_sram_dmaread(struct mbcs_soft *soft, uint64_t hostAddr, + size_t len, loff_t * off) +{ + int rv = 0; + + if (down_interruptible(&soft->dmareadlock)) + return -ERESTARTSYS; + + atomic_set(&soft->dmawrite_done, 0); + + soft->getdma.hostAddr = hostAddr; + soft->getdma.localAddr = *off; + soft->getdma.bytes = len; + + if (mbcs_getdma_start(soft) < 0) { + DBG(KERN_ALERT "mbcs_strategy: mbcs_getdma_start failed\n"); + rv = -EAGAIN; + goto dmaread_exit; + } + + if (wait_event_interruptible(soft->dmaread_queue, + atomic_read(&soft->dmaread_done))) { + rv = -ERESTARTSYS; + goto dmaread_exit; + } + + rv = len; + *off += len; + +dmaread_exit: + up(&soft->dmareadlock); + + return rv; +} + +int mbcs_open(struct inode *ip, struct file *fp) +{ + struct mbcs_soft *soft; + int minor; + + minor = iminor(ip); + + list_for_each_entry(soft, &soft_list, list) { + if (soft->nasid == minor) { + fp->private_data = soft->cxdev; + return 0; + } + } + + return -ENODEV; +} + +ssize_t mbcs_sram_read(struct file * fp, char *buf, size_t len, loff_t * off) +{ + struct cx_dev *cx_dev = fp->private_data; + struct mbcs_soft *soft = cx_dev->soft; + uint64_t hostAddr; + int rv = 0; + + hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len)); + if (hostAddr == 0) + return -ENOMEM; + + rv = do_mbcs_sram_dmawrite(soft, hostAddr, len, off); + if (rv < 0) + goto exit; + + if (copy_to_user(buf, (void *)hostAddr, len)) + rv = -EFAULT; + + exit: + free_pages(hostAddr, get_order(len)); + + return rv; +} + +ssize_t +mbcs_sram_write(struct file * fp, const char *buf, size_t len, loff_t * off) +{ + struct cx_dev *cx_dev = fp->private_data; + struct mbcs_soft *soft = cx_dev->soft; + uint64_t hostAddr; + int rv = 0; + + hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len)); + if (hostAddr == 0) + return -ENOMEM; + + if (copy_from_user((void *)hostAddr, buf, len)) { + rv = -EFAULT; + goto exit; + } + + rv = do_mbcs_sram_dmaread(soft, hostAddr, len, off); + + exit: + free_pages(hostAddr, get_order(len)); + + return rv; +} + +loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence) +{ + loff_t newpos; + + switch (whence) { + case 0: /* SEEK_SET */ + newpos = off; + break; + + case 1: /* SEEK_CUR */ + newpos = filp->f_pos + off; + break; + + case 2: /* SEEK_END */ + newpos = MBCS_SRAM_SIZE + off; + break; + + default: /* can't happen */ + return -EINVAL; + } + + if (newpos < 0) + return -EINVAL; + + filp->f_pos = newpos; + + return newpos; +} + +static uint64_t mbcs_pioaddr(struct mbcs_soft *soft, uint64_t offset) +{ + uint64_t mmr_base; + + mmr_base = (uint64_t) (soft->mmr_base + offset); + + return mmr_base; +} + +static void mbcs_debug_pioaddr_set(struct mbcs_soft *soft) +{ + soft->debug_addr = mbcs_pioaddr(soft, MBCS_DEBUG_START); +} + +static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft) +{ + soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START); +} + +int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma) +{ + struct cx_dev *cx_dev = fp->private_data; + struct mbcs_soft *soft = cx_dev->soft; + + if (vma->vm_pgoff != 0) + return -EINVAL; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ + if (remap_pfn_range(vma, + vma->vm_start, + __pa(soft->gscr_addr) >> PAGE_SHIFT, + PAGE_SIZE, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +/** + * mbcs_completion_intr_handler - Primary completion handler. + * @irq: irq + * @arg: soft struct for device + * @ep: regs + * + */ +static irqreturn_t +mbcs_completion_intr_handler(int irq, void *arg, struct pt_regs *ep) +{ + struct mbcs_soft *soft = (struct mbcs_soft *)arg; + void *mmr_base; + union cm_status cm_status; + union cm_control cm_control; + + mmr_base = soft->mmr_base; + cm_status.cm_status_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_STATUS); + + if (cm_status.rd_dma_done) { + /* stop dma-read engine, clear status */ + cm_control.cm_control_reg = + MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); + cm_control.rd_dma_clr = 1; + MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, + cm_control.cm_control_reg); + atomic_set(&soft->dmaread_done, 1); + wake_up(&soft->dmaread_queue); + } + if (cm_status.wr_dma_done) { + /* stop dma-write engine, clear status */ + cm_control.cm_control_reg = + MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); + cm_control.wr_dma_clr = 1; + MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, + cm_control.cm_control_reg); + atomic_set(&soft->dmawrite_done, 1); + wake_up(&soft->dmawrite_queue); + } + if (cm_status.alg_done) { + /* clear status */ + cm_control.cm_control_reg = + MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); + cm_control.alg_done_clr = 1; + MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, + cm_control.cm_control_reg); + atomic_set(&soft->algo_done, 1); + wake_up(&soft->algo_queue); + } + + return IRQ_HANDLED; +} + +/** + * mbcs_intr_alloc - Allocate interrupts. + * @dev: device pointer + * + */ +static int mbcs_intr_alloc(struct cx_dev *dev) +{ + struct sn_irq_info *sn_irq; + struct mbcs_soft *soft; + struct getdma *getdma; + struct putdma *putdma; + struct algoblock *algo; + + soft = dev->soft; + getdma = &soft->getdma; + putdma = &soft->putdma; + algo = &soft->algo; + + soft->get_sn_irq = NULL; + soft->put_sn_irq = NULL; + soft->algo_sn_irq = NULL; + + sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); + if (sn_irq == NULL) + return -EAGAIN; + soft->get_sn_irq = sn_irq; + getdma->intrHostDest = sn_irq->irq_xtalkaddr; + getdma->intrVector = sn_irq->irq_irq; + if (request_irq(sn_irq->irq_irq, + (void *)mbcs_completion_intr_handler, SA_SHIRQ, + "MBCS get intr", (void *)soft)) { + tiocx_irq_free(soft->get_sn_irq); + return -EAGAIN; + } + + sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); + if (sn_irq == NULL) { + free_irq(soft->get_sn_irq->irq_irq, soft); + tiocx_irq_free(soft->get_sn_irq); + return -EAGAIN; + } + soft->put_sn_irq = sn_irq; + putdma->intrHostDest = sn_irq->irq_xtalkaddr; + putdma->intrVector = sn_irq->irq_irq; + if (request_irq(sn_irq->irq_irq, + (void *)mbcs_completion_intr_handler, SA_SHIRQ, + "MBCS put intr", (void *)soft)) { + tiocx_irq_free(soft->put_sn_irq); + free_irq(soft->get_sn_irq->irq_irq, soft); + tiocx_irq_free(soft->get_sn_irq); + return -EAGAIN; + } + + sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); + if (sn_irq == NULL) { + free_irq(soft->put_sn_irq->irq_irq, soft); + tiocx_irq_free(soft->put_sn_irq); + free_irq(soft->get_sn_irq->irq_irq, soft); + tiocx_irq_free(soft->get_sn_irq); + return -EAGAIN; + } + soft->algo_sn_irq = sn_irq; + algo->intrHostDest = sn_irq->irq_xtalkaddr; + algo->intrVector = sn_irq->irq_irq; + if (request_irq(sn_irq->irq_irq, + (void *)mbcs_completion_intr_handler, SA_SHIRQ, + "MBCS algo intr", (void *)soft)) { + tiocx_irq_free(soft->algo_sn_irq); + free_irq(soft->put_sn_irq->irq_irq, soft); + tiocx_irq_free(soft->put_sn_irq); + free_irq(soft->get_sn_irq->irq_irq, soft); + tiocx_irq_free(soft->get_sn_irq); + return -EAGAIN; + } + + return 0; +} + +/** + * mbcs_intr_dealloc - Remove interrupts. + * @dev: device pointer + * + */ +static void mbcs_intr_dealloc(struct cx_dev *dev) +{ + struct mbcs_soft *soft; + + soft = dev->soft; + + free_irq(soft->get_sn_irq->irq_irq, soft); + tiocx_irq_free(soft->get_sn_irq); + free_irq(soft->put_sn_irq->irq_irq, soft); + tiocx_irq_free(soft->put_sn_irq); + free_irq(soft->algo_sn_irq->irq_irq, soft); + tiocx_irq_free(soft->algo_sn_irq); +} + +static inline int mbcs_hw_init(struct mbcs_soft *soft) +{ + void *mmr_base = soft->mmr_base; + union cm_control cm_control; + union cm_req_timeout cm_req_timeout; + uint64_t err_stat; + + cm_req_timeout.cm_req_timeout_reg = + MBCS_MMR_GET(mmr_base, MBCS_CM_REQ_TOUT); + + cm_req_timeout.time_out = MBCS_CM_CONTROL_REQ_TOUT_MASK; + MBCS_MMR_SET(mmr_base, MBCS_CM_REQ_TOUT, + cm_req_timeout.cm_req_timeout_reg); + + mbcs_gscr_pioaddr_set(soft); + mbcs_debug_pioaddr_set(soft); + + /* clear errors */ + err_stat = MBCS_MMR_GET(mmr_base, MBCS_CM_ERR_STAT); + MBCS_MMR_SET(mmr_base, MBCS_CM_CLR_ERR_STAT, err_stat); + MBCS_MMR_ZERO(mmr_base, MBCS_CM_ERROR_DETAIL1); + + /* enable interrupts */ + /* turn off 2^23 (INT_EN_PIO_REQ_ADDR_INV) */ + MBCS_MMR_SET(mmr_base, MBCS_CM_ERR_INT_EN, 0x3ffffff7e00ffUL); + + /* arm status regs and clear engines */ + cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); + cm_control.rearm_stat_regs = 1; + cm_control.alg_clr = 1; + cm_control.wr_dma_clr = 1; + cm_control.rd_dma_clr = 1; + + MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); + + return 0; +} + +static ssize_t show_algo(struct device *dev, char *buf) +{ + struct cx_dev *cx_dev = to_cx_dev(dev); + struct mbcs_soft *soft = cx_dev->soft; + uint64_t debug0; + + /* + * By convention, the first debug register contains the + * algorithm number and revision. + */ + debug0 = *(uint64_t *) soft->debug_addr; + + return sprintf(buf, "0x%lx 0x%lx\n", + (debug0 >> 32), (debug0 & 0xffffffff)); +} + +static ssize_t store_algo(struct device *dev, const char *buf, size_t count) +{ + int n; + struct cx_dev *cx_dev = to_cx_dev(dev); + struct mbcs_soft *soft = cx_dev->soft; + + if (count <= 0) + return 0; + + n = simple_strtoul(buf, NULL, 0); + + if (n == 1) { + mbcs_algo_start(soft); + if (wait_event_interruptible(soft->algo_queue, + atomic_read(&soft->algo_done))) + return -ERESTARTSYS; + } + + return count; +} + +DEVICE_ATTR(algo, 0644, show_algo, store_algo); + +/** + * mbcs_probe - Initialize for device + * @dev: device pointer + * @device_id: id table pointer + * + */ +static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id) +{ + struct mbcs_soft *soft; + + dev->soft = NULL; + + soft = kcalloc(1, sizeof(struct mbcs_soft), GFP_KERNEL); + if (soft == NULL) + return -ENOMEM; + + soft->nasid = dev->cx_id.nasid; + list_add(&soft->list, &soft_list); + soft->mmr_base = (void *)tiocx_swin_base(dev->cx_id.nasid); + dev->soft = soft; + soft->cxdev = dev; + + init_waitqueue_head(&soft->dmawrite_queue); + init_waitqueue_head(&soft->dmaread_queue); + init_waitqueue_head(&soft->algo_queue); + + init_MUTEX(&soft->dmawritelock); + init_MUTEX(&soft->dmareadlock); + init_MUTEX(&soft->algolock); + + mbcs_getdma_init(&soft->getdma); + mbcs_putdma_init(&soft->putdma); + mbcs_algo_init(&soft->algo); + + mbcs_hw_init(soft); + + /* Allocate interrupts */ + mbcs_intr_alloc(dev); + + device_create_file(&dev->dev, &dev_attr_algo); + + return 0; +} + +static int mbcs_remove(struct cx_dev *dev) +{ + if (dev->soft) { + mbcs_intr_dealloc(dev); + kfree(dev->soft); + } + + device_remove_file(&dev->dev, &dev_attr_algo); + + return 0; +} + +const struct cx_device_id __devinitdata mbcs_id_table[] = { + { + .part_num = MBCS_PART_NUM, + .mfg_num = MBCS_MFG_NUM, + }, + { + .part_num = MBCS_PART_NUM_ALG0, + .mfg_num = MBCS_MFG_NUM, + }, + {0, 0} +}; + +MODULE_DEVICE_TABLE(cx, mbcs_id_table); + +struct cx_drv mbcs_driver = { + .name = DEVICE_NAME, + .id_table = mbcs_id_table, + .probe = mbcs_probe, + .remove = mbcs_remove, +}; + +static void __exit mbcs_exit(void) +{ + int rv; + + rv = unregister_chrdev(mbcs_major, DEVICE_NAME); + if (rv < 0) + DBG(KERN_ALERT "Error in unregister_chrdev: %d\n", rv); + + cx_driver_unregister(&mbcs_driver); +} + +static int __init mbcs_init(void) +{ + int rv; + + // Put driver into chrdevs[]. Get major number. + rv = register_chrdev(mbcs_major, DEVICE_NAME, &mbcs_ops); + if (rv < 0) { + DBG(KERN_ALERT "mbcs_init: can't get major number. %d\n", rv); + return rv; + } + mbcs_major = rv; + + return cx_driver_register(&mbcs_driver); +} + +module_init(mbcs_init); +module_exit(mbcs_exit); + +MODULE_AUTHOR("Bruce Losure "); +MODULE_DESCRIPTION("Driver for MOATB Core Services"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h new file mode 100644 index 0000000..844644d --- /dev/null +++ b/drivers/char/mbcs.h @@ -0,0 +1,553 @@ +/* + * 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. + * + * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. + */ + +#ifndef __MBCS_H__ +#define __MBCS_H__ + +/* + * General macros + */ +#define MB (1024*1024) +#define MB2 (2*MB) +#define MB4 (4*MB) +#define MB6 (6*MB) + +/* + * Offsets and masks + */ +#define MBCS_CM_ID 0x0000 /* Identification */ +#define MBCS_CM_STATUS 0x0008 /* Status */ +#define MBCS_CM_ERROR_DETAIL1 0x0010 /* Error Detail1 */ +#define MBCS_CM_ERROR_DETAIL2 0x0018 /* Error Detail2 */ +#define MBCS_CM_CONTROL 0x0020 /* Control */ +#define MBCS_CM_REQ_TOUT 0x0028 /* Request Time-out */ +#define MBCS_CM_ERR_INT_DEST 0x0038 /* Error Interrupt Destination */ +#define MBCS_CM_TARG_FL 0x0050 /* Target Flush */ +#define MBCS_CM_ERR_STAT 0x0060 /* Error Status */ +#define MBCS_CM_CLR_ERR_STAT 0x0068 /* Clear Error Status */ +#define MBCS_CM_ERR_INT_EN 0x0070 /* Error Interrupt Enable */ +#define MBCS_RD_DMA_SYS_ADDR 0x0100 /* Read DMA System Address */ +#define MBCS_RD_DMA_LOC_ADDR 0x0108 /* Read DMA Local Address */ +#define MBCS_RD_DMA_CTRL 0x0110 /* Read DMA Control */ +#define MBCS_RD_DMA_AMO_DEST 0x0118 /* Read DMA AMO Destination */ +#define MBCS_RD_DMA_INT_DEST 0x0120 /* Read DMA Interrupt Destination */ +#define MBCS_RD_DMA_AUX_STAT 0x0130 /* Read DMA Auxillary Status */ +#define MBCS_WR_DMA_SYS_ADDR 0x0200 /* Write DMA System Address */ +#define MBCS_WR_DMA_LOC_ADDR 0x0208 /* Write DMA Local Address */ +#define MBCS_WR_DMA_CTRL 0x0210 /* Write DMA Control */ +#define MBCS_WR_DMA_AMO_DEST 0x0218 /* Write DMA AMO Destination */ +#define MBCS_WR_DMA_INT_DEST 0x0220 /* Write DMA Interrupt Destination */ +#define MBCS_WR_DMA_AUX_STAT 0x0230 /* Write DMA Auxillary Status */ +#define MBCS_ALG_AMO_DEST 0x0300 /* Algorithm AMO Destination */ +#define MBCS_ALG_INT_DEST 0x0308 /* Algorithm Interrupt Destination */ +#define MBCS_ALG_OFFSETS 0x0310 +#define MBCS_ALG_STEP 0x0318 /* Algorithm Step */ + +#define MBCS_GSCR_START 0x0000000 +#define MBCS_DEBUG_START 0x0100000 +#define MBCS_RAM0_START 0x0200000 +#define MBCS_RAM1_START 0x0400000 +#define MBCS_RAM2_START 0x0600000 + +#define MBCS_CM_CONTROL_REQ_TOUT_MASK 0x0000000000ffffffUL +//#define PIO_BASE_ADDR_BASE_OFFSET_MASK 0x00fffffffff00000UL + +#define MBCS_SRAM_SIZE (1024*1024) +#define MBCS_CACHELINE_SIZE 128 + +/* + * MMR get's and put's + */ +#define MBCS_MMR_ADDR(mmr_base, offset)((uint64_t *)(mmr_base + offset)) +#define MBCS_MMR_SET(mmr_base, offset, value) { \ + uint64_t *mbcs_mmr_set_u64p, readback; \ + mbcs_mmr_set_u64p = (uint64_t *)(mmr_base + offset); \ + *mbcs_mmr_set_u64p = value; \ + readback = *mbcs_mmr_set_u64p; \ +} +#define MBCS_MMR_GET(mmr_base, offset) *(uint64_t *)(mmr_base + offset) +#define MBCS_MMR_ZERO(mmr_base, offset) MBCS_MMR_SET(mmr_base, offset, 0) + +/* + * MBCS mmr structures + */ +union cm_id { + uint64_t cm_id_reg; + struct { + uint64_t always_one:1, // 0 + mfg_id:11, // 11:1 + part_num:16, // 27:12 + bitstream_rev:8, // 35:28 + :28; // 63:36 + }; +}; + +union cm_status { + uint64_t cm_status_reg; + struct { + uint64_t pending_reads:8, // 7:0 + pending_writes:8, // 15:8 + ice_rsp_credits:8, // 23:16 + ice_req_credits:8, // 31:24 + cm_req_credits:8, // 39:32 + :1, // 40 + rd_dma_in_progress:1, // 41 + rd_dma_done:1, // 42 + :1, // 43 + wr_dma_in_progress:1, // 44 + wr_dma_done:1, // 45 + alg_waiting:1, // 46 + alg_pipe_running:1, // 47 + alg_done:1, // 48 + :3, // 51:49 + pending_int_reqs:8, // 59:52 + :3, // 62:60 + alg_half_speed_sel:1; // 63 + }; +}; + +union cm_error_detail1 { + uint64_t cm_error_detail1_reg; + struct { + uint64_t packet_type:4, // 3:0 + source_id:2, // 5:4 + data_size:2, // 7:6 + tnum:8, // 15:8 + byte_enable:8, // 23:16 + gfx_cred:8, // 31:24 + read_type:2, // 33:32 + pio_or_memory:1, // 34 + head_cw_error:1, // 35 + :12, // 47:36 + head_error_bit:1, // 48 + data_error_bit:1, // 49 + :13, // 62:50 + valid:1; // 63 + }; +}; + +union cm_error_detail2 { + uint64_t cm_error_detail2_reg; + struct { + uint64_t address:56, // 55:0 + :8; // 63:56 + }; +}; + +union cm_control { + uint64_t cm_control_reg; + struct { + uint64_t cm_id:2, // 1:0 + :2, // 3:2 + max_trans:5, // 8:4 + :3, // 11:9 + address_mode:1, // 12 + :7, // 19:13 + credit_limit:8, // 27:20 + :5, // 32:28 + rearm_stat_regs:1, // 33 + prescalar_byp:1, // 34 + force_gap_war:1, // 35 + rd_dma_go:1, // 36 + wr_dma_go:1, // 37 + alg_go:1, // 38 + rd_dma_clr:1, // 39 + wr_dma_clr:1, // 40 + alg_clr:1, // 41 + :2, // 43:42 + alg_wait_step:1, // 44 + alg_done_amo_en:1, // 45 + alg_done_int_en:1, // 46 + :1, // 47 + alg_sram0_locked:1, // 48 + alg_sram1_locked:1, // 49 + alg_sram2_locked:1, // 50 + alg_done_clr:1, // 51 + :12; // 63:52 + }; +}; + +union cm_req_timeout { + uint64_t cm_req_timeout_reg; + struct { + uint64_t time_out:24, // 23:0 + :40; // 63:24 + }; +}; + +union intr_dest { + uint64_t intr_dest_reg; + struct { + uint64_t address:56, // 55:0 + int_vector:8; // 63:56 + }; +}; + +union cm_error_status { + uint64_t cm_error_status_reg; + struct { + uint64_t ecc_sbe:1, // 0 + ecc_mbe:1, // 1 + unsupported_req:1, // 2 + unexpected_rsp:1, // 3 + bad_length:1, // 4 + bad_datavalid:1, // 5 + buffer_overflow:1, // 6 + request_timeout:1, // 7 + :8, // 15:8 + head_inv_data_size:1, // 16 + rsp_pactype_inv:1, // 17 + head_sb_err:1, // 18 + missing_head:1, // 19 + head_inv_rd_type:1, // 20 + head_cmd_err_bit:1, // 21 + req_addr_align_inv:1, // 22 + pio_req_addr_inv:1, // 23 + req_range_dsize_inv:1, // 24 + early_term:1, // 25 + early_tail:1, // 26 + missing_tail:1, // 27 + data_flit_sb_err:1, // 28 + cm2hcm_req_cred_of:1, // 29 + cm2hcm_rsp_cred_of:1, // 30 + rx_bad_didn:1, // 31 + rd_dma_err_rsp:1, // 32 + rd_dma_tnum_tout:1, // 33 + rd_dma_multi_tnum_tou:1, // 34 + wr_dma_err_rsp:1, // 35 + wr_dma_tnum_tout:1, // 36 + wr_dma_multi_tnum_tou:1, // 37 + alg_data_overflow:1, // 38 + alg_data_underflow:1, // 39 + ram0_access_conflict:1, // 40 + ram1_access_conflict:1, // 41 + ram2_access_conflict:1, // 42 + ram0_perr:1, // 43 + ram1_perr:1, // 44 + ram2_perr:1, // 45 + int_gen_rsp_err:1, // 46 + int_gen_tnum_tout:1, // 47 + rd_dma_prog_err:1, // 48 + wr_dma_prog_err:1, // 49 + :14; // 63:50 + }; +}; + +union cm_clr_error_status { + uint64_t cm_clr_error_status_reg; + struct { + uint64_t clr_ecc_sbe:1, // 0 + clr_ecc_mbe:1, // 1 + clr_unsupported_req:1, // 2 + clr_unexpected_rsp:1, // 3 + clr_bad_length:1, // 4 + clr_bad_datavalid:1, // 5 + clr_buffer_overflow:1, // 6 + clr_request_timeout:1, // 7 + :8, // 15:8 + clr_head_inv_data_siz:1, // 16 + clr_rsp_pactype_inv:1, // 17 + clr_head_sb_err:1, // 18 + clr_missing_head:1, // 19 + clr_head_inv_rd_type:1, // 20 + clr_head_cmd_err_bit:1, // 21 + clr_req_addr_align_in:1, // 22 + clr_pio_req_addr_inv:1, // 23 + clr_req_range_dsize_i:1, // 24 + clr_early_term:1, // 25 + clr_early_tail:1, // 26 + clr_missing_tail:1, // 27 + clr_data_flit_sb_err:1, // 28 + clr_cm2hcm_req_cred_o:1, // 29 + clr_cm2hcm_rsp_cred_o:1, // 30 + clr_rx_bad_didn:1, // 31 + clr_rd_dma_err_rsp:1, // 32 + clr_rd_dma_tnum_tout:1, // 33 + clr_rd_dma_multi_tnum:1, // 34 + clr_wr_dma_err_rsp:1, // 35 + clr_wr_dma_tnum_tout:1, // 36 + clr_wr_dma_multi_tnum:1, // 37 + clr_alg_data_overflow:1, // 38 + clr_alg_data_underflo:1, // 39 + clr_ram0_access_confl:1, // 40 + clr_ram1_access_confl:1, // 41 + clr_ram2_access_confl:1, // 42 + clr_ram0_perr:1, // 43 + clr_ram1_perr:1, // 44 + clr_ram2_perr:1, // 45 + clr_int_gen_rsp_err:1, // 46 + clr_int_gen_tnum_tout:1, // 47 + clr_rd_dma_prog_err:1, // 48 + clr_wr_dma_prog_err:1, // 49 + :14; // 63:50 + }; +}; + +union cm_error_intr_enable { + uint64_t cm_error_intr_enable_reg; + struct { + uint64_t int_en_ecc_sbe:1, // 0 + int_en_ecc_mbe:1, // 1 + int_en_unsupported_re:1, // 2 + int_en_unexpected_rsp:1, // 3 + int_en_bad_length:1, // 4 + int_en_bad_datavalid:1, // 5 + int_en_buffer_overflo:1, // 6 + int_en_request_timeou:1, // 7 + :8, // 15:8 + int_en_head_inv_data_:1, // 16 + int_en_rsp_pactype_in:1, // 17 + int_en_head_sb_err:1, // 18 + int_en_missing_head:1, // 19 + int_en_head_inv_rd_ty:1, // 20 + int_en_head_cmd_err_b:1, // 21 + int_en_req_addr_align:1, // 22 + int_en_pio_req_addr_i:1, // 23 + int_en_req_range_dsiz:1, // 24 + int_en_early_term:1, // 25 + int_en_early_tail:1, // 26 + int_en_missing_tail:1, // 27 + int_en_data_flit_sb_e:1, // 28 + int_en_cm2hcm_req_cre:1, // 29 + int_en_cm2hcm_rsp_cre:1, // 30 + int_en_rx_bad_didn:1, // 31 + int_en_rd_dma_err_rsp:1, // 32 + int_en_rd_dma_tnum_to:1, // 33 + int_en_rd_dma_multi_t:1, // 34 + int_en_wr_dma_err_rsp:1, // 35 + int_en_wr_dma_tnum_to:1, // 36 + int_en_wr_dma_multi_t:1, // 37 + int_en_alg_data_overf:1, // 38 + int_en_alg_data_under:1, // 39 + int_en_ram0_access_co:1, // 40 + int_en_ram1_access_co:1, // 41 + int_en_ram2_access_co:1, // 42 + int_en_ram0_perr:1, // 43 + int_en_ram1_perr:1, // 44 + int_en_ram2_perr:1, // 45 + int_en_int_gen_rsp_er:1, // 46 + int_en_int_gen_tnum_t:1, // 47 + int_en_rd_dma_prog_er:1, // 48 + int_en_wr_dma_prog_er:1, // 49 + :14; // 63:50 + }; +}; + +struct cm_mmr { + union cm_id id; + union cm_status status; + union cm_error_detail1 err_detail1; + union cm_error_detail2 err_detail2; + union cm_control control; + union cm_req_timeout req_timeout; + uint64_t reserved1[1]; + union intr_dest int_dest; + uint64_t reserved2[2]; + uint64_t targ_flush; + uint64_t reserved3[1]; + union cm_error_status err_status; + union cm_clr_error_status clr_err_status; + union cm_error_intr_enable int_enable; +}; + +union dma_hostaddr { + uint64_t dma_hostaddr_reg; + struct { + uint64_t dma_sys_addr:56, // 55:0 + :8; // 63:56 + }; +}; + +union dma_localaddr { + uint64_t dma_localaddr_reg; + struct { + uint64_t dma_ram_addr:21, // 20:0 + dma_ram_sel:2, // 22:21 + :41; // 63:23 + }; +}; + +union dma_control { + uint64_t dma_control_reg; + struct { + uint64_t dma_op_length:16, // 15:0 + :18, // 33:16 + done_amo_en:1, // 34 + done_int_en:1, // 35 + :1, // 36 + pio_mem_n:1, // 37 + :26; // 63:38 + }; +}; + +union dma_amo_dest { + uint64_t dma_amo_dest_reg; + struct { + uint64_t dma_amo_sys_addr:56, // 55:0 + dma_amo_mod_type:3, // 58:56 + :5; // 63:59 + }; +}; + +union rdma_aux_status { + uint64_t rdma_aux_status_reg; + struct { + uint64_t op_num_pacs_left:17, // 16:0 + :5, // 21:17 + lrsp_buff_empty:1, // 22 + :17, // 39:23 + pending_reqs_left:6, // 45:40 + :18; // 63:46 + }; +}; + +struct rdma_mmr { + union dma_hostaddr host_addr; + union dma_localaddr local_addr; + union dma_control control; + union dma_amo_dest amo_dest; + union intr_dest intr_dest; + union rdma_aux_status aux_status; +}; + +union wdma_aux_status { + uint64_t wdma_aux_status_reg; + struct { + uint64_t op_num_pacs_left:17, // 16:0 + :4, // 20:17 + lreq_buff_empty:1, // 21 + :18, // 39:22 + pending_reqs_left:6, // 45:40 + :18; // 63:46 + }; +}; + +struct wdma_mmr { + union dma_hostaddr host_addr; + union dma_localaddr local_addr; + union dma_control control; + union dma_amo_dest amo_dest; + union intr_dest intr_dest; + union wdma_aux_status aux_status; +}; + +union algo_step { + uint64_t algo_step_reg; + struct { + uint64_t alg_step_cnt:16, // 15:0 + :48; // 63:16 + }; +}; + +struct algo_mmr { + union dma_amo_dest amo_dest; + union intr_dest intr_dest; + union { + uint64_t algo_offset_reg; + struct { + uint64_t sram0_offset:7, // 6:0 + reserved0:1, // 7 + sram1_offset:7, // 14:8 + reserved1:1, // 15 + sram2_offset:7, // 22:16 + reserved2:14; // 63:23 + }; + } sram_offset; + union algo_step step; +}; + +struct mbcs_mmr { + struct cm_mmr cm; + uint64_t reserved1[17]; + struct rdma_mmr rdDma; + uint64_t reserved2[25]; + struct wdma_mmr wrDma; + uint64_t reserved3[25]; + struct algo_mmr algo; + uint64_t reserved4[156]; +}; + +/* + * defines + */ +#define DEVICE_NAME "mbcs" +#define MBCS_PART_NUM 0xfff0 +#define MBCS_PART_NUM_ALG0 0xf001 +#define MBCS_MFG_NUM 0x1 + +struct algoblock { + uint64_t amoHostDest; + uint64_t amoModType; + uint64_t intrHostDest; + uint64_t intrVector; + uint64_t algoStepCount; +}; + +struct getdma { + uint64_t hostAddr; + uint64_t localAddr; + uint64_t bytes; + uint64_t DoneAmoEnable; + uint64_t DoneIntEnable; + uint64_t peerIO; + uint64_t amoHostDest; + uint64_t amoModType; + uint64_t intrHostDest; + uint64_t intrVector; +}; + +struct putdma { + uint64_t hostAddr; + uint64_t localAddr; + uint64_t bytes; + uint64_t DoneAmoEnable; + uint64_t DoneIntEnable; + uint64_t peerIO; + uint64_t amoHostDest; + uint64_t amoModType; + uint64_t intrHostDest; + uint64_t intrVector; +}; + +struct mbcs_soft { + struct list_head list; + struct cx_dev *cxdev; + int major; + int nasid; + void *mmr_base; + wait_queue_head_t dmawrite_queue; + wait_queue_head_t dmaread_queue; + wait_queue_head_t algo_queue; + struct sn_irq_info *get_sn_irq; + struct sn_irq_info *put_sn_irq; + struct sn_irq_info *algo_sn_irq; + struct getdma getdma; + struct putdma putdma; + struct algoblock algo; + uint64_t gscr_addr; // pio addr + uint64_t ram0_addr; // pio addr + uint64_t ram1_addr; // pio addr + uint64_t ram2_addr; // pio addr + uint64_t debug_addr; // pio addr + atomic_t dmawrite_done; + atomic_t dmaread_done; + atomic_t algo_done; + struct semaphore dmawritelock; + struct semaphore dmareadlock; + struct semaphore algolock; +}; + +extern int mbcs_open(struct inode *ip, struct file *fp); +extern ssize_t mbcs_sram_read(struct file *fp, char *buf, size_t len, + loff_t * off); +extern ssize_t mbcs_sram_write(struct file *fp, const char *buf, size_t len, + loff_t * off); +extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence); +extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma); + +#endif // __MBCS_H__ diff --git a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h index ae0bc99..960d626 100644 --- a/include/asm-ia64/sn/addrs.h +++ b/include/asm-ia64/sn/addrs.h @@ -169,7 +169,10 @@ #define TIO_BWIN_SIZE_BITS 30 /* big window size: 1G */ #define NODE_SWIN_BASE(n, w) ((w == 0) ? NODE_BWIN_BASE((n), SWIN0_BIGWIN) \ : RAW_NODE_SWIN_BASE(n, w)) +#define TIO_SWIN_BASE(n, w) (TIO_IO_BASE(n) + \ + ((u64) (w) << TIO_SWIN_SIZE_BITS)) #define NODE_IO_BASE(n) (GLOBAL_MMR_SPACE | NASID_SPACE(n)) +#define TIO_IO_BASE(n) (UNCACHED | NASID_SPACE(n)) #define BWIN_SIZE (1UL << BWIN_SIZE_BITS) #define NODE_BWIN_BASE0(n) (NODE_IO_BASE(n) + BWIN_SIZE) #define NODE_BWIN_BASE(n, w) (NODE_BWIN_BASE0(n) + ((u64) (w) << BWIN_SIZE_BITS)) diff --git a/include/asm-ia64/sn/tiocx.h b/include/asm-ia64/sn/tiocx.h new file mode 100644 index 0000000..c5447a5 --- /dev/null +++ b/include/asm-ia64/sn/tiocx.h @@ -0,0 +1,71 @@ +/* + * 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. + * + * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. + */ + +#ifndef _ASM_IA64_SN_TIO_TIOCX_H +#define _ASM_IA64_SN_TIO_TIOCX_H + +#ifdef __KERNEL__ + +struct cx_id_s { + unsigned int part_num; + unsigned int mfg_num; + int nasid; +}; + +struct cx_dev { + struct cx_id_s cx_id; + void *soft; /* driver specific */ + struct hubdev_info *hubdev; + struct device dev; + struct cx_drv *driver; +}; + +struct cx_device_id { + unsigned int part_num; + unsigned int mfg_num; +}; + +struct cx_drv { + char *name; + const struct cx_device_id *id_table; + struct device_driver driver; + int (*probe) (struct cx_dev * dev, const struct cx_device_id * id); + int (*remove) (struct cx_dev * dev); +}; + +/* create DMA address by stripping AS bits */ +#define TIOCX_DMA_ADDR(a) (uint64_t)((uint64_t)(a) & 0xffffcfffffffffUL) + +#define TIOCX_TO_TIOCX_DMA_ADDR(a) (uint64_t)(((uint64_t)(a) & 0xfffffffff) | \ + ((((uint64_t)(a)) & 0xffffc000000000UL) <<2)) + +#define TIO_CE_ASIC_PARTNUM 0xce00 +#define TIOCX_CORELET 3 + +/* These are taken from tio_mmr_as.h */ +#define TIO_ICE_FRZ_CFG TIO_MMR_ADDR_MOD(0x00000000b0008100UL) +#define TIO_ICE_PMI_TX_CFG TIO_MMR_ADDR_MOD(0x00000000b000b100UL) +#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3 TIO_MMR_ADDR_MOD(0x00000000b000be18UL) +#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK 0x000000000000000fUL + +#define to_cx_dev(n) container_of(n, struct cx_dev, dev) +#define to_cx_driver(drv) container_of(drv, struct cx_drv, driver) + +extern struct sn_irq_info *tiocx_irq_alloc(nasid_t, int, int, nasid_t, int); +extern void tiocx_irq_free(struct sn_irq_info *); +extern int cx_device_unregister(struct cx_dev *); +extern int cx_device_register(nasid_t, int, int, struct hubdev_info *); +extern int cx_driver_unregister(struct cx_drv *); +extern int cx_driver_register(struct cx_drv *); +extern uint64_t tiocx_dma_addr(uint64_t addr); +extern uint64_t tiocx_swin_base(int nasid); +extern void tiocx_mmr_store(int nasid, uint64_t offset, uint64_t value); +extern uint64_t tiocx_mmr_load(int nasid, uint64_t offset); + +#endif // __KERNEL__ +#endif // _ASM_IA64_SN_TIO_TIOCX__ -- cgit v0.10.2 From c1298c5c7e5763a3b2fd4a9535d474ff6e54cd53 Mon Sep 17 00:00:00 2001 From: Aaron J Young Date: Mon, 25 Apr 2005 13:11:14 -0700 Subject: [IA64-SGI] Altix: enable poweroff This patch adds the necessary "hook" to allow SGI/SN machines to perform a system power off upon a 'init 0', 'halt -p', 'poweroff' or 'shutdown -h'. The "hook" is to set the pm_power_off callback to ia64_sn_power_down(). pm_power_off is checked in machine_power_off()/do_poweroff() and, if set, is executed. ia64_sn_power_down() is a function already present (but not used currently) in the sn kernel. ia64_sn_power_down() makes a SAL call to execute the power off. Signed-off-by: Aaron J Young Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index f0306b5..d35f2a6 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -353,6 +354,14 @@ void __init sn_setup(char **cmdline_p) screen_info = sn_screen_info; sn_timer_init(); + + /* + * set pm_power_off to a SAL call to allow + * sn machines to power off. The SAL call can be replaced + * by an ACPI interface call when ACPI is fully implemented + * for sn. + */ + pm_power_off = ia64_sn_power_down; } /** -- cgit v0.10.2 From ff3eb55ed97db3f12964beeffe3d34602d295367 Mon Sep 17 00:00:00 2001 From: Bruce Losure Date: Mon, 25 Apr 2005 13:12:02 -0700 Subject: [IA64-SGI] Missed the "bk new" for this file in the last commit. Signed-off-by: Bruce Losure Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c new file mode 100644 index 0000000..66190d7 --- /dev/null +++ b/arch/ia64/sn/kernel/tiocx.c @@ -0,0 +1,548 @@ +/* + * 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. + * + * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tio.h" +#include "xtalk/xwidgetdev.h" +#include "xtalk/hubdev.h" + +#define CX_DEV_NONE 0 +#define DEVICE_NAME "tiocx" +#define WIDGET_ID 0 +#define TIOCX_DEBUG 0 + +#if TIOCX_DEBUG +#define DBG(fmt...) printk(KERN_ALERT fmt) +#else +#define DBG(fmt...) +#endif + +struct device_attribute dev_attr_cxdev_control; + +/** + * tiocx_match - Try to match driver id list with device. + * @dev: device pointer + * @drv: driver pointer + * + * Returns 1 if match, 0 otherwise. + */ +static int tiocx_match(struct device *dev, struct device_driver *drv) +{ + struct cx_dev *cx_dev = to_cx_dev(dev); + struct cx_drv *cx_drv = to_cx_driver(drv); + const struct cx_device_id *ids = cx_drv->id_table; + + if (!ids) + return 0; + + while (ids->part_num) { + if (ids->part_num == cx_dev->cx_id.part_num) + return 1; + ids++; + } + return 0; + +} + +static int tiocx_hotplug(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + return -ENODEV; +} + +static void tiocx_bus_release(struct device *dev) +{ + kfree(to_cx_dev(dev)); +} + +struct bus_type tiocx_bus_type = { + .name = "tiocx", + .match = tiocx_match, + .hotplug = tiocx_hotplug, +}; + +/** + * cx_device_match - Find cx_device in the id table. + * @ids: id table from driver + * @cx_device: part/mfg id for the device + * + */ +static const struct cx_device_id *cx_device_match(const struct cx_device_id + *ids, + struct cx_dev *cx_device) +{ + /* + * NOTES: We may want to check for CX_ANY_ID too. + * Do we want to match against nasid too? + * CX_DEV_NONE == 0, if the driver tries to register for + * part/mfg == 0 we should return no-match (NULL) here. + */ + while (ids->part_num && ids->mfg_num) { + if (ids->part_num == cx_device->cx_id.part_num && + ids->mfg_num == cx_device->cx_id.mfg_num) + return ids; + ids++; + } + + return NULL; +} + +/** + * cx_device_probe - Look for matching device. + * Call driver probe routine if found. + * @cx_driver: driver table (cx_drv struct) from driver + * @cx_device: part/mfg id for the device + */ +static int cx_device_probe(struct device *dev) +{ + const struct cx_device_id *id; + struct cx_drv *cx_drv = to_cx_driver(dev->driver); + struct cx_dev *cx_dev = to_cx_dev(dev); + int error = 0; + + if (!cx_dev->driver && cx_drv->probe) { + id = cx_device_match(cx_drv->id_table, cx_dev); + if (id) { + if ((error = cx_drv->probe(cx_dev, id)) < 0) + return error; + else + cx_dev->driver = cx_drv; + } + } + + return error; +} + +/** + * cx_driver_remove - Remove driver from device struct. + * @dev: device + */ +static int cx_driver_remove(struct device *dev) +{ + struct cx_dev *cx_dev = to_cx_dev(dev); + struct cx_drv *cx_drv = cx_dev->driver; + if (cx_drv->remove) + cx_drv->remove(cx_dev); + cx_dev->driver = NULL; + return 0; +} + +/** + * cx_driver_register - Register the driver. + * @cx_driver: driver table (cx_drv struct) from driver + * + * Called from the driver init routine to register a driver. + * The cx_drv struct contains the driver name, a pointer to + * a table of part/mfg numbers and a pointer to the driver's + * probe/attach routine. + */ +int cx_driver_register(struct cx_drv *cx_driver) +{ + cx_driver->driver.name = cx_driver->name; + cx_driver->driver.bus = &tiocx_bus_type; + cx_driver->driver.probe = cx_device_probe; + cx_driver->driver.remove = cx_driver_remove; + + return driver_register(&cx_driver->driver); +} + +/** + * cx_driver_unregister - Unregister the driver. + * @cx_driver: driver table (cx_drv struct) from driver + */ +int cx_driver_unregister(struct cx_drv *cx_driver) +{ + driver_unregister(&cx_driver->driver); + return 0; +} + +/** + * cx_device_register - Register a device. + * @nasid: device's nasid + * @part_num: device's part number + * @mfg_num: device's manufacturer number + * @hubdev: hub info associated with this device + * + */ +int +cx_device_register(nasid_t nasid, int part_num, int mfg_num, + struct hubdev_info *hubdev) +{ + struct cx_dev *cx_dev; + + cx_dev = kcalloc(1, sizeof(struct cx_dev), GFP_KERNEL); + DBG("cx_dev= 0x%p\n", cx_dev); + if (cx_dev == NULL) + return -ENOMEM; + + cx_dev->cx_id.part_num = part_num; + cx_dev->cx_id.mfg_num = mfg_num; + cx_dev->cx_id.nasid = nasid; + cx_dev->hubdev = hubdev; + + cx_dev->dev.parent = NULL; + cx_dev->dev.bus = &tiocx_bus_type; + cx_dev->dev.release = tiocx_bus_release; + snprintf(cx_dev->dev.bus_id, BUS_ID_SIZE, "%d.0x%x", + cx_dev->cx_id.nasid, cx_dev->cx_id.part_num); + device_register(&cx_dev->dev); + get_device(&cx_dev->dev); + + device_create_file(&cx_dev->dev, &dev_attr_cxdev_control); + + return 0; +} + +/** + * cx_device_unregister - Unregister a device. + * @cx_dev: part/mfg id for the device + */ +int cx_device_unregister(struct cx_dev *cx_dev) +{ + put_device(&cx_dev->dev); + device_unregister(&cx_dev->dev); + return 0; +} + +/** + * cx_device_reload - Reload the device. + * @nasid: device's nasid + * @part_num: device's part number + * @mfg_num: device's manufacturer number + * + * Remove the device associated with 'nasid' from device list and then + * call device-register with the given part/mfg numbers. + */ +static int cx_device_reload(struct cx_dev *cx_dev) +{ + device_remove_file(&cx_dev->dev, &dev_attr_cxdev_control); + cx_device_unregister(cx_dev); + return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num, + cx_dev->cx_id.mfg_num, cx_dev->hubdev); +} + +static inline uint64_t tiocx_intr_alloc(nasid_t nasid, int widget, + u64 sn_irq_info, + int req_irq, nasid_t req_nasid, + int req_slice) +{ + struct ia64_sal_retval rv; + rv.status = 0; + rv.v0 = 0; + + ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT, + SAL_INTR_ALLOC, nasid, + widget, sn_irq_info, req_irq, + req_nasid, req_slice); + return rv.status; +} + +static inline void tiocx_intr_free(nasid_t nasid, int widget, + struct sn_irq_info *sn_irq_info) +{ + struct ia64_sal_retval rv; + rv.status = 0; + rv.v0 = 0; + + ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT, + SAL_INTR_FREE, nasid, + widget, sn_irq_info->irq_irq, + sn_irq_info->irq_cookie, 0, 0); +} + +struct sn_irq_info *tiocx_irq_alloc(nasid_t nasid, int widget, int irq, + nasid_t req_nasid, int slice) +{ + struct sn_irq_info *sn_irq_info; + int status; + int sn_irq_size = sizeof(struct sn_irq_info); + + if ((nasid & 1) == 0) + return NULL; + + sn_irq_info = kmalloc(sn_irq_size, GFP_KERNEL); + if (sn_irq_info == NULL) + return NULL; + + memset(sn_irq_info, 0x0, sn_irq_size); + + status = tiocx_intr_alloc(nasid, widget, __pa(sn_irq_info), irq, + req_nasid, slice); + if (status) { + kfree(sn_irq_info); + return NULL; + } else { + return sn_irq_info; + } +} + +void tiocx_irq_free(struct sn_irq_info *sn_irq_info) +{ + uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge; + nasid_t nasid = NASID_GET(bridge); + int widget; + + if (nasid & 1) { + widget = TIO_SWIN_WIDGETNUM(bridge); + tiocx_intr_free(nasid, widget, sn_irq_info); + kfree(sn_irq_info); + } +} + +uint64_t +tiocx_dma_addr(uint64_t addr) +{ + return PHYS_TO_TIODMA(addr); +} + +uint64_t +tiocx_swin_base(int nasid) +{ + return TIO_SWIN_BASE(nasid, TIOCX_CORELET); +} + +EXPORT_SYMBOL(cx_driver_register); +EXPORT_SYMBOL(cx_driver_unregister); +EXPORT_SYMBOL(cx_device_register); +EXPORT_SYMBOL(cx_device_unregister); +EXPORT_SYMBOL(tiocx_irq_alloc); +EXPORT_SYMBOL(tiocx_irq_free); +EXPORT_SYMBOL(tiocx_bus_type); +EXPORT_SYMBOL(tiocx_dma_addr); +EXPORT_SYMBOL(tiocx_swin_base); + +static uint64_t tiocx_get_hubdev_info(u64 handle, u64 address) +{ + + struct ia64_sal_retval ret_stuff; + ret_stuff.status = 0; + ret_stuff.v0 = 0; + + ia64_sal_oemcall_nolock(&ret_stuff, + SN_SAL_IOIF_GET_HUBDEV_INFO, + handle, address, 0, 0, 0, 0, 0); + return ret_stuff.v0; +} + +static void tio_conveyor_set(nasid_t nasid, int enable_flag) +{ + uint64_t ice_frz; + uint64_t disable_cb = (1ull << 61); + + if (!(nasid & 1)) + return; + + ice_frz = REMOTE_HUB_L(nasid, TIO_ICE_FRZ_CFG); + if (enable_flag) { + if (!(ice_frz & disable_cb)) /* already enabled */ + return; + ice_frz &= ~disable_cb; + } else { + if (ice_frz & disable_cb) /* already disabled */ + return; + ice_frz |= disable_cb; + } + DBG(KERN_ALERT "TIO_ICE_FRZ_CFG= 0x%lx\n", ice_frz); + REMOTE_HUB_S(nasid, TIO_ICE_FRZ_CFG, ice_frz); +} + +#define tio_conveyor_enable(nasid) tio_conveyor_set(nasid, 1) +#define tio_conveyor_disable(nasid) tio_conveyor_set(nasid, 0) + +static void tio_corelet_reset(nasid_t nasid, int corelet) +{ + if (!(nasid & 1)) + return; + + REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 1 << corelet); + udelay(2000); + REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 0); + udelay(2000); +} + +static int fpga_attached(nasid_t nasid) +{ + uint64_t cx_credits; + + cx_credits = REMOTE_HUB_L(nasid, TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3); + cx_credits &= TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK; + DBG("cx_credits= 0x%lx\n", cx_credits); + + return (cx_credits == 0xf) ? 1 : 0; +} + +static int tiocx_reload(struct cx_dev *cx_dev) +{ + int part_num = CX_DEV_NONE; + int mfg_num = CX_DEV_NONE; + nasid_t nasid = cx_dev->cx_id.nasid; + + if (fpga_attached(nasid)) { + uint64_t cx_id; + + cx_id = + *(volatile int32_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) + + WIDGET_ID); + part_num = XWIDGET_PART_NUM(cx_id); + mfg_num = XWIDGET_MFG_NUM(cx_id); + DBG("part= 0x%x, mfg= 0x%x\n", part_num, mfg_num); + /* just ignore it if it's a CE */ + if (part_num == TIO_CE_ASIC_PARTNUM) + return 0; + } + + cx_dev->cx_id.part_num = part_num; + cx_dev->cx_id.mfg_num = mfg_num; + + /* + * Delete old device and register the new one. It's ok if + * part_num/mfg_num == CX_DEV_NONE. We want to register + * devices in the table even if a bitstream isn't loaded. + * That allows use to see that a bitstream isn't loaded via + * TIOCX_IOCTL_DEV_LIST. + */ + return cx_device_reload(cx_dev); +} + +static ssize_t show_cxdev_control(struct device *dev, char *buf) +{ + struct cx_dev *cx_dev = to_cx_dev(dev); + + return sprintf(buf, "0x%x 0x%x 0x%x\n", + cx_dev->cx_id.nasid, + cx_dev->cx_id.part_num, cx_dev->cx_id.mfg_num); +} + +static ssize_t store_cxdev_control(struct device *dev, const char *buf, + size_t count) +{ + int n; + struct cx_dev *cx_dev = to_cx_dev(dev); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (count <= 0) + return 0; + + n = simple_strtoul(buf, NULL, 0); + + switch (n) { + case 1: + tiocx_reload(cx_dev); + break; + case 3: + tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET); + break; + default: + break; + } + + return count; +} + +DEVICE_ATTR(cxdev_control, 0644, show_cxdev_control, store_cxdev_control); + +static int __init tiocx_init(void) +{ + cnodeid_t cnodeid; + int found_tiocx_device = 0; + + bus_register(&tiocx_bus_type); + + for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) { + nasid_t nasid; + + if ((nasid = cnodeid_to_nasid(cnodeid)) < 0) + break; /* No more nasids .. bail out of loop */ + + if (nasid & 0x1) { /* TIO's are always odd */ + struct hubdev_info *hubdev; + uint64_t status; + struct xwidget_info *widgetp; + + DBG("Found TIO at nasid 0x%x\n", nasid); + + hubdev = + (struct hubdev_info *)(NODEPDA(cnodeid)->pdinfo); + status = + tiocx_get_hubdev_info(nasid, + (uint64_t) __pa(hubdev)); + if (status) + continue; + + widgetp = &hubdev->hdi_xwidget_info[TIOCX_CORELET]; + + /* The CE hangs off of the CX port but is not an FPGA */ + if (widgetp->xwi_hwid.part_num == TIO_CE_ASIC_PARTNUM) + continue; + + tio_corelet_reset(nasid, TIOCX_CORELET); + tio_conveyor_enable(nasid); + + if (cx_device_register + (nasid, widgetp->xwi_hwid.part_num, + widgetp->xwi_hwid.mfg_num, hubdev) < 0) + return -ENXIO; + else + found_tiocx_device++; + } + } + + /* It's ok if we find zero devices. */ + DBG("found_tiocx_device= %d\n", found_tiocx_device); + + return 0; +} + +static void __exit tiocx_exit(void) +{ + struct device *dev; + struct device *tdev; + + DBG("tiocx_exit\n"); + + /* + * Unregister devices. + */ + list_for_each_entry_safe(dev, tdev, &tiocx_bus_type.devices.list, + bus_list) { + if (dev) { + struct cx_dev *cx_dev = to_cx_dev(dev); + device_remove_file(dev, &dev_attr_cxdev_control); + cx_device_unregister(cx_dev); + } + } + + bus_unregister(&tiocx_bus_type); +} + +module_init(tiocx_init); +module_exit(tiocx_exit); + +/************************************************************************ + * Module licensing and description + ************************************************************************/ +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Bruce Losure "); +MODULE_DESCRIPTION("TIOCX module"); +MODULE_SUPPORTED_DEVICE(DEVICE_NAME); -- cgit v0.10.2 From fde740e4dd4a05ca8957490d468fa9b2770f5bd6 Mon Sep 17 00:00:00 2001 From: Robin Holt Date: Mon, 25 Apr 2005 13:13:16 -0700 Subject: [IA64] Percpu quicklist for combined allocator for pgd/pmd/pte. This patch introduces using the quicklists for pgd, pmd, and pte levels by combining the alloc and free functions into a common set of routines. This greatly simplifies the reading of this header file. This patch is simple but necessary for large numa configurations. It simply ensures that only pages from the local node are added to a cpus quicklist. This prevents the trapping of pages on a remote nodes quicklist by starting a process, touching a large number of pages to fill pmd and pte entries, migrating to another node, and then unmapping or exiting. With those conditions, the pages get trapped and if the machine has more than 100 nodes of the same size, the calculation of the pgtable high water mark will be larger than any single node so page table cache flushing will never occur. I ran lmbench lat_proc fork and lat_proc exec on a zx1 with and without this patch and did not notice any change. On an sn2 machine, there was a slight improvement which is possibly due to pages from other nodes trapped on the test node before starting the run. I did not investigate further. This patch shrinks the quicklist based upon free memory on the node instead of the high/low water marks. I have written it to enable preemption periodically and recalculate the amount to shrink every time we have freed enough pages that the quicklist size should have grown. I rescan the nodes zones each pass because other processess may be draining node memory at the same time as we are adding. Signed-off-by: Robin Holt Signed-off-by: Tony Luck diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index 6daf15a..91a055f 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c @@ -61,7 +61,8 @@ show_mem (void) printk("%d reserved pages\n", reserved); printk("%d pages shared\n", shared); printk("%d pages swap cached\n", cached); - printk("%ld pages in page table cache\n", pgtable_cache_size); + printk("%ld pages in page table cache\n", + pgtable_quicklist_total_size()); } /* physical address where the bootmem map is located */ diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index 3456a9b..c007109 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -582,7 +582,8 @@ void show_mem(void) printk("%d reserved pages\n", total_reserved); printk("%d pages shared\n", total_shared); printk("%d pages swap cached\n", total_cached); - printk("Total of %ld pages in page table cache\n", pgtable_cache_size); + printk("Total of %ld pages in page table cache\n", + pgtable_quicklist_total_size()); printk("%d free buffer pages\n", nr_free_buffer_pages()); } diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 65cf839..4892be5 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -39,6 +39,9 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); +DEFINE_PER_CPU(unsigned long *, __pgtable_quicklist); +DEFINE_PER_CPU(long, __pgtable_quicklist_size); + extern void ia64_tlb_init (void); unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; @@ -50,27 +53,53 @@ struct page *vmem_map; EXPORT_SYMBOL(vmem_map); #endif -static int pgt_cache_water[2] = { 25, 50 }; - -struct page *zero_page_memmap_ptr; /* map entry for zero page */ +struct page *zero_page_memmap_ptr; /* map entry for zero page */ EXPORT_SYMBOL(zero_page_memmap_ptr); +#define MIN_PGT_PAGES 25UL +#define MAX_PGT_FREES_PER_PASS 16 +#define PGT_FRACTION_OF_NODE_MEM 16 + +static inline long +max_pgt_pages(void) +{ + u64 node_free_pages, max_pgt_pages; + +#ifndef CONFIG_NUMA + node_free_pages = nr_free_pages(); +#else + node_free_pages = nr_free_pages_pgdat(NODE_DATA(numa_node_id())); +#endif + max_pgt_pages = node_free_pages / PGT_FRACTION_OF_NODE_MEM; + max_pgt_pages = max(max_pgt_pages, MIN_PGT_PAGES); + return max_pgt_pages; +} + +static inline long +min_pages_to_free(void) +{ + long pages_to_free; + + pages_to_free = pgtable_quicklist_size - max_pgt_pages(); + pages_to_free = min(pages_to_free, MAX_PGT_FREES_PER_PASS); + return pages_to_free; +} + void -check_pgt_cache (void) +check_pgt_cache(void) { - int low, high; + long pages_to_free; - low = pgt_cache_water[0]; - high = pgt_cache_water[1]; + if (unlikely(pgtable_quicklist_size <= MIN_PGT_PAGES)) + return; preempt_disable(); - if (pgtable_cache_size > (u64) high) { - do { - if (pgd_quicklist) - free_page((unsigned long)pgd_alloc_one_fast(NULL)); - if (pmd_quicklist) - free_page((unsigned long)pmd_alloc_one_fast(NULL, 0)); - } while (pgtable_cache_size > (u64) low); + while (unlikely((pages_to_free = min_pages_to_free()) > 0)) { + while (pages_to_free--) { + free_page((unsigned long)pgtable_quicklist_alloc()); + } + preempt_enable(); + preempt_disable(); } preempt_enable(); } @@ -523,11 +552,14 @@ void mem_init (void) { long reserved_pages, codesize, datasize, initsize; - unsigned long num_pgt_pages; pg_data_t *pgdat; int i; static struct kcore_list kcore_mem, kcore_vmem, kcore_kernel; + BUG_ON(PTRS_PER_PGD * sizeof(pgd_t) != PAGE_SIZE); + BUG_ON(PTRS_PER_PMD * sizeof(pmd_t) != PAGE_SIZE); + BUG_ON(PTRS_PER_PTE * sizeof(pte_t) != PAGE_SIZE); + #ifdef CONFIG_PCI /* * This needs to be called _after_ the command line has been parsed but _before_ @@ -564,18 +596,6 @@ mem_init (void) num_physpages << (PAGE_SHIFT - 10), codesize >> 10, reserved_pages << (PAGE_SHIFT - 10), datasize >> 10, initsize >> 10); - /* - * Allow for enough (cached) page table pages so that we can map the entire memory - * at least once. Each task also needs a couple of page tables pages, so add in a - * fudge factor for that (don't use "threads-max" here; that would be wrong!). - * Don't allow the cache to be more than 10% of total memory, though. - */ -# define NUM_TASKS 500 /* typical number of tasks */ - num_pgt_pages = nr_free_pages() / PTRS_PER_PGD + NUM_TASKS; - if (num_pgt_pages > nr_free_pages() / 10) - num_pgt_pages = nr_free_pages() / 10; - if (num_pgt_pages > (u64) pgt_cache_water[1]) - pgt_cache_water[1] = num_pgt_pages; /* * For fsyscall entrpoints with no light-weight handler, use the ordinary diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h index 0f05dc8..e86a8c3 100644 --- a/include/asm-ia64/pgalloc.h +++ b/include/asm-ia64/pgalloc.h @@ -22,146 +22,124 @@ #include -/* - * Very stupidly, we used to get new pgd's and pmd's, init their contents - * to point to the NULL versions of the next level page table, later on - * completely re-init them the same way, then free them up. This wasted - * a lot of work and caused unnecessary memory traffic. How broken... - * We fix this by caching them. - */ -#define pgd_quicklist (local_cpu_data->pgd_quick) -#define pmd_quicklist (local_cpu_data->pmd_quick) -#define pgtable_cache_size (local_cpu_data->pgtable_cache_sz) +DECLARE_PER_CPU(unsigned long *, __pgtable_quicklist); +#define pgtable_quicklist __ia64_per_cpu_var(__pgtable_quicklist) +DECLARE_PER_CPU(long, __pgtable_quicklist_size); +#define pgtable_quicklist_size __ia64_per_cpu_var(__pgtable_quicklist_size) -static inline pgd_t* -pgd_alloc_one_fast (struct mm_struct *mm) +static inline long pgtable_quicklist_total_size(void) +{ + long ql_size; + int cpuid; + + for_each_online_cpu(cpuid) { + ql_size += per_cpu(__pgtable_quicklist_size, cpuid); + } + return ql_size; +} + +static inline void *pgtable_quicklist_alloc(void) { unsigned long *ret = NULL; preempt_disable(); - ret = pgd_quicklist; + ret = pgtable_quicklist; if (likely(ret != NULL)) { - pgd_quicklist = (unsigned long *)(*ret); + pgtable_quicklist = (unsigned long *)(*ret); ret[0] = 0; - --pgtable_cache_size; - } else - ret = NULL; + --pgtable_quicklist_size; + } else { + ret = (unsigned long *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + } preempt_enable(); - return (pgd_t *) ret; + return ret; } -static inline pgd_t* -pgd_alloc (struct mm_struct *mm) +static inline void pgtable_quicklist_free(void *pgtable_entry) { - /* the VM system never calls pgd_alloc_one_fast(), so we do it here. */ - pgd_t *pgd = pgd_alloc_one_fast(mm); +#ifdef CONFIG_NUMA + unsigned long nid = page_to_nid(virt_to_page(pgtable_entry)); - if (unlikely(pgd == NULL)) { - pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_ZERO); + if (unlikely(nid != numa_node_id())) { + free_page((unsigned long)pgtable_entry); + return; } - return pgd; -} +#endif -static inline void -pgd_free (pgd_t *pgd) -{ preempt_disable(); - *(unsigned long *)pgd = (unsigned long) pgd_quicklist; - pgd_quicklist = (unsigned long *) pgd; - ++pgtable_cache_size; + *(unsigned long *)pgtable_entry = (unsigned long)pgtable_quicklist; + pgtable_quicklist = (unsigned long *)pgtable_entry; + ++pgtable_quicklist_size; preempt_enable(); } -static inline void -pud_populate (struct mm_struct *mm, pud_t *pud_entry, pmd_t *pmd) +static inline pgd_t *pgd_alloc(struct mm_struct *mm) { - pud_val(*pud_entry) = __pa(pmd); + return pgtable_quicklist_alloc(); } -static inline pmd_t* -pmd_alloc_one_fast (struct mm_struct *mm, unsigned long addr) +static inline void pgd_free(pgd_t * pgd) { - unsigned long *ret = NULL; - - preempt_disable(); - - ret = (unsigned long *)pmd_quicklist; - if (likely(ret != NULL)) { - pmd_quicklist = (unsigned long *)(*ret); - ret[0] = 0; - --pgtable_cache_size; - } - - preempt_enable(); - - return (pmd_t *)ret; + pgtable_quicklist_free(pgd); } -static inline pmd_t* -pmd_alloc_one (struct mm_struct *mm, unsigned long addr) +static inline void +pud_populate(struct mm_struct *mm, pud_t * pud_entry, pmd_t * pmd) { - pmd_t *pmd = (pmd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); + pud_val(*pud_entry) = __pa(pmd); +} - return pmd; +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) +{ + return pgtable_quicklist_alloc(); } -static inline void -pmd_free (pmd_t *pmd) +static inline void pmd_free(pmd_t * pmd) { - preempt_disable(); - *(unsigned long *)pmd = (unsigned long) pmd_quicklist; - pmd_quicklist = (unsigned long *) pmd; - ++pgtable_cache_size; - preempt_enable(); + pgtable_quicklist_free(pmd); } #define __pmd_free_tlb(tlb, pmd) pmd_free(pmd) static inline void -pmd_populate (struct mm_struct *mm, pmd_t *pmd_entry, struct page *pte) +pmd_populate(struct mm_struct *mm, pmd_t * pmd_entry, struct page *pte) { pmd_val(*pmd_entry) = page_to_phys(pte); } static inline void -pmd_populate_kernel (struct mm_struct *mm, pmd_t *pmd_entry, pte_t *pte) +pmd_populate_kernel(struct mm_struct *mm, pmd_t * pmd_entry, pte_t * pte) { pmd_val(*pmd_entry) = __pa(pte); } -static inline struct page * -pte_alloc_one (struct mm_struct *mm, unsigned long addr) +static inline struct page *pte_alloc_one(struct mm_struct *mm, + unsigned long addr) { - struct page *pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); - - return pte; + return virt_to_page(pgtable_quicklist_alloc()); } -static inline pte_t * -pte_alloc_one_kernel (struct mm_struct *mm, unsigned long addr) +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long addr) { - pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); - - return pte; + return pgtable_quicklist_alloc(); } -static inline void -pte_free (struct page *pte) +static inline void pte_free(struct page *pte) { - __free_page(pte); + pgtable_quicklist_free(page_address(pte)); } -static inline void -pte_free_kernel (pte_t *pte) +static inline void pte_free_kernel(pte_t * pte) { - free_page((unsigned long) pte); + pgtable_quicklist_free(pte); } -#define __pte_free_tlb(tlb, pte) tlb_remove_page((tlb), (pte)) +#define __pte_free_tlb(tlb, pte) pte_free(pte) -extern void check_pgt_cache (void); +extern void check_pgt_cache(void); -#endif /* _ASM_IA64_PGALLOC_H */ +#endif /* _ASM_IA64_PGALLOC_H */ diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h index 2807f8d..983798e 100644 --- a/include/asm-ia64/processor.h +++ b/include/asm-ia64/processor.h @@ -137,9 +137,6 @@ struct cpuinfo_ia64 { __u64 nsec_per_cyc; /* (1000000000< Date: Mon, 25 Apr 2005 13:14:36 -0700 Subject: [IA64] sba_iommu bug fixes This fixes a couple of bugs in the zx1/sx1000 sba_iommu. These are all pretty low likelihood of hitting. The first problem is a simple off by one, deep in the sba_alloc_range() error path. Surrounding that was a lock ordering problem that could have potentially deadlocked with the order the locks are grabbed in sba_unmap_single(). I moved the resource locking into sba_search_bitmap() to prevent this. Finally, there's a potential race between unmapping pdir entries and marking incoming DMA pages clean. If you see any oddities, please let me know, but I've tested it pretty thoroughly here. Tony, please apply. Thanks, BTW, many of the options in this driver not on by default are becoming more and more broken. I'll be working on some patches to clean them out, but I wanted to get this bug fix out first. Signed-off-by: Alex Williamson Signed-off-by: Tony Luck diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 017c9ab..6a8fcba 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -1,9 +1,9 @@ /* ** IA64 System Bus Adapter (SBA) I/O MMU manager ** -** (c) Copyright 2002-2004 Alex Williamson +** (c) Copyright 2002-2005 Alex Williamson ** (c) Copyright 2002-2003 Grant Grundler -** (c) Copyright 2002-2004 Hewlett-Packard Company +** (c) Copyright 2002-2005 Hewlett-Packard Company ** ** Portions (c) 2000 Grant Grundler (from parisc I/O MMU code) ** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code) @@ -459,21 +459,32 @@ get_iovp_order (unsigned long size) * sba_search_bitmap - find free space in IO PDIR resource bitmap * @ioc: IO MMU structure which owns the pdir we are interested in. * @bits_wanted: number of entries we need. + * @use_hint: use res_hint to indicate where to start looking * * Find consecutive free bits in resource bitmap. * Each bit represents one entry in the IO Pdir. * Cool perf optimization: search for log2(size) bits at a time. */ static SBA_INLINE unsigned long -sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) +sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted, int use_hint) { - unsigned long *res_ptr = ioc->res_hint; + unsigned long *res_ptr; unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); - unsigned long pide = ~0UL; + unsigned long flags, pide = ~0UL; ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0); ASSERT(res_ptr < res_end); + spin_lock_irqsave(&ioc->res_lock, flags); + + /* Allow caller to force a search through the entire resource space */ + if (likely(use_hint)) { + res_ptr = ioc->res_hint; + } else { + res_ptr = (ulong *)ioc->res_map; + ioc->res_bitshift = 0; + } + /* * N.B. REO/Grande defect AR2305 can cause TLB fetch timeouts * if a TLB entry is purged while in use. sba_mark_invalid() @@ -570,10 +581,12 @@ not_found: prefetch(ioc->res_map); ioc->res_hint = (unsigned long *) ioc->res_map; ioc->res_bitshift = 0; + spin_unlock_irqrestore(&ioc->res_lock, flags); return (pide); found_it: ioc->res_hint = res_ptr; + spin_unlock_irqrestore(&ioc->res_lock, flags); return (pide); } @@ -594,36 +607,36 @@ sba_alloc_range(struct ioc *ioc, size_t size) unsigned long itc_start; #endif unsigned long pide; - unsigned long flags; ASSERT(pages_needed); ASSERT(0 == (size & ~iovp_mask)); - spin_lock_irqsave(&ioc->res_lock, flags); - #ifdef PDIR_SEARCH_TIMING itc_start = ia64_get_itc(); #endif /* ** "seek and ye shall find"...praying never hurts either... */ - pide = sba_search_bitmap(ioc, pages_needed); + pide = sba_search_bitmap(ioc, pages_needed, 1); if (unlikely(pide >= (ioc->res_size << 3))) { - pide = sba_search_bitmap(ioc, pages_needed); + pide = sba_search_bitmap(ioc, pages_needed, 0); if (unlikely(pide >= (ioc->res_size << 3))) { #if DELAYED_RESOURCE_CNT > 0 + unsigned long flags; + /* ** With delayed resource freeing, we can give this one more shot. We're ** getting close to being in trouble here, so do what we can to make this ** one count. */ - spin_lock(&ioc->saved_lock); + spin_lock_irqsave(&ioc->saved_lock, flags); if (ioc->saved_cnt > 0) { struct sba_dma_pair *d; int cnt = ioc->saved_cnt; - d = &(ioc->saved[ioc->saved_cnt]); + d = &(ioc->saved[ioc->saved_cnt - 1]); + spin_lock(&ioc->res_lock); while (cnt--) { sba_mark_invalid(ioc, d->iova, d->size); sba_free_range(ioc, d->iova, d->size); @@ -631,10 +644,11 @@ sba_alloc_range(struct ioc *ioc, size_t size) } ioc->saved_cnt = 0; READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ + spin_unlock(&ioc->res_lock); } - spin_unlock(&ioc->saved_lock); + spin_unlock_irqrestore(&ioc->saved_lock, flags); - pide = sba_search_bitmap(ioc, pages_needed); + pide = sba_search_bitmap(ioc, pages_needed, 0); if (unlikely(pide >= (ioc->res_size << 3))) panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n", ioc->ioc_hpa); @@ -664,8 +678,6 @@ sba_alloc_range(struct ioc *ioc, size_t size) (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map), ioc->res_bitshift ); - spin_unlock_irqrestore(&ioc->res_lock, flags); - return (pide); } @@ -950,6 +962,30 @@ sba_map_single(struct device *dev, void *addr, size_t size, int dir) return SBA_IOVA(ioc, iovp, offset); } +#ifdef ENABLE_MARK_CLEAN +static SBA_INLINE void +sba_mark_clean(struct ioc *ioc, dma_addr_t iova, size_t size) +{ + u32 iovp = (u32) SBA_IOVP(ioc,iova); + int off = PDIR_INDEX(iovp); + void *addr; + + if (size <= iovp_size) { + addr = phys_to_virt(ioc->pdir_base[off] & + ~0xE000000000000FFFULL); + mark_clean(addr, size); + } else { + do { + addr = phys_to_virt(ioc->pdir_base[off] & + ~0xE000000000000FFFULL); + mark_clean(addr, min(size, iovp_size)); + off++; + size -= iovp_size; + } while (size > 0); + } +} +#endif + /** * sba_unmap_single - unmap one IOVA and free resources * @dev: instance of PCI owned by the driver that's asking. @@ -995,6 +1031,10 @@ void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) size += offset; size = ROUNDUP(size, iovp_size); +#ifdef ENABLE_MARK_CLEAN + if (dir == DMA_FROM_DEVICE) + sba_mark_clean(ioc, iova, size); +#endif #if DELAYED_RESOURCE_CNT > 0 spin_lock_irqsave(&ioc->saved_lock, flags); @@ -1021,30 +1061,6 @@ void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ spin_unlock_irqrestore(&ioc->res_lock, flags); #endif /* DELAYED_RESOURCE_CNT == 0 */ -#ifdef ENABLE_MARK_CLEAN - if (dir == DMA_FROM_DEVICE) { - u32 iovp = (u32) SBA_IOVP(ioc,iova); - int off = PDIR_INDEX(iovp); - void *addr; - - if (size <= iovp_size) { - addr = phys_to_virt(ioc->pdir_base[off] & - ~0xE000000000000FFFULL); - mark_clean(addr, size); - } else { - size_t byte_cnt = size; - - do { - addr = phys_to_virt(ioc->pdir_base[off] & - ~0xE000000000000FFFULL); - mark_clean(addr, min(byte_cnt, iovp_size)); - off++; - byte_cnt -= iovp_size; - - } while (byte_cnt > 0); - } - } -#endif } -- cgit v0.10.2 From c411cb56586915350e4cdb6f228e9da2adba3285 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Mon, 25 Apr 2005 13:16:16 -0700 Subject: [IA64] fix: warning: `ql_size' might be used uninitialized Oops. Should have caught this before I checked it in. Signed-off-by: Tony Luck diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h index e86a8c3..2b71273 100644 --- a/include/asm-ia64/pgalloc.h +++ b/include/asm-ia64/pgalloc.h @@ -29,7 +29,7 @@ DECLARE_PER_CPU(long, __pgtable_quicklist_size); static inline long pgtable_quicklist_total_size(void) { - long ql_size; + long ql_size = 0; int cpuid; for_each_online_cpu(cpuid) { -- cgit v0.10.2 From e96c9b4779e651a7469bea677be3a08f70be399e Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Mon, 25 Apr 2005 13:16:59 -0700 Subject: [IA64] MAX_PGT_FREES_PER_PASS must be 'L' to avoid warning 'min' is very picky about types of arguments, make it happy Signed-off-by: Tony Luck diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 4892be5..547785e 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -57,7 +57,7 @@ struct page *zero_page_memmap_ptr; /* map entry for zero page */ EXPORT_SYMBOL(zero_page_memmap_ptr); #define MIN_PGT_PAGES 25UL -#define MAX_PGT_FREES_PER_PASS 16 +#define MAX_PGT_FREES_PER_PASS 16L #define PGT_FRACTION_OF_NODE_MEM 16 static inline long -- cgit v0.10.2 From 4628d7cada7a19166ba8fe57f5ef0f0009694e1e Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Mon, 25 Apr 2005 13:18:02 -0700 Subject: [IA64-SGI] disable TIOCA GART TLB prefetching Patch to disable SGI TIOCA GART TLB prefetching due to hw bug. Signed-off-by: Mark Maule Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c index 2234d61..54a0dd4 100644 --- a/arch/ia64/sn/pci/tioca_provider.c +++ b/arch/ia64/sn/pci/tioca_provider.c @@ -171,15 +171,15 @@ tioca_gart_init(struct tioca_kernel *tioca_kern) * use agp op-combining * use GET semantics to fetch memory * participate in coherency domain - * prefetch TLB entries + * DISABLE GART PREFETCHING due to hw bug tracked in SGI PV930029 */ ca_base->ca_control1 |= CA_AGPDMA_OP_ENB_COMBDELAY; /* PV895469 ? */ ca_base->ca_control2 &= ~(CA_GART_MEM_PARAM); ca_base->ca_control2 |= (0x2ull << CA_GART_MEM_PARAM_SHFT); tioca_kern->ca_gart_iscoherent = 1; - ca_base->ca_control2 |= - (CA_GART_WR_PREFETCH_ENB | CA_GART_RD_PREFETCH_ENB); + ca_base->ca_control2 &= + ~(CA_GART_WR_PREFETCH_ENB | CA_GART_RD_PREFETCH_ENB); /* * Unmask GART fetch error interrupts. Clear residual errors first. -- cgit v0.10.2 From 95ff439a517835aa2bdf725fafbb025a63984289 Mon Sep 17 00:00:00 2001 From: Russ Anderson Date: Mon, 25 Apr 2005 13:19:11 -0700 Subject: [IA64-SGI] Add new MMR definitions/Modify BTE initialiation©. patch 1: Add new MMR definitions. Modify BTE initialiation. Modify BTE copy. Signed-off-by: Russ Anderson Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index ce0bc40..647deae 100644 --- a/arch/ia64/sn/kernel/bte.c +++ b/arch/ia64/sn/kernel/bte.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. */ #include @@ -170,10 +170,6 @@ retry_bteop: /* Initialize the notification to a known value. */ *bte->most_rcnt_na = BTE_WORD_BUSY; - /* Set the status reg busy bit and transfer length */ - BTE_PRINTKV(("IBLS = 0x%lx\n", IBLS_BUSY | transfer_size)); - BTE_LNSTAT_STORE(bte, IBLS_BUSY | transfer_size); - /* Set the source and destination registers */ BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src)))); BTE_SRC_STORE(bte, TO_PHYS(src)); @@ -188,7 +184,7 @@ retry_bteop: /* Initiate the transfer */ BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode))); - BTE_CTRL_STORE(bte, BTE_VALID_MODE(mode)); + BTE_START_TRANSFER(bte, transfer_size, BTE_VALID_MODE(mode)); itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec); @@ -429,10 +425,16 @@ void bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) mynodepda->bte_recovery_timer.data = (unsigned long)mynodepda; for (i = 0; i < BTES_PER_NODE; i++) { + u64 *base_addr; + /* Which link status register should we use? */ - unsigned long link_status = (i == 0 ? IIO_IBLS0 : IIO_IBLS1); - mynodepda->bte_if[i].bte_base_addr = (u64 *) - REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), link_status); + base_addr = (u64 *) + REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), BTE_BASE_ADDR(i)); + mynodepda->bte_if[i].bte_base_addr = base_addr; + mynodepda->bte_if[i].bte_source_addr = BTE_SOURCE_ADDR(base_addr); + mynodepda->bte_if[i].bte_destination_addr = BTE_DEST_ADDR(base_addr); + mynodepda->bte_if[i].bte_control_addr = BTE_CTRL_ADDR(base_addr); + mynodepda->bte_if[i].bte_notify_addr = BTE_NOTIF_ADDR(base_addr); /* * Initialize the notification and spinlock diff --git a/include/asm-ia64/sn/bte.h b/include/asm-ia64/sn/bte.h index 0ec27f9..f50da3d 100644 --- a/include/asm-ia64/sn/bte.h +++ b/include/asm-ia64/sn/bte.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. */ @@ -13,8 +13,12 @@ #include #include #include +#include #include +#include +#define IBCT_NOTIFY (0x1UL << 4) +#define IBCT_ZFIL_MODE (0x1UL << 0) /* #define BTE_DEBUG */ /* #define BTE_DEBUG_VERBOSE */ @@ -39,8 +43,36 @@ /* Define hardware */ -#define BTES_PER_NODE 2 +#define BTES_PER_NODE (is_shub2() ? 4 : 2) +#define MAX_BTES_PER_NODE 4 +#define BTE2OFF_CTRL (0) +#define BTE2OFF_SRC (SH2_BT_ENG_SRC_ADDR_0 - SH2_BT_ENG_CSR_0) +#define BTE2OFF_DEST (SH2_BT_ENG_DEST_ADDR_0 - SH2_BT_ENG_CSR_0) +#define BTE2OFF_NOTIFY (SH2_BT_ENG_NOTIF_ADDR_0 - SH2_BT_ENG_CSR_0) + +#define BTE_BASE_ADDR(interface) \ + (is_shub2() ? (interface == 0) ? SH2_BT_ENG_CSR_0 : \ + (interface == 1) ? SH2_BT_ENG_CSR_1 : \ + (interface == 2) ? SH2_BT_ENG_CSR_2 : \ + SH2_BT_ENG_CSR_3 \ + : (interface == 0) ? IIO_IBLS0 : IIO_IBLS1) + +#define BTE_SOURCE_ADDR(base) \ + (is_shub2() ? base + (BTE2OFF_SRC/8) \ + : base + (BTEOFF_SRC/8)) + +#define BTE_DEST_ADDR(base) \ + (is_shub2() ? base + (BTE2OFF_DEST/8) \ + : base + (BTEOFF_DEST/8)) + +#define BTE_CTRL_ADDR(base) \ + (is_shub2() ? base + (BTE2OFF_CTRL/8) \ + : base + (BTEOFF_CTRL/8)) + +#define BTE_NOTIF_ADDR(base) \ + (is_shub2() ? base + (BTE2OFF_NOTIFY/8) \ + : base + (BTEOFF_NOTIFY/8)) /* Define hardware modes */ #define BTE_NOTIFY (IBCT_NOTIFY) @@ -68,14 +100,18 @@ #define BTE_LNSTAT_STORE(_bte, _x) \ HUB_S(_bte->bte_base_addr, (_x)) #define BTE_SRC_STORE(_bte, _x) \ - HUB_S(_bte->bte_base_addr + (BTEOFF_SRC/8), (_x)) + HUB_S(_bte->bte_source_addr, (_x)) #define BTE_DEST_STORE(_bte, _x) \ - HUB_S(_bte->bte_base_addr + (BTEOFF_DEST/8), (_x)) + HUB_S(_bte->bte_destination_addr, (_x)) #define BTE_CTRL_STORE(_bte, _x) \ - HUB_S(_bte->bte_base_addr + (BTEOFF_CTRL/8), (_x)) + HUB_S(_bte->bte_control_addr, (_x)) #define BTE_NOTIF_STORE(_bte, _x) \ - HUB_S(_bte->bte_base_addr + (BTEOFF_NOTIFY/8), (_x)) + HUB_S(_bte->bte_notify_addr, (_x)) +#define BTE_START_TRANSFER(_bte, _len, _mode) \ + is_shub2() ? BTE_CTRL_STORE(_bte, IBLS_BUSY | (_mode << 24) | _len) \ + : BTE_LNSTAT_STORE(_bte, _len); \ + BTE_CTRL_STORE(_bte, _mode) /* Possible results from bte_copy and bte_unaligned_copy */ /* The following error codes map into the BTE hardware codes @@ -110,6 +146,10 @@ typedef enum { struct bteinfo_s { volatile u64 notify ____cacheline_aligned; u64 *bte_base_addr ____cacheline_aligned; + u64 *bte_source_addr; + u64 *bte_destination_addr; + u64 *bte_control_addr; + u64 *bte_notify_addr; spinlock_t spinlock; cnodeid_t bte_cnode; /* cnode */ int bte_error_count; /* Number of errors encountered */ @@ -117,6 +157,7 @@ struct bteinfo_s { int cleanup_active; /* Interface is locked for cleanup */ volatile bte_result_t bh_error; /* error while processing */ volatile u64 *most_rcnt_na; + struct bteinfo_s *btes_to_try[MAX_BTES_PER_NODE]; }; diff --git a/include/asm-ia64/sn/nodepda.h b/include/asm-ia64/sn/nodepda.h index 2fbde33..13cc100 100644 --- a/include/asm-ia64/sn/nodepda.h +++ b/include/asm-ia64/sn/nodepda.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_NODEPDA_H #define _ASM_IA64_SN_NODEPDA_H @@ -43,7 +43,7 @@ struct nodepda_s { /* * The BTEs on this node are shared by the local cpus */ - struct bteinfo_s bte_if[BTES_PER_NODE]; /* Virtual Interface */ + struct bteinfo_s bte_if[MAX_BTES_PER_NODE]; /* Virtual Interface */ struct timer_list bte_recovery_timer; spinlock_t bte_recovery_lock; diff --git a/include/asm-ia64/sn/pda.h b/include/asm-ia64/sn/pda.h index e940d36..cd19f17 100644 --- a/include/asm-ia64/sn/pda.h +++ b/include/asm-ia64/sn/pda.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PDA_H #define _ASM_IA64_SN_PDA_H @@ -11,7 +11,6 @@ #include #include #include -#include /* diff --git a/include/asm-ia64/sn/shub_mmr.h b/include/asm-ia64/sn/shub_mmr.h index 6ec37e8..2f88508 100644 --- a/include/asm-ia64/sn/shub_mmr.h +++ b/include/asm-ia64/sn/shub_mmr.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2004 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2005 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SHUB_MMR_H @@ -455,4 +455,22 @@ #define SH_INT_CMPC shubmmr(SH, INT_CMPC) #define SH_INT_CMPD shubmmr(SH, INT_CMPD) +/* ========================================================================== */ +/* Register "SH2_BT_ENG_CSR_0" */ +/* Engine 0 Control and Status Register */ +/* ========================================================================== */ + +#define SH2_BT_ENG_CSR_0 0x0000000030040000 +#define SH2_BT_ENG_SRC_ADDR_0 0x0000000030040080 +#define SH2_BT_ENG_DEST_ADDR_0 0x0000000030040100 +#define SH2_BT_ENG_NOTIF_ADDR_0 0x0000000030040180 + +/* ========================================================================== */ +/* BTE interfaces 1-3 */ +/* ========================================================================== */ + +#define SH2_BT_ENG_CSR_1 0x0000000030050000 +#define SH2_BT_ENG_CSR_2 0x0000000030060000 +#define SH2_BT_ENG_CSR_3 0x0000000030070000 + #endif /* _ASM_IA64_SN_SHUB_MMR_H */ -- cgit v0.10.2 From 93a07d0a0e7b013ee73fb39d4edb07b47288912e Mon Sep 17 00:00:00 2001 From: Russ Anderson Date: Mon, 25 Apr 2005 13:19:52 -0700 Subject: [IA64-SGI] Shub2 BTE support - BTE recovery code patch 2: Shub2 BTE recovery code will be implemented in SAL. Define the SAL interface. Modify bte_error to call SAL for shub2. Signed-off-by: Russ Anderson Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/kernel/bte_error.c b/arch/ia64/sn/kernel/bte_error.c index fd10431..fcbc748 100644 --- a/arch/ia64/sn/kernel/bte_error.c +++ b/arch/ia64/sn/kernel/bte_error.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. */ #include @@ -33,48 +33,28 @@ void bte_error_handler(unsigned long); * Wait until all BTE related CRBs are completed * and then reset the interfaces. */ -void bte_error_handler(unsigned long _nodepda) +void shub1_bte_error_handler(unsigned long _nodepda) { struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda; - spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock; struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; nasid_t nasid; int i; int valid_crbs; - unsigned long irq_flags; - volatile u64 *notify; - bte_result_t bh_error; ii_imem_u_t imem; /* II IMEM Register */ ii_icrb0_d_u_t icrbd; /* II CRB Register D */ ii_ibcr_u_t ibcr; ii_icmr_u_t icmr; ii_ieclr_u_t ieclr; - BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda, + BTE_PRINTK(("shub1_bte_error_handler(%p) - %d\n", err_nodepda, smp_processor_id())); - spin_lock_irqsave(recovery_lock, irq_flags); - if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) && (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) { BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda, smp_processor_id())); - spin_unlock_irqrestore(recovery_lock, irq_flags); return; } - /* - * Lock all interfaces on this node to prevent new transfers - * from being queued. - */ - for (i = 0; i < BTES_PER_NODE; i++) { - if (err_nodepda->bte_if[i].cleanup_active) { - continue; - } - spin_lock(&err_nodepda->bte_if[i].spinlock); - BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda, - smp_processor_id(), i)); - err_nodepda->bte_if[i].cleanup_active = 1; - } /* Determine information about our hub */ nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); @@ -101,7 +81,6 @@ void bte_error_handler(unsigned long _nodepda) mod_timer(recovery_timer, HZ * 5); BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, smp_processor_id())); - spin_unlock_irqrestore(recovery_lock, irq_flags); return; } if (icmr.ii_icmr_fld_s.i_crb_vld != 0) { @@ -120,8 +99,6 @@ void bte_error_handler(unsigned long _nodepda) BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n", err_nodepda, smp_processor_id(), i)); - spin_unlock_irqrestore(recovery_lock, - irq_flags); return; } } @@ -146,6 +123,51 @@ void bte_error_handler(unsigned long _nodepda) ibcr.ii_ibcr_fld_s.i_soft_reset = 1; REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); + del_timer(recovery_timer); +} + +/* + * Wait until all BTE related CRBs are completed + * and then reset the interfaces. + */ +void bte_error_handler(unsigned long _nodepda) +{ + struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda; + spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock; + int i; + nasid_t nasid; + unsigned long irq_flags; + volatile u64 *notify; + bte_result_t bh_error; + + BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda, + smp_processor_id())); + + spin_lock_irqsave(recovery_lock, irq_flags); + + /* + * Lock all interfaces on this node to prevent new transfers + * from being queued. + */ + for (i = 0; i < BTES_PER_NODE; i++) { + if (err_nodepda->bte_if[i].cleanup_active) { + continue; + } + spin_lock(&err_nodepda->bte_if[i].spinlock); + BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda, + smp_processor_id(), i)); + err_nodepda->bte_if[i].cleanup_active = 1; + } + + if (is_shub1()) { + shub1_bte_error_handler(_nodepda); + } else { + nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); + + if (ia64_sn_bte_recovery(nasid)) + panic("bte_error_handler(): Fatal BTE Error"); + } + for (i = 0; i < BTES_PER_NODE; i++) { bh_error = err_nodepda->bte_if[i].bh_error; if (bh_error != BTE_SUCCESS) { @@ -165,8 +187,6 @@ void bte_error_handler(unsigned long _nodepda) spin_unlock(&err_nodepda->bte_if[i].spinlock); } - del_timer(recovery_timer); - spin_unlock_irqrestore(recovery_lock, irq_flags); } diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c index 2bdf684..5c39b43 100644 --- a/arch/ia64/sn/kernel/huberror.c +++ b/arch/ia64/sn/kernel/huberror.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000,2002-2004 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000,2002-2005 Silicon Graphics, Inc. All rights reserved. */ #include @@ -38,8 +38,11 @@ static irqreturn_t hub_eint_handler(int irq, void *arg, struct pt_regs *ep) if ((int)ret_stuff.v0) panic("hubii_eint_handler(): Fatal TIO Error"); - if (!(nasid & 1)) /* Not a TIO, handle CRB errors */ - (void)hubiio_crb_error_handler(hubdev_info); + if (is_shub1()) { + if (!(nasid & 1)) /* Not a TIO, handle CRB errors */ + (void)hubiio_crb_error_handler(hubdev_info); + } else + bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid))); return IRQ_HANDLED; } diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index 410d356..581f9a7 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -8,7 +8,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2005 Silicon Graphics, Inc. All rights reserved. */ @@ -77,7 +77,7 @@ #define SN_SAL_IOIF_GET_PCI_TOPOLOGY 0x02000059 #define SN_SAL_HUB_ERROR_INTERRUPT 0x02000060 - +#define SN_SAL_BTE_RECOVER 0x02000061 /* * Service-specific constants @@ -1023,4 +1023,19 @@ ia64_sn_ioif_get_pci_topology(u64 rack, u64 bay, u64 slot, u64 slab, return (int) rv.status; } +/* + * BTE error recovery is implemented in SAL + */ +static inline int +ia64_sn_bte_recovery(nasid_t nasid) +{ + struct ia64_sal_retval rv; + + rv.status = 0; + SAL_CALL_NOLOCK(rv, SN_SAL_BTE_RECOVER, 0, 0, 0, 0, 0, 0, 0); + if (rv.status == SALRET_NOT_IMPLEMENTED) + return 0; + return (int) rv.status; +} + #endif /* _ASM_IA64_SN_SN_SAL_H */ -- cgit v0.10.2 From a37d98f6a98254c05315e0bbf45c4602942d14b1 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Mon, 25 Apr 2005 13:20:38 -0700 Subject: [IA64] fix syscall-optimization goof Sadly, I goofed in this syscall-tuning patch: ChangeSet 1.1966.1.40 2005/01/22 13:31:05 davidm@hpl.hp.com [IA64] Improve ia64_leave_syscall() for McKinley-type cores. Optimize ia64_leave_syscall() a bit better for McKinley-type cores. The patch looks big, but that's mostly due to renaming r16/r17 to r2/r3. Good for a 13 cycle improvement. The problem is that the size of the physical stacked registers was loaded into the wrong register (r3 instead of r17). Since r17 by coincidence always had the value 1, this had the effect of turning rse_clear_invalid into a no-op. That poses the risk of leaking kernel state back to user-land and is hence not acceptable. The fix below is simple, but unfortunately it costs us about 28 cycles in syscall overhead. ;-( Unfortunately, there isn't much we can do about that since those registers have to be cleared one way or another. --david Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 73e23da..bd86fea 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -759,7 +759,7 @@ ENTRY(ia64_leave_syscall) (pUStk) st1 [r14]=r17 addl r3=THIS_CPU(ia64_phys_stacked_size_p8),r0 ;; -(pUStk) ld4 r3=[r3] // r3 = cpu_data->phys_stacked_size_p8 +(pUStk) ld4 r17=[r3] // r17 = cpu_data->phys_stacked_size_p8 mov.m ar.csd=r0 // M2 clear ar.csd mov b6=r18 // I0 restore b6 ;; -- cgit v0.10.2 From 0985ea8f2db87d32b0b750229889e55fed7458ef Mon Sep 17 00:00:00 2001 From: Mark Goodwin Date: Mon, 25 Apr 2005 13:21:54 -0700 Subject: [IA64-SGI] Altix SN add support for slots in geoid_t locator This patch against ia64-test-2.6.12 is needed for forthcoming Altix chipsets. It renames geoid_any_t to geoid_common_t and splits the 8bit 'slab' field into two 4bit fields for 'slab' and 'slot'. Similar changes in the Altix SAL will retain backward compatibility for old kernels. Signed-off-by: Mark Goodwin Signed-off-by: Tony Luck diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index e731fcb..833e700 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c @@ -116,7 +116,7 @@ static int sn_hwperf_geoid_to_cnode(char *location) module_id = geo_module(geoid); this_rack = MODULE_GET_RACK(module_id); this_bay = MODULE_GET_BPOS(module_id); - this_slot = 0; /* XXX */ + this_slot = geo_slot(geoid); this_slab = geo_slab(geoid); if (rack == this_rack && bay == this_bay && slot == this_slot && slab == this_slab) { @@ -176,20 +176,27 @@ static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj, static void print_pci_topology(struct seq_file *s, struct sn_hwperf_object_info *obj, int *ordinal, - char *pci_topo_buf, int len) + u64 rack, u64 bay, u64 slot, u64 slab) { char *p1; char *p2; - - for (p1=pci_topo_buf; *p1 && p1 < pci_topo_buf + len;) { - if (!(p2 = strchr(p1, '\n'))) - break; - *p2 = '\0'; - seq_printf(s, "pcibus %d %s-%s\n", - *ordinal, obj->location, p1); - (*ordinal)++; - p1 = p2 + 1; + char *pg; + + if (!(pg = (char *)get_zeroed_page(GFP_KERNEL))) + return; /* ignore */ + if (ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab, + __pa(pg), PAGE_SIZE) == SN_HWPERF_OP_OK) { + for (p1=pg; *p1 && p1 < pg + PAGE_SIZE;) { + if (!(p2 = strchr(p1, '\n'))) + break; + *p2 = '\0'; + seq_printf(s, "pcibus %d %s-%s\n", + *ordinal, obj->location, p1); + (*ordinal)++; + p1 = p2 + 1; + } } + free_page((unsigned long)pg); } static int sn_topology_show(struct seq_file *s, void *d) @@ -218,9 +225,7 @@ static int sn_topology_show(struct seq_file *s, void *d) u8 region_size; u16 nasid_mask; int nasid_msb; - char *pci_topo_buf; int pci_bus_ordinal = 0; - static int pci_topo_buf_len = 256; if (obj == objs) { seq_printf(s, "# sn_topology version 2\n"); @@ -299,41 +304,13 @@ static int sn_topology_show(struct seq_file *s, void *d) /* * PCI busses attached to this node, if any */ - do { - if (sn_hwperf_location_to_bpos(obj->location, - &rack, &bay, &slot, &slab)) { - break; - } - - if (!(pci_topo_buf = vmalloc(pci_topo_buf_len))) { - printk("sn_topology_show: vmalloc failed\n"); - break; - } + if (sn_hwperf_location_to_bpos(obj->location, + &rack, &bay, &slot, &slab)) { + /* export pci bus info */ + print_pci_topology(s, obj, &pci_bus_ordinal, + rack, bay, slot, slab); - e = ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab, - pci_topo_buf, pci_topo_buf_len); - - switch (e) { - case SALRET_NOT_IMPLEMENTED: - case SALRET_INVALID_ARG: - /* ignore, don't print anything */ - e = SN_HWPERF_OP_OK; - break; - - case SALRET_ERROR: - /* retry with a bigger buffer */ - pci_topo_buf_len += 256; - break; - - case SN_HWPERF_OP_OK: - default: - /* export pci bus info */ - print_pci_topology(s, obj, &pci_bus_ordinal, - pci_topo_buf, pci_topo_buf_len); - break; - } - vfree(pci_topo_buf); - } while (e != SN_HWPERF_OP_OK && pci_topo_buf_len < 0x200000); + } } if (obj->ports) { diff --git a/include/asm-ia64/sn/geo.h b/include/asm-ia64/sn/geo.h index f566343..84b2546 100644 --- a/include/asm-ia64/sn/geo.h +++ b/include/asm-ia64/sn/geo.h @@ -18,32 +18,34 @@ #define GEOID_SIZE 8 /* Would 16 be better? The size can be different on different platforms. */ -#define MAX_SLABS 0xe /* slabs per module */ +#define MAX_SLOTS 0xf /* slots per module */ +#define MAX_SLABS 0xf /* slabs per slot */ typedef unsigned char geo_type_t; /* Fields common to all substructures */ -typedef struct geo_any_s { +typedef struct geo_common_s { moduleid_t module; /* The module (box) this h/w lives in */ geo_type_t type; /* What type of h/w is named by this geoid_t */ - slabid_t slab; /* The logical assembly within the module */ -} geo_any_t; + slabid_t slab:4; /* slab (ASIC), 0 .. 15 within slot */ + slotid_t slot:4; /* slot (Blade), 0 .. 15 within module */ +} geo_common_t; /* Additional fields for particular types of hardware */ typedef struct geo_node_s { - geo_any_t any; /* No additional fields needed */ + geo_common_t common; /* No additional fields needed */ } geo_node_t; typedef struct geo_rtr_s { - geo_any_t any; /* No additional fields needed */ + geo_common_t common; /* No additional fields needed */ } geo_rtr_t; typedef struct geo_iocntl_s { - geo_any_t any; /* No additional fields needed */ + geo_common_t common; /* No additional fields needed */ } geo_iocntl_t; typedef struct geo_pcicard_s { - geo_iocntl_t any; + geo_iocntl_t common; char bus; /* Bus/widget number */ char slot; /* PCI slot number */ } geo_pcicard_t; @@ -62,14 +64,14 @@ typedef struct geo_mem_s { typedef union geoid_u { - geo_any_t any; - geo_node_t node; + geo_common_t common; + geo_node_t node; geo_iocntl_t iocntl; geo_pcicard_t pcicard; - geo_rtr_t rtr; - geo_cpu_t cpu; - geo_mem_t mem; - char padsize[GEOID_SIZE]; + geo_rtr_t rtr; + geo_cpu_t cpu; + geo_mem_t mem; + char padsize[GEOID_SIZE]; } geoid_t; @@ -104,19 +106,26 @@ typedef union geoid_u { #define INVALID_CNODEID ((cnodeid_t)-1) #define INVALID_PNODEID ((pnodeid_t)-1) #define INVALID_SLAB (slabid_t)-1 +#define INVALID_SLOT (slotid_t)-1 #define INVALID_MODULE ((moduleid_t)-1) #define INVALID_PARTID ((partid_t)-1) static inline slabid_t geo_slab(geoid_t g) { - return (g.any.type == GEO_TYPE_INVALID) ? - INVALID_SLAB : g.any.slab; + return (g.common.type == GEO_TYPE_INVALID) ? + INVALID_SLAB : g.common.slab; +} + +static inline slotid_t geo_slot(geoid_t g) +{ + return (g.common.type == GEO_TYPE_INVALID) ? + INVALID_SLOT : g.common.slot; } static inline moduleid_t geo_module(geoid_t g) { - return (g.any.type == GEO_TYPE_INVALID) ? - INVALID_MODULE : g.any.module; + return (g.common.type == GEO_TYPE_INVALID) ? + INVALID_MODULE : g.common.module; } extern geoid_t cnodeid_get_geoid(cnodeid_t cnode); diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index 581f9a7..123c1a5 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -74,10 +74,10 @@ #define SN_SAL_IOIF_GET_PCIBUS_INFO 0x02000056 #define SN_SAL_IOIF_GET_PCIDEV_INFO 0x02000057 #define SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST 0x02000058 -#define SN_SAL_IOIF_GET_PCI_TOPOLOGY 0x02000059 #define SN_SAL_HUB_ERROR_INTERRUPT 0x02000060 #define SN_SAL_BTE_RECOVER 0x02000061 +#define SN_SAL_IOIF_GET_PCI_TOPOLOGY 0x02000062 /* * Service-specific constants @@ -1015,7 +1015,7 @@ ia64_sn_hwperf_op(nasid_t nasid, u64 opcode, u64 a0, u64 a1, u64 a2, static inline int ia64_sn_ioif_get_pci_topology(u64 rack, u64 bay, u64 slot, u64 slab, - char *buf, u64 len) + u64 buf, u64 len) { struct ia64_sal_retval rv; SAL_CALL_NOLOCK(rv, SN_SAL_IOIF_GET_PCI_TOPOLOGY, diff --git a/include/asm-ia64/sn/types.h b/include/asm-ia64/sn/types.h index 586ed47..8e04ee2 100644 --- a/include/asm-ia64/sn/types.h +++ b/include/asm-ia64/sn/types.h @@ -16,7 +16,8 @@ typedef signed short nasid_t; /* node id in numa-as-id space */ typedef signed char partid_t; /* partition ID type */ typedef unsigned int moduleid_t; /* user-visible module number type */ typedef unsigned int cmoduleid_t; /* kernel compact module id type */ -typedef signed char slabid_t; +typedef unsigned char slotid_t; /* slot (blade) within module */ +typedef unsigned char slabid_t; /* slab (asic) within slot */ typedef u64 nic_t; typedef unsigned long iopaddr_t; typedef unsigned long paddr_t; -- cgit v0.10.2 From f0a8d3c9ec1f82d2a41faa6c46b8db7bd5b1eb8d Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Mon, 25 Apr 2005 13:22:44 -0700 Subject: [IA64] Need to handle lfetch in "no_context" case. Thanks to Mark for tracking down this one. Users of __copy_from_user_inatomic() will be sad if we don't handle lfetch faults for the "no_context" case. Signed-off-by: Tony Luck diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index da85912..4174ec9 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -209,10 +209,13 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re } no_context: - if (isr & IA64_ISR_SP) { + if ((isr & IA64_ISR_SP) + || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) + { /* - * This fault was due to a speculative load set the "ed" bit in the psr to - * ensure forward progress (target register will get a NaT). + * This fault was due to a speculative load or lfetch.fault, set the "ed" + * bit in the psr to ensure forward progress. (Target register will get a + * NaT for ld.s, lfetch will be canceled.) */ ia64_psr(regs)->ed = 1; return; -- cgit v0.10.2 From 6118ec847e8e35393efc0f88394c2f5dd48c3313 Mon Sep 17 00:00:00 2001 From: Keith Owens Date: Mon, 25 Apr 2005 13:23:47 -0700 Subject: [IA64] __copy_user breaks on unaligned src memcpy_mck.S::__copy_user breaks in the prefetch code under these conditions :- * src is unaligned and * dst is near the end of a page and * the page after dst is unmapped. Signed-off-by: Keith Owens Signed-off-by: Tony Luck diff --git a/arch/ia64/lib/memcpy_mck.S b/arch/ia64/lib/memcpy_mck.S index 6f26ef7..3c2cd2f 100644 --- a/arch/ia64/lib/memcpy_mck.S +++ b/arch/ia64/lib/memcpy_mck.S @@ -300,7 +300,7 @@ EK(.ex_handler, (p[D]) st8 [dst1] = t15, 4*8) add src_pre_mem=0,src0 // prefetch src pointer add dst_pre_mem=0,dst0 // prefetch dest pointer and src0=-8,src0 // 1st src pointer -(p7) mov ar.lc = r21 +(p7) mov ar.lc = cnt (p8) mov ar.lc = r0 ;; TEXT_ALIGN(32) -- cgit v0.10.2 From e927ecb05e1ce4bbb1e10f57008c94994e2160f5 Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Mon, 25 Apr 2005 13:25:06 -0700 Subject: [IA64] multi-core/multi-thread identification Version 3 - rediffed to apply on top of Ashok's hotplug cpu patch. /proc/cpuinfo output in step with x86. This is an updated MC/MT identification patch based on the previous discussions on list. Add the Multi-core and Multi-threading detection for IPF. - Add new core and threading related fields in /proc/cpuinfo. Physical id Core id Thread id Siblings - setup the cpu_core_map and cpu_sibling_map appropriately - Handles Hot plug CPU Signed-off-by: Suresh Siddha Signed-off-by: Gordon Jin Signed-off-by: Rohit Seth Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index f05650c..8804384 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -4,10 +4,15 @@ * Copyright (C) 1998-2001, 2003-2004 Hewlett-Packard Co * David Mosberger-Tang * Stephane Eranian - * Copyright (C) 2000, Rohit Seth + * Copyright (C) 2000, 2004 Intel Corp + * Rohit Seth + * Suresh Siddha + * Gordon Jin * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond * + * 12/26/04 S.Siddha, G.Jin, R.Seth + * Add multi-threading and multi-core detection * 11/12/01 D.Mosberger Convert get_cpuinfo() to seq_file based show_cpuinfo(). * 04/04/00 D.Mosberger renamed cpu_initialized to cpu_online_map * 03/31/00 R.Seth cpu_initialized and current->processor fixes @@ -296,6 +301,34 @@ mark_bsp_online (void) #endif } +#ifdef CONFIG_SMP +static void +check_for_logical_procs (void) +{ + pal_logical_to_physical_t info; + s64 status; + + status = ia64_pal_logical_to_phys(0, &info); + if (status == -1) { + printk(KERN_INFO "No logical to physical processor mapping " + "available\n"); + return; + } + if (status) { + printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n", + status); + return; + } + /* + * Total number of siblings that BSP has. Though not all of them + * may have booted successfully. The correct number of siblings + * booted is in info.overview_num_log. + */ + smp_num_siblings = info.overview_tpc; + smp_num_cpucores = info.overview_cpp; +} +#endif + void __init setup_arch (char **cmdline_p) { @@ -356,6 +389,19 @@ setup_arch (char **cmdline_p) #ifdef CONFIG_SMP cpu_physical_id(0) = hard_smp_processor_id(); + + cpu_set(0, cpu_sibling_map[0]); + cpu_set(0, cpu_core_map[0]); + + check_for_logical_procs(); + if (smp_num_cpucores > 1) + printk(KERN_INFO + "cpu package is Multi-Core capable: number of cores=%d\n", + smp_num_cpucores); + if (smp_num_siblings > 1) + printk(KERN_INFO + "cpu package is Multi-Threading capable: number of siblings=%d\n", + smp_num_siblings); #endif cpu_init(); /* initialize the bootstrap CPU */ @@ -459,12 +505,23 @@ show_cpuinfo (struct seq_file *m, void *v) "cpu regs : %u\n" "cpu MHz : %lu.%06lu\n" "itc MHz : %lu.%06lu\n" - "BogoMIPS : %lu.%02lu\n\n", + "BogoMIPS : %lu.%02lu\n", cpunum, c->vendor, family, c->model, c->revision, c->archrev, features, c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000, c->itc_freq / 1000000, c->itc_freq % 1000000, lpj*HZ/500000, (lpj*HZ/5000) % 100); +#ifdef CONFIG_SMP + if (c->threads_per_core > 1 || c->cores_per_socket > 1) + seq_printf(m, + "physical id: %u\n" + "core id : %u\n" + "thread id : %u\n", + c->socket_id, c->core_id, c->thread_id); + seq_printf(m, "siblings : %u\n", c->num_log); +#endif + seq_printf(m,"\n"); + return 0; } @@ -533,6 +590,14 @@ identify_cpu (struct cpuinfo_ia64 *c) memcpy(c->vendor, cpuid.field.vendor, 16); #ifdef CONFIG_SMP c->cpu = smp_processor_id(); + + /* below default values will be overwritten by identify_siblings() + * for Multi-Threading/Multi-Core capable cpu's + */ + c->threads_per_core = c->cores_per_socket = c->num_log = 1; + c->socket_id = -1; + + identify_siblings(c); #endif c->ppn = cpuid.field.ppn; c->number = cpuid.field.number; diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index dbc6b61..0d5ee57 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -3,6 +3,11 @@ * * Copyright (C) 1998-2003, 2005 Hewlett-Packard Co * David Mosberger-Tang + * Copyright (C) 2001, 2004-2005 Intel Corp + * Rohit Seth + * Suresh Siddha + * Gordon Jin + * Ashok Raj * * 01/05/16 Rohit Seth Moved SMP booting functions from smp.c to here. * 01/04/27 David Mosberger Added ITC synching code. @@ -10,6 +15,11 @@ * smp_boot_cpus()/smp_commence() is replaced by * smp_prepare_cpus()/__cpu_up()/smp_cpus_done(). * 04/06/21 Ashok Raj Added CPU Hotplug Support + * 04/12/26 Jin Gordon + * 04/12/26 Rohit Seth + * Add multi-threading and multi-core detection + * 05/01/30 Suresh Siddha + * Setup cpu_sibling_map and cpu_core_map */ #include @@ -122,6 +132,11 @@ EXPORT_SYMBOL(cpu_online_map); cpumask_t cpu_possible_map; EXPORT_SYMBOL(cpu_possible_map); +cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; +cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; +int smp_num_siblings = 1; +int smp_num_cpucores = 1; + /* which logical CPU number maps to which CPU (physical APIC ID) */ volatile int ia64_cpu_to_sapicid[NR_CPUS]; EXPORT_SYMBOL(ia64_cpu_to_sapicid); @@ -598,7 +613,68 @@ void __devinit smp_prepare_boot_cpu(void) cpu_set(smp_processor_id(), cpu_callin_map); } +/* + * mt_info[] is a temporary store for all info returned by + * PAL_LOGICAL_TO_PHYSICAL, to be copied into cpuinfo_ia64 when the + * specific cpu comes. + */ +static struct { + __u32 socket_id; + __u16 core_id; + __u16 thread_id; + __u16 proc_fixed_addr; + __u8 valid; +}mt_info[NR_CPUS] __devinit; + #ifdef CONFIG_HOTPLUG_CPU +static inline void +remove_from_mtinfo(int cpu) +{ + int i; + + for_each_cpu(i) + if (mt_info[i].valid && mt_info[i].socket_id == + cpu_data(cpu)->socket_id) + mt_info[i].valid = 0; +} + +static inline void +clear_cpu_sibling_map(int cpu) +{ + int i; + + for_each_cpu_mask(i, cpu_sibling_map[cpu]) + cpu_clear(cpu, cpu_sibling_map[i]); + for_each_cpu_mask(i, cpu_core_map[cpu]) + cpu_clear(cpu, cpu_core_map[i]); + + cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE; +} + +static void +remove_siblinginfo(int cpu) +{ + int last = 0; + + if (cpu_data(cpu)->threads_per_core == 1 && + cpu_data(cpu)->cores_per_socket == 1) { + cpu_clear(cpu, cpu_core_map[cpu]); + cpu_clear(cpu, cpu_sibling_map[cpu]); + return; + } + + last = (cpus_weight(cpu_core_map[cpu]) == 1 ? 1 : 0); + + /* remove it from all sibling map's */ + clear_cpu_sibling_map(cpu); + + /* if this cpu is the last in the core group, remove all its info + * from mt_info structure + */ + if (last) + remove_from_mtinfo(cpu); +} + extern void fixup_irqs(void); /* must be called with cpucontrol mutex held */ int __cpu_disable(void) @@ -611,6 +687,7 @@ int __cpu_disable(void) if (cpu == 0) return -EBUSY; + remove_siblinginfo(cpu); fixup_irqs(); local_flush_tlb_all(); cpu_clear(cpu, cpu_callin_map); @@ -663,6 +740,23 @@ smp_cpus_done (unsigned int dummy) (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100); } +static inline void __devinit +set_cpu_sibling_map(int cpu) +{ + int i; + + for_each_online_cpu(i) { + if ((cpu_data(cpu)->socket_id == cpu_data(i)->socket_id)) { + cpu_set(i, cpu_core_map[cpu]); + cpu_set(cpu, cpu_core_map[i]); + if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) { + cpu_set(i, cpu_sibling_map[cpu]); + cpu_set(cpu, cpu_sibling_map[i]); + } + } + } +} + int __devinit __cpu_up (unsigned int cpu) { @@ -685,6 +779,15 @@ __cpu_up (unsigned int cpu) if (ret < 0) return ret; + if (cpu_data(cpu)->threads_per_core == 1 && + cpu_data(cpu)->cores_per_socket == 1) { + cpu_set(cpu, cpu_sibling_map[cpu]); + cpu_set(cpu, cpu_core_map[cpu]); + return 0; + } + + set_cpu_sibling_map(cpu); + return 0; } @@ -712,3 +815,106 @@ init_smp_config(void) ia64_sal_strerror(sal_ret)); } +static inline int __devinit +check_for_mtinfo_index(void) +{ + int i; + + for_each_cpu(i) + if (!mt_info[i].valid) + return i; + + return -1; +} + +/* + * Search the mt_info to find out if this socket's cid/tid information is + * cached or not. If the socket exists, fill in the core_id and thread_id + * in cpuinfo + */ +static int __devinit +check_for_new_socket(__u16 logical_address, struct cpuinfo_ia64 *c) +{ + int i; + __u32 sid = c->socket_id; + + for_each_cpu(i) { + if (mt_info[i].valid && mt_info[i].proc_fixed_addr == logical_address + && mt_info[i].socket_id == sid) { + c->core_id = mt_info[i].core_id; + c->thread_id = mt_info[i].thread_id; + return 1; /* not a new socket */ + } + } + return 0; +} + +/* + * identify_siblings(cpu) gets called from identify_cpu. This populates the + * information related to logical execution units in per_cpu_data structure. + */ +void __devinit +identify_siblings(struct cpuinfo_ia64 *c) +{ + s64 status; + u16 pltid; + u64 proc_fixed_addr; + int count, i; + pal_logical_to_physical_t info; + + if (smp_num_cpucores == 1 && smp_num_siblings == 1) + return; + + if ((status = ia64_pal_logical_to_phys(0, &info)) != PAL_STATUS_SUCCESS) { + printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n", + status); + return; + } + if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) { + printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status); + return; + } + if ((status = ia64_pal_fixed_addr(&proc_fixed_addr)) != PAL_STATUS_SUCCESS) { + printk(KERN_ERR "ia64_pal_fixed_addr failed with %ld\n", status); + return; + } + + c->socket_id = (pltid << 8) | info.overview_ppid; + c->cores_per_socket = info.overview_cpp; + c->threads_per_core = info.overview_tpc; + count = c->num_log = info.overview_num_log; + + /* If the thread and core id information is already cached, then + * we will simply update cpu_info and return. Otherwise, we will + * do the PAL calls and cache core and thread id's of all the siblings. + */ + if (check_for_new_socket(proc_fixed_addr, c)) + return; + + for (i = 0; i < count; i++) { + int index; + + if (i && (status = ia64_pal_logical_to_phys(i, &info)) + != PAL_STATUS_SUCCESS) { + printk(KERN_ERR "ia64_pal_logical_to_phys failed" + " with %ld\n", status); + return; + } + if (info.log2_la == proc_fixed_addr) { + c->core_id = info.log1_cid; + c->thread_id = info.log1_tid; + } + + index = check_for_mtinfo_index(); + /* We will not do the mt_info caching optimization in this case. + */ + if (index < 0) + continue; + + mt_info[index].valid = 1; + mt_info[index].socket_id = c->socket_id; + mt_info[index].core_id = info.log1_cid; + mt_info[index].thread_id = info.log1_tid; + mt_info[index].proc_fixed_addr = info.log2_la; + } +} diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h index 5dd477f..2303a10 100644 --- a/include/asm-ia64/pal.h +++ b/include/asm-ia64/pal.h @@ -67,6 +67,7 @@ #define PAL_REGISTER_INFO 39 /* return AR and CR register information*/ #define PAL_SHUTDOWN 40 /* enter processor shutdown state */ #define PAL_PREFETCH_VISIBILITY 41 /* Make Processor Prefetches Visible */ +#define PAL_LOGICAL_TO_PHYSICAL 42 /* returns information on logical to physical processor mapping */ #define PAL_COPY_PAL 256 /* relocate PAL procedures and PAL PMI */ #define PAL_HALT_INFO 257 /* return the low power capabilities of processor */ @@ -1559,6 +1560,73 @@ ia64_pal_prefetch_visibility (s64 trans_type) return iprv.status; } +/* data structure for getting information on logical to physical mappings */ +typedef union pal_log_overview_u { + struct { + u64 num_log :16, /* Total number of logical + * processors on this die + */ + tpc :8, /* Threads per core */ + reserved3 :8, /* Reserved */ + cpp :8, /* Cores per processor */ + reserved2 :8, /* Reserved */ + ppid :8, /* Physical processor ID */ + reserved1 :8; /* Reserved */ + } overview_bits; + u64 overview_data; +} pal_log_overview_t; + +typedef union pal_proc_n_log_info1_u{ + struct { + u64 tid :16, /* Thread id */ + reserved2 :16, /* Reserved */ + cid :16, /* Core id */ + reserved1 :16; /* Reserved */ + } ppli1_bits; + u64 ppli1_data; +} pal_proc_n_log_info1_t; + +typedef union pal_proc_n_log_info2_u { + struct { + u64 la :16, /* Logical address */ + reserved :48; /* Reserved */ + } ppli2_bits; + u64 ppli2_data; +} pal_proc_n_log_info2_t; + +typedef struct pal_logical_to_physical_s +{ + pal_log_overview_t overview; + pal_proc_n_log_info1_t ppli1; + pal_proc_n_log_info2_t ppli2; +} pal_logical_to_physical_t; + +#define overview_num_log overview.overview_bits.num_log +#define overview_tpc overview.overview_bits.tpc +#define overview_cpp overview.overview_bits.cpp +#define overview_ppid overview.overview_bits.ppid +#define log1_tid ppli1.ppli1_bits.tid +#define log1_cid ppli1.ppli1_bits.cid +#define log2_la ppli2.ppli2_bits.la + +/* Get information on logical to physical processor mappings. */ +static inline s64 +ia64_pal_logical_to_phys(u64 proc_number, pal_logical_to_physical_t *mapping) +{ + struct ia64_pal_retval iprv; + + PAL_CALL(iprv, PAL_LOGICAL_TO_PHYSICAL, proc_number, 0, 0); + + if (iprv.status == PAL_STATUS_SUCCESS) + { + if (proc_number == 0) + mapping->overview.overview_data = iprv.v0; + mapping->ppli1.ppli1_data = iprv.v1; + mapping->ppli2.ppli2_data = iprv.v2; + } + + return iprv.status; +} #endif /* __ASSEMBLY__ */ #endif /* _ASM_IA64_PAL_H */ diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h index 983798e..9e1ba8b 100644 --- a/include/asm-ia64/processor.h +++ b/include/asm-ia64/processor.h @@ -148,6 +148,13 @@ struct cpuinfo_ia64 { #ifdef CONFIG_SMP __u64 loops_per_jiffy; int cpu; + __u32 socket_id; /* physical processor socket id */ + __u16 core_id; /* core id */ + __u16 thread_id; /* thread id */ + __u16 num_log; /* Total number of logical processors on + * this socket that were successfully booted */ + __u8 cores_per_socket; /* Cores per processor socket */ + __u8 threads_per_core; /* Threads per core */ #endif /* CPUID-derived information: */ diff --git a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h index 240676f..29df88b 100644 --- a/include/asm-ia64/sal.h +++ b/include/asm-ia64/sal.h @@ -91,6 +91,7 @@ extern spinlock_t sal_lock; #define SAL_PCI_CONFIG_READ 0x01000010 #define SAL_PCI_CONFIG_WRITE 0x01000011 #define SAL_FREQ_BASE 0x01000012 +#define SAL_PHYSICAL_ID_INFO 0x01000013 #define SAL_UPDATE_PAL 0x01000020 @@ -815,6 +816,17 @@ ia64_sal_update_pal (u64 param_buf, u64 scratch_buf, u64 scratch_buf_size, return isrv.status; } +/* Get physical processor die mapping in the platform. */ +static inline s64 +ia64_sal_physical_id_info(u16 *splid) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_PHYSICAL_ID_INFO, 0, 0, 0, 0, 0, 0, 0); + if (splid) + *splid = isrv.v0; + return isrv.status; +} + extern unsigned long sal_platform_features; extern int (*salinfo_platform_oemdata)(const u8 *, u8 **, u64 *); diff --git a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h index c4a227a..3ba1a06 100644 --- a/include/asm-ia64/smp.h +++ b/include/asm-ia64/smp.h @@ -56,6 +56,10 @@ extern struct smp_boot_data { extern char no_int_routing __devinitdata; extern cpumask_t cpu_online_map; +extern cpumask_t cpu_core_map[NR_CPUS]; +extern cpumask_t cpu_sibling_map[NR_CPUS]; +extern int smp_num_siblings; +extern int smp_num_cpucores; extern void __iomem *ipi_base_addr; extern unsigned char smp_int_redirect; @@ -124,6 +128,7 @@ extern int smp_call_function_single (int cpuid, void (*func) (void *info), void extern void smp_send_reschedule (int cpu); extern void lock_ipi_calllock(void); extern void unlock_ipi_calllock(void); +extern void identify_siblings (struct cpuinfo_ia64 *); #else -- cgit v0.10.2 From 24eeb568aeeaee771b9f0a6fd6f5d01040a887da Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Mon, 25 Apr 2005 13:26:23 -0700 Subject: [IA64] vector sharing (Large I/O system support) Current ia64 linux cannot handle greater than 184 interrupt sources because of the lack of vectors. The following patch enables ia64 linux to handle greater than 184 interrupt sources by allowing the same vector number to be shared by multiple IOSAPIC's RTEs. The design of this patch is besed on "Intel(R) Itanium(R) Processor Family Interrupt Architecture Guide". Even if you don't have a large I/O system, you can see the behavior of vector sharing by changing IOSAPIC_LAST_DEVICE_VECTOR to fewer value. Signed-off-by: Kenji Kaneshige Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index c15be5c..11a221c 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -79,6 +79,7 @@ #include #include #include +#include #include #include @@ -98,19 +99,30 @@ #define DBG(fmt...) #endif +#define NR_PREALLOCATE_RTE_ENTRIES (PAGE_SIZE / sizeof(struct iosapic_rte_info)) +#define RTE_PREALLOCATED (1) + static DEFINE_SPINLOCK(iosapic_lock); /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ -static struct iosapic_intr_info { +struct iosapic_rte_info { + struct list_head rte_list; /* node in list of RTEs sharing the same vector */ char __iomem *addr; /* base address of IOSAPIC */ - u32 low32; /* current value of low word of Redirection table entry */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ - char rte_index; /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */ + char rte_index; /* IOSAPIC RTE index */ + int refcnt; /* reference counter */ + unsigned int flags; /* flags */ +} ____cacheline_aligned; + +static struct iosapic_intr_info { + struct list_head rtes; /* RTEs using this vector (empty => not an IOSAPIC interrupt) */ + int count; /* # of RTEs that shares this vector */ + u32 low32; /* current value of low word of Redirection table entry */ + unsigned int dest; /* destination CPU physical ID */ unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ - int refcnt; /* reference counter */ } iosapic_intr_info[IA64_NUM_VECTORS]; static struct iosapic { @@ -126,6 +138,8 @@ static int num_iosapic; static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */ +static int iosapic_kmalloc_ok; +static LIST_HEAD(free_rte_list); /* * Find an IOSAPIC associated with a GSI @@ -147,10 +161,12 @@ static inline int _gsi_to_vector (unsigned int gsi) { struct iosapic_intr_info *info; + struct iosapic_rte_info *rte; for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info) - if (info->gsi_base + info->rte_index == gsi) - return info - iosapic_intr_info; + list_for_each_entry(rte, &info->rtes, rte_list) + if (rte->gsi_base + rte->rte_index == gsi) + return info - iosapic_intr_info; return -1; } @@ -167,33 +183,52 @@ gsi_to_vector (unsigned int gsi) int gsi_to_irq (unsigned int gsi) { + unsigned long flags; + int irq; /* * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq * numbers... */ - return _gsi_to_vector(gsi); + spin_lock_irqsave(&iosapic_lock, flags); + { + irq = _gsi_to_vector(gsi); + } + spin_unlock_irqrestore(&iosapic_lock, flags); + + return irq; +} + +static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec) +{ + struct iosapic_rte_info *rte; + + list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) + if (rte->gsi_base + rte->rte_index == gsi) + return rte; + return NULL; } static void -set_rte (unsigned int vector, unsigned int dest, int mask) +set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) { unsigned long pol, trigger, dmode; u32 low32, high32; char __iomem *addr; int rte_index; char redir; + struct iosapic_rte_info *rte; DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest); - rte_index = iosapic_intr_info[vector].rte_index; - if (rte_index < 0) + rte = gsi_vector_to_rte(gsi, vector); + if (!rte) return; /* not an IOSAPIC interrupt */ - addr = iosapic_intr_info[vector].addr; + rte_index = rte->rte_index; + addr = rte->addr; pol = iosapic_intr_info[vector].polarity; trigger = iosapic_intr_info[vector].trigger; dmode = iosapic_intr_info[vector].dmode; - vector &= (~IA64_IRQ_REDIRECTED); redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0; @@ -221,6 +256,7 @@ set_rte (unsigned int vector, unsigned int dest, int mask) iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); iosapic_intr_info[vector].low32 = low32; + iosapic_intr_info[vector].dest = dest; } static void @@ -237,18 +273,20 @@ mask_irq (unsigned int irq) u32 low32; int rte_index; ia64_vector vec = irq_to_vector(irq); + struct iosapic_rte_info *rte; - addr = iosapic_intr_info[vec].addr; - rte_index = iosapic_intr_info[vec].rte_index; - - if (rte_index < 0) + if (list_empty(&iosapic_intr_info[vec].rtes)) return; /* not an IOSAPIC interrupt! */ spin_lock_irqsave(&iosapic_lock, flags); { /* set only the mask bit */ low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; - iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); + list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { + addr = rte->addr; + rte_index = rte->rte_index; + iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); + } } spin_unlock_irqrestore(&iosapic_lock, flags); } @@ -261,16 +299,19 @@ unmask_irq (unsigned int irq) u32 low32; int rte_index; ia64_vector vec = irq_to_vector(irq); + struct iosapic_rte_info *rte; - addr = iosapic_intr_info[vec].addr; - rte_index = iosapic_intr_info[vec].rte_index; - if (rte_index < 0) + if (list_empty(&iosapic_intr_info[vec].rtes)) return; /* not an IOSAPIC interrupt! */ spin_lock_irqsave(&iosapic_lock, flags); { low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; - iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); + list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { + addr = rte->addr; + rte_index = rte->rte_index; + iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); + } } spin_unlock_irqrestore(&iosapic_lock, flags); } @@ -286,6 +327,7 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) char __iomem *addr; int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; ia64_vector vec; + struct iosapic_rte_info *rte; irq &= (~IA64_IRQ_REDIRECTED); vec = irq_to_vector(irq); @@ -295,10 +337,7 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) dest = cpu_physical_id(first_cpu(mask)); - rte_index = iosapic_intr_info[vec].rte_index; - addr = iosapic_intr_info[vec].addr; - - if (rte_index < 0) + if (list_empty(&iosapic_intr_info[vec].rtes)) return; /* not an IOSAPIC interrupt */ set_irq_affinity_info(irq, dest, redir); @@ -318,8 +357,13 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); iosapic_intr_info[vec].low32 = low32; - iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); - iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); + iosapic_intr_info[vec].dest = dest; + list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { + addr = rte->addr; + rte_index = rte->rte_index; + iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); + iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); + } } spin_unlock_irqrestore(&iosapic_lock, flags); #endif @@ -340,9 +384,11 @@ static void iosapic_end_level_irq (unsigned int irq) { ia64_vector vec = irq_to_vector(irq); + struct iosapic_rte_info *rte; move_irq(irq); - iosapic_eoi(iosapic_intr_info[vec].addr, vec); + list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) + iosapic_eoi(rte->addr, vec); } #define iosapic_shutdown_level_irq mask_irq @@ -422,6 +468,34 @@ iosapic_version (char __iomem *addr) return iosapic_read(addr, IOSAPIC_VERSION); } +static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol) +{ + int i, vector = -1, min_count = -1; + struct iosapic_intr_info *info; + + /* + * shared vectors for edge-triggered interrupts are not + * supported yet + */ + if (trigger == IOSAPIC_EDGE) + return -1; + + for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) { + info = &iosapic_intr_info[i]; + if (info->trigger == trigger && info->polarity == pol && + (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) { + if (min_count == -1 || info->count < min_count) { + vector = i; + min_count = info->count; + } + } + } + if (vector < 0) + panic("%s: out of interrupt vectors!\n", __FUNCTION__); + + return vector; +} + /* * if the given vector is already owned by other, * assign a new vector for the other and make the vector available @@ -431,19 +505,63 @@ iosapic_reassign_vector (int vector) { int new_vector; - if (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr - || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode - || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger) - { + if (!list_empty(&iosapic_intr_info[vector].rtes)) { new_vector = assign_irq_vector(AUTO_ASSIGN); printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector); memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], sizeof(struct iosapic_intr_info)); + INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes); + list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes); memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); - iosapic_intr_info[vector].rte_index = -1; + iosapic_intr_info[vector].low32 = IOSAPIC_MASK; + INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); } } +static struct iosapic_rte_info *iosapic_alloc_rte (void) +{ + int i; + struct iosapic_rte_info *rte; + int preallocated = 0; + + if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) { + rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES); + if (!rte) + return NULL; + for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++) + list_add(&rte->rte_list, &free_rte_list); + } + + if (!list_empty(&free_rte_list)) { + rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list); + list_del(&rte->rte_list); + preallocated++; + } else { + rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC); + if (!rte) + return NULL; + } + + memset(rte, 0, sizeof(struct iosapic_rte_info)); + if (preallocated) + rte->flags |= RTE_PREALLOCATED; + + return rte; +} + +static void iosapic_free_rte (struct iosapic_rte_info *rte) +{ + if (rte->flags & RTE_PREALLOCATED) + list_add_tail(&rte->rte_list, &free_rte_list); + else + kfree(rte); +} + +static inline int vector_is_shared (int vector) +{ + return (iosapic_intr_info[vector].count > 1); +} + static void register_intr (unsigned int gsi, int vector, unsigned char delivery, unsigned long polarity, unsigned long trigger) @@ -454,6 +572,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, int index; unsigned long gsi_base; void __iomem *iosapic_address; + struct iosapic_rte_info *rte; index = find_iosapic(gsi); if (index < 0) { @@ -464,14 +583,33 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, iosapic_address = iosapic_lists[index].addr; gsi_base = iosapic_lists[index].gsi_base; - rte_index = gsi - gsi_base; - iosapic_intr_info[vector].rte_index = rte_index; + rte = gsi_vector_to_rte(gsi, vector); + if (!rte) { + rte = iosapic_alloc_rte(); + if (!rte) { + printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__); + return; + } + + rte_index = gsi - gsi_base; + rte->rte_index = rte_index; + rte->addr = iosapic_address; + rte->gsi_base = gsi_base; + rte->refcnt++; + list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); + iosapic_intr_info[vector].count++; + } + else if (vector_is_shared(vector)) { + struct iosapic_intr_info *info = &iosapic_intr_info[vector]; + if (info->trigger != trigger || info->polarity != polarity) { + printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__); + return; + } + } + iosapic_intr_info[vector].polarity = polarity; iosapic_intr_info[vector].dmode = delivery; - iosapic_intr_info[vector].addr = iosapic_address; - iosapic_intr_info[vector].gsi_base = gsi_base; iosapic_intr_info[vector].trigger = trigger; - iosapic_intr_info[vector].refcnt++; if (trigger == IOSAPIC_EDGE) irq_type = &irq_type_iosapic_edge; @@ -494,6 +632,13 @@ get_target_cpu (unsigned int gsi, int vector) static int cpu = -1; /* + * In case of vector shared by multiple RTEs, all RTEs that + * share the vector need to use the same destination CPU. + */ + if (!list_empty(&iosapic_intr_info[vector].rtes)) + return iosapic_intr_info[vector].dest; + + /* * If the platform supports redirection via XTP, let it * distribute interrupts. */ @@ -565,10 +710,12 @@ int iosapic_register_intr (unsigned int gsi, unsigned long polarity, unsigned long trigger) { - int vector; + int vector, mask = 1; unsigned int dest; unsigned long flags; - + struct iosapic_rte_info *rte; + u32 low32; +again: /* * If this GSI has already been registered (i.e., it's a * shared interrupt, or we lost a race to register it), @@ -578,19 +725,45 @@ iosapic_register_intr (unsigned int gsi, { vector = gsi_to_vector(gsi); if (vector > 0) { - iosapic_intr_info[vector].refcnt++; + rte = gsi_vector_to_rte(gsi, vector); + rte->refcnt++; spin_unlock_irqrestore(&iosapic_lock, flags); return vector; } + } + spin_unlock_irqrestore(&iosapic_lock, flags); + + /* If vector is running out, we try to find a sharable vector */ + vector = assign_irq_vector_nopanic(AUTO_ASSIGN); + if (vector < 0) + vector = iosapic_find_sharable_vector(trigger, polarity); + + spin_lock_irqsave(&irq_descp(vector)->lock, flags); + spin_lock(&iosapic_lock); + { + if (gsi_to_vector(gsi) > 0) { + if (list_empty(&iosapic_intr_info[vector].rtes)) + free_irq_vector(vector); + spin_unlock(&iosapic_lock); + spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); + goto again; + } - vector = assign_irq_vector(AUTO_ASSIGN); dest = get_target_cpu(gsi, vector); register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, - polarity, trigger); + polarity, trigger); - set_rte(vector, dest, 1); + /* + * If the vector is shared and already unmasked for + * other interrupt sources, don't mask it. + */ + low32 = iosapic_intr_info[vector].low32; + if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK)) + mask = 0; + set_rte(gsi, vector, dest, mask); } - spin_unlock_irqrestore(&iosapic_lock, flags); + spin_unlock_irq(&iosapic_lock); + spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), @@ -607,8 +780,10 @@ iosapic_unregister_intr (unsigned int gsi) unsigned long flags; int irq, vector; irq_desc_t *idesc; - int rte_index; + u32 low32; unsigned long trigger, polarity; + unsigned int dest; + struct iosapic_rte_info *rte; /* * If the irq associated with the gsi is not found, @@ -627,54 +802,56 @@ iosapic_unregister_intr (unsigned int gsi) spin_lock_irqsave(&idesc->lock, flags); spin_lock(&iosapic_lock); { - rte_index = iosapic_intr_info[vector].rte_index; - if (rte_index < 0) { - spin_unlock(&iosapic_lock); - spin_unlock_irqrestore(&idesc->lock, flags); + if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) { printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); WARN_ON(1); - return; + goto out; } - if (--iosapic_intr_info[vector].refcnt > 0) { - spin_unlock(&iosapic_lock); - spin_unlock_irqrestore(&idesc->lock, flags); - return; - } + if (--rte->refcnt > 0) + goto out; - /* - * If interrupt handlers still exist on the irq - * associated with the gsi, don't unregister the - * interrupt. - */ - if (idesc->action) { - iosapic_intr_info[vector].refcnt++; - spin_unlock(&iosapic_lock); - spin_unlock_irqrestore(&idesc->lock, flags); - printk(KERN_WARNING "Cannot unregister GSI. IRQ %u is still in use.\n", irq); - return; - } + /* Mask the interrupt */ + low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; + iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32); - /* Clear the interrupt controller descriptor. */ - idesc->handler = &no_irq_type; + /* Remove the rte entry from the list */ + list_del(&rte->rte_list); + iosapic_intr_info[vector].count--; + iosapic_free_rte(rte); - trigger = iosapic_intr_info[vector].trigger; + trigger = iosapic_intr_info[vector].trigger; polarity = iosapic_intr_info[vector].polarity; + dest = iosapic_intr_info[vector].dest; + printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n", + gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), + (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), + cpu_logical_id(dest), dest, vector); + + if (list_empty(&iosapic_intr_info[vector].rtes)) { + /* Sanity check */ + BUG_ON(iosapic_intr_info[vector].count); + + /* Clear the interrupt controller descriptor */ + idesc->handler = &no_irq_type; + + /* Clear the interrupt information */ + memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); + iosapic_intr_info[vector].low32 |= IOSAPIC_MASK; + INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); + + if (idesc->action) { + printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq); + WARN_ON(1); + } - /* Clear the interrupt information. */ - memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); - iosapic_intr_info[vector].rte_index = -1; /* mark as unused */ + /* Free the interrupt vector */ + free_irq_vector(vector); + } } + out: spin_unlock(&iosapic_lock); spin_unlock_irqrestore(&idesc->lock, flags); - - /* Free the interrupt vector */ - free_irq_vector(vector); - - printk(KERN_INFO "GSI %u (%s, %s) -> vector %d unregisterd.\n", - gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), - (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), - vector); } #endif /* CONFIG_ACPI_DEALLOCATE_IRQ */ @@ -724,7 +901,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), cpu_logical_id(dest), dest, vector); - set_rte(vector, dest, mask); + set_rte(gsi, vector, dest, mask); return vector; } @@ -750,7 +927,7 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, polarity == IOSAPIC_POL_HIGH ? "high" : "low", cpu_logical_id(dest), dest, vector); - set_rte(vector, dest, 1); + set_rte(gsi, vector, dest, 1); } void __init @@ -758,8 +935,10 @@ iosapic_system_init (int system_pcat_compat) { int vector; - for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) - iosapic_intr_info[vector].rte_index = -1; /* mark as unused */ + for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) { + iosapic_intr_info[vector].low32 = IOSAPIC_MASK; + INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); /* mark as unused */ + } pcat_compat = system_pcat_compat; if (pcat_compat) { @@ -825,3 +1004,10 @@ map_iosapic_to_node(unsigned int gsi_base, int node) return; } #endif + +static int __init iosapic_enable_kmalloc (void) +{ + iosapic_kmalloc_ok = 1; + return 0; +} +core_initcall (iosapic_enable_kmalloc); diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 5ba06eb..4fe60c7 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -63,20 +63,30 @@ EXPORT_SYMBOL(isa_irq_to_vector_map); static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)]; int -assign_irq_vector (int irq) +assign_irq_vector_nopanic (int irq) { int pos, vector; again: pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS); vector = IA64_FIRST_DEVICE_VECTOR + pos; if (vector > IA64_LAST_DEVICE_VECTOR) - /* XXX could look for sharable vectors instead of panic'ing... */ - panic("assign_irq_vector: out of interrupt vectors!"); + return -1; if (test_and_set_bit(pos, ia64_vector_mask)) goto again; return vector; } +int +assign_irq_vector (int irq) +{ + int vector = assign_irq_vector_nopanic(irq); + + if (vector < 0) + panic("assign_irq_vector: out of interrupt vectors!"); + + return vector; +} + void free_irq_vector (int vector) { diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h index 041ab8c..cd4e06b 100644 --- a/include/asm-ia64/hw_irq.h +++ b/include/asm-ia64/hw_irq.h @@ -81,6 +81,7 @@ extern __u8 isa_irq_to_vector_map[16]; extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt controller */ +extern int assign_irq_vector_nopanic (int irq); /* allocate a free vector without panic */ extern int assign_irq_vector (int irq); /* allocate a free vector */ extern void free_irq_vector (int vector); extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); -- cgit v0.10.2 From e1ed81ab7a34fc0f92f2e200825bdb6d86d6c8ef Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Mon, 25 Apr 2005 13:27:12 -0700 Subject: [IA64] print "siblings" before {physical,core,thread} id Rohit and Suresh changed their mind about the order to print things in /proc/cpuinfo, but didn't include the change in the version of the patch they sent to me. Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 8804384..b7e6b4c 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -512,13 +512,13 @@ show_cpuinfo (struct seq_file *m, void *v) c->itc_freq / 1000000, c->itc_freq % 1000000, lpj*HZ/500000, (lpj*HZ/5000) % 100); #ifdef CONFIG_SMP + seq_printf(m, "siblings : %u\n", c->num_log); if (c->threads_per_core > 1 || c->cores_per_socket > 1) seq_printf(m, "physical id: %u\n" "core id : %u\n" "thread id : %u\n", c->socket_id, c->core_id, c->thread_id); - seq_printf(m, "siblings : %u\n", c->num_log); #endif seq_printf(m,"\n"); -- cgit v0.10.2 From b9e41d7fb62ae26adee84c18048037214ce5d866 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Mon, 25 Apr 2005 13:27:48 -0700 Subject: [IA64] iosapic.c: typo ... s/spin_unlock_irq/spin_unlock/ vector sharing patch had a typo ... mismatched spin_lock() with a spin_unlock_irq(). Fix from Kenji Kaneshige. Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 11a221c..88b0143 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -762,7 +762,7 @@ again: mask = 0; set_rte(gsi, vector, dest, mask); } - spin_unlock_irq(&iosapic_lock); + spin_unlock(&iosapic_lock); spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", -- cgit v0.10.2 From 67639deb099c6085acc447c1b7d6a17792dedad0 Mon Sep 17 00:00:00 2001 From: Greg Howard Date: Mon, 25 Apr 2005 13:28:52 -0700 Subject: [IA64] Altix system controller event handling The following is an update of the patch I sent yesterday (3/9/05) incorporating suggestions from Christoph Hellwig and Andreas Schwab. It allows Altix and Altix-like systems to handle environmental events generated by the system controllers, and should apply on top of Jack Steiner's patch of 3/1/05 ("New chipset support for SN platform") and Mark Goodwin's patch of 3/8/05 ("Altix SN topology support for new chipsets and pci topology"). Signed-off-by: Greg Howard Signed-off-by: Tony Luck diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 3ea8cc8..e3f5c32 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -42,7 +42,7 @@ obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_RIO) += rio/ generic_serial.o obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvsi.o obj-$(CONFIG_RAW_DRIVER) += raw.o -obj-$(CONFIG_SGI_SNSC) += snsc.o +obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MMTIMER) += mmtimer.o obj-$(CONFIG_VIOCONS) += viocons.o obj-$(CONFIG_VIOTAPE) += viotape.o diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index ffb9143..e3c0b52 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -374,6 +374,7 @@ scdrv_init(void) void *salbuf; struct class_simple *snsc_class; dev_t first_dev, dev; + nasid_t event_nasid = ia64_sn_get_console_nasid(); if (alloc_chrdev_region(&first_dev, 0, numionodes, SYSCTL_BASENAME) < 0) { @@ -441,6 +442,13 @@ scdrv_init(void) ia64_sn_irtr_intr_enable(scd->scd_nasid, 0 /*ignored */ , SAL_IROUTER_INTR_RECV); + + /* on the console nasid, prepare to receive + * system controller environmental events + */ + if(scd->scd_nasid == event_nasid) { + scdrv_event_init(scd); + } } return 0; } diff --git a/drivers/char/snsc.h b/drivers/char/snsc.h index c22c6c5..a9efc13 100644 --- a/drivers/char/snsc.h +++ b/drivers/char/snsc.h @@ -47,4 +47,44 @@ struct sysctl_data_s { nasid_t scd_nasid; /* Node on which subchannels are opened. */ }; + +/* argument types */ +#define IR_ARG_INT 0x00 /* 4-byte integer (big-endian) */ +#define IR_ARG_ASCII 0x01 /* null-terminated ASCII string */ +#define IR_ARG_UNKNOWN 0x80 /* unknown data type. The low + * 7 bits will contain the data + * length. */ +#define IR_ARG_UNKNOWN_LENGTH_MASK 0x7f + + +/* system controller event codes */ +#define EV_CLASS_MASK 0xf000ul +#define EV_SEVERITY_MASK 0x0f00ul +#define EV_COMPONENT_MASK 0x00fful + +#define EV_CLASS_POWER 0x1000ul +#define EV_CLASS_FAN 0x2000ul +#define EV_CLASS_TEMP 0x3000ul +#define EV_CLASS_ENV 0x4000ul +#define EV_CLASS_TEST_FAULT 0x5000ul +#define EV_CLASS_TEST_WARNING 0x6000ul +#define EV_CLASS_PWRD_NOTIFY 0x8000ul + +#define EV_SEVERITY_POWER_STABLE 0x0000ul +#define EV_SEVERITY_POWER_LOW_WARNING 0x0100ul +#define EV_SEVERITY_POWER_HIGH_WARNING 0x0200ul +#define EV_SEVERITY_POWER_HIGH_FAULT 0x0300ul +#define EV_SEVERITY_POWER_LOW_FAULT 0x0400ul + +#define EV_SEVERITY_FAN_STABLE 0x0000ul +#define EV_SEVERITY_FAN_WARNING 0x0100ul +#define EV_SEVERITY_FAN_FAULT 0x0200ul + +#define EV_SEVERITY_TEMP_STABLE 0x0000ul +#define EV_SEVERITY_TEMP_ADVISORY 0x0100ul +#define EV_SEVERITY_TEMP_CRITICAL 0x0200ul +#define EV_SEVERITY_TEMP_FAULT 0x0300ul + +void scdrv_event_init(struct sysctl_data_s *); + #endif /* _SN_SYSCTL_H_ */ diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index 123c1a5..f914f6d 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -64,6 +64,7 @@ #define SN_SAL_SYSCTL_IOBRICK_PCI_OP 0x02000042 // reentrant #define SN_SAL_IROUTER_OP 0x02000043 +#define SN_SAL_SYSCTL_EVENT 0x02000044 #define SN_SAL_IOIF_INTERRUPT 0x0200004a #define SN_SAL_HWPERF_OP 0x02000050 // lock #define SN_SAL_IOIF_ERROR_INTERRUPT 0x02000051 @@ -850,6 +851,19 @@ ia64_sn_irtr_intr_disable(nasid_t nasid, int subch, u64 intr) return (int) rv.v0; } +/* + * Set up a node as the point of contact for system controller + * environmental event delivery. + */ +static inline int +ia64_sn_sysctl_event_init(nasid_t nasid) +{ + struct ia64_sal_retval rv; + SAL_CALL_REENTRANT(rv, SN_SAL_SYSCTL_EVENT, (u64) nasid, + 0, 0, 0, 0, 0, 0); + return (int) rv.v0; +} + /** * ia64_sn_get_fit_compt - read a FIT entry from the PROM header * @nasid: NASID of node to read -- cgit v0.10.2 From fc626b278a05a0fe3eb9abd1733120f2f400cbcd Mon Sep 17 00:00:00 2001 From: Greg Howard Date: Mon, 25 Apr 2005 13:29:46 -0700 Subject: [IA64-SGI] snsc_event.c new file Forgot the "bk new" to add this file. Part of the patch from Greg Howard Signed-off-by: Tony Luck diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c new file mode 100644 index 0000000..d692af5 --- /dev/null +++ b/drivers/char/snsc_event.c @@ -0,0 +1,304 @@ +/* + * SN Platform system controller communication support + * + * 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. + * + * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * System controller event handler + * + * These routines deal with environmental events arriving from the + * system controllers. + */ + +#include +#include +#include +#include +#include "snsc.h" + +static struct subch_data_s *event_sd; + +void scdrv_event(unsigned long); +DECLARE_TASKLET(sn_sysctl_event, scdrv_event, 0); + +/* + * scdrv_event_interrupt + * + * Pull incoming environmental events off the physical link to the + * system controller and put them in a temporary holding area in SAL. + * Schedule scdrv_event() to move them along to their ultimate + * destination. + */ +static irqreturn_t +scdrv_event_interrupt(int irq, void *subch_data, struct pt_regs *regs) +{ + struct subch_data_s *sd = subch_data; + unsigned long flags; + int status; + + spin_lock_irqsave(&sd->sd_rlock, flags); + status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch); + + if ((status > 0) && (status & SAL_IROUTER_INTR_RECV)) { + tasklet_schedule(&sn_sysctl_event); + } + spin_unlock_irqrestore(&sd->sd_rlock, flags); + return IRQ_HANDLED; +} + + +/* + * scdrv_parse_event + * + * Break an event (as read from SAL) into useful pieces so we can decide + * what to do with it. + */ +static int +scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc) +{ + char *desc_end; + + /* record event source address */ + *src = be32_to_cpup((__be32 *)event); + event += 4; /* move on to event code */ + + /* record the system controller's event code */ + *code = be32_to_cpup((__be32 *)event); + event += 4; /* move on to event arguments */ + + /* how many arguments are in the packet? */ + if (*event++ != 2) { + /* if not 2, give up */ + return -1; + } + + /* parse out the ESP code */ + if (*event++ != IR_ARG_INT) { + /* not an integer argument, so give up */ + return -1; + } + *esp_code = be32_to_cpup((__be32 *)event); + event += 4; + + /* parse out the event description */ + if (*event++ != IR_ARG_ASCII) { + /* not an ASCII string, so give up */ + return -1; + } + event[CHUNKSIZE-1] = '\0'; /* ensure this string ends! */ + event += 2; /* skip leading CR/LF */ + desc_end = desc + sprintf(desc, "%s", event); + + /* strip trailing CR/LF (if any) */ + for (desc_end--; + (desc_end != desc) && ((*desc_end == 0xd) || (*desc_end == 0xa)); + desc_end--) { + *desc_end = '\0'; + } + + return 0; +} + + +/* + * scdrv_event_severity + * + * Figure out how urgent a message we should write to the console/syslog + * via printk. + */ +static char * +scdrv_event_severity(int code) +{ + int ev_class = (code & EV_CLASS_MASK); + int ev_severity = (code & EV_SEVERITY_MASK); + char *pk_severity = KERN_NOTICE; + + switch (ev_class) { + case EV_CLASS_POWER: + switch (ev_severity) { + case EV_SEVERITY_POWER_LOW_WARNING: + case EV_SEVERITY_POWER_HIGH_WARNING: + pk_severity = KERN_WARNING; + break; + case EV_SEVERITY_POWER_HIGH_FAULT: + case EV_SEVERITY_POWER_LOW_FAULT: + pk_severity = KERN_ALERT; + break; + } + break; + case EV_CLASS_FAN: + switch (ev_severity) { + case EV_SEVERITY_FAN_WARNING: + pk_severity = KERN_WARNING; + break; + case EV_SEVERITY_FAN_FAULT: + pk_severity = KERN_CRIT; + break; + } + break; + case EV_CLASS_TEMP: + switch (ev_severity) { + case EV_SEVERITY_TEMP_ADVISORY: + pk_severity = KERN_WARNING; + break; + case EV_SEVERITY_TEMP_CRITICAL: + pk_severity = KERN_CRIT; + break; + case EV_SEVERITY_TEMP_FAULT: + pk_severity = KERN_ALERT; + break; + } + break; + case EV_CLASS_ENV: + pk_severity = KERN_ALERT; + break; + case EV_CLASS_TEST_FAULT: + pk_severity = KERN_ALERT; + break; + case EV_CLASS_TEST_WARNING: + pk_severity = KERN_WARNING; + break; + case EV_CLASS_PWRD_NOTIFY: + pk_severity = KERN_ALERT; + break; + } + + return pk_severity; +} + + +/* + * scdrv_dispatch_event + * + * Do the right thing with an incoming event. That's often nothing + * more than printing it to the system log. For power-down notifications + * we start a graceful shutdown. + */ +static void +scdrv_dispatch_event(char *event, int len) +{ + int code, esp_code, src; + char desc[CHUNKSIZE]; + char *severity; + + if (scdrv_parse_event(event, &src, &code, &esp_code, desc) < 0) { + /* ignore uninterpretible event */ + return; + } + + /* how urgent is the message? */ + severity = scdrv_event_severity(code); + + if ((code & EV_CLASS_MASK) == EV_CLASS_PWRD_NOTIFY) { + struct task_struct *p; + + /* give a SIGPWR signal to init proc */ + + /* first find init's task */ + read_lock(&tasklist_lock); + for_each_process(p) { + if (p->pid == 1) + break; + } + if (p) { /* we found init's task */ + printk(KERN_EMERG "Power off indication received. Initiating power fail sequence...\n"); + force_sig(SIGPWR, p); + } else { /* failed to find init's task - just give message(s) */ + printk(KERN_WARNING "Failed to find init proc to handle power off!\n"); + printk("%s|$(0x%x)%s\n", severity, esp_code, desc); + } + read_unlock(&tasklist_lock); + } else { + /* print to system log */ + printk("%s|$(0x%x)%s\n", severity, esp_code, desc); + } +} + + +/* + * scdrv_event + * + * Called as a tasklet when an event arrives from the L1. Read the event + * from where it's temporarily stored in SAL and call scdrv_dispatch_event() + * to send it on its way. Keep trying to read events until SAL indicates + * that there are no more immediately available. + */ +void +scdrv_event(unsigned long dummy) +{ + int status; + int len; + unsigned long flags; + struct subch_data_s *sd = event_sd; + + /* anything to read? */ + len = CHUNKSIZE; + spin_lock_irqsave(&sd->sd_rlock, flags); + status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch, + sd->sd_rb, &len); + + while (!(status < 0)) { + spin_unlock_irqrestore(&sd->sd_rlock, flags); + scdrv_dispatch_event(sd->sd_rb, len); + len = CHUNKSIZE; + spin_lock_irqsave(&sd->sd_rlock, flags); + status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch, + sd->sd_rb, &len); + } + spin_unlock_irqrestore(&sd->sd_rlock, flags); +} + + +/* + * scdrv_event_init + * + * Sets up a system controller subchannel to begin receiving event + * messages. This is sort of a specialized version of scdrv_open() + * in drivers/char/sn_sysctl.c. + */ +void +scdrv_event_init(struct sysctl_data_s *scd) +{ + int rv; + + event_sd = kmalloc(sizeof (struct subch_data_s), GFP_KERNEL); + if (event_sd == NULL) { + printk(KERN_WARNING "%s: couldn't allocate subchannel info" + " for event monitoring\n", __FUNCTION__); + return; + } + + /* initialize subch_data_s fields */ + memset(event_sd, 0, sizeof (struct subch_data_s)); + event_sd->sd_nasid = scd->scd_nasid; + spin_lock_init(&event_sd->sd_rlock); + + /* ask the system controllers to send events to this node */ + event_sd->sd_subch = ia64_sn_sysctl_event_init(scd->scd_nasid); + + if (event_sd->sd_subch < 0) { + kfree(event_sd); + printk(KERN_WARNING "%s: couldn't open event subchannel\n", + __FUNCTION__); + return; + } + + /* hook event subchannel up to the system controller interrupt */ + rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt, + SA_SHIRQ | SA_INTERRUPT, + "system controller events", event_sd); + if (rv) { + printk(KERN_WARNING "%s: irq request failed (%d)\n", + __FUNCTION__, rv); + ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch); + kfree(event_sd); + return; + } +} + + -- cgit v0.10.2 From 605036cf8443b9172b24954dc1fd218e2049f91b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 25 Apr 2005 13:31:04 -0700 Subject: From: jbarnes@sgi.com [IA64] fix ia64 Kconfig to allow CONFIG_PM on sn2 This probably should have been fixed when I fixed up the generic build for discontig+numa machines, but oh well. CONFIG_PM is allowable for generic builds but not for sn2 builds, which doesn't make much sense, and in fact breaks the build if recent ACPI bits are added to the tree. It looks like the only arch that needs to prevent CONFIG_PM stuff is the ski simulator (though those options could probably use some cleanup as well), so remove the big conditional and replace it with a simple test for IA64_HP_SIM instead. Signed-off-by: Jesse Barnes Signed-off-by: Tony Luck diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 33fcb20..468dbe8 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -329,7 +329,7 @@ menu "Power management and ACPI" config PM bool "Power Management support" - depends on IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB + depends on !IA64_HP_SIM default y help "Power Management" means that parts of your computer are shut -- cgit v0.10.2 From bd7b170201149fd82bc3212cb570a7a7386463a4 Mon Sep 17 00:00:00 2001 From: Lucas Correia Villa Real Date: Mon, 25 Apr 2005 23:12:50 +0100 Subject: [PATCH] ARM: 2644/1: Adds S3C2400 support to uncompress.h Patch from Lucas Correia Villa Real The S3C2400 doesn't have a cpuid information stored anywhere. This patch adds support to the S3C2400 at include/asm-arm/arch-s3c2400/uncompress.h by initializing the cpuid variable to the S3C2410, as they share the same routine. The GSTATUS1 pin is then used only if not compiling for the S3C2400. Signed-off-by: Lucas Correia Villa Real Signed-off-by: Ben Dooks Signed-off-by: Russell King diff --git a/include/asm-arm/arch-s3c2410/uncompress.h b/include/asm-arm/arch-s3c2410/uncompress.h index ad4252e..d7a4a83 100644 --- a/include/asm-arm/arch-s3c2410/uncompress.h +++ b/include/asm-arm/arch-s3c2410/uncompress.h @@ -16,6 +16,7 @@ * 12-Oct-2004 BJD Take account of debug uart configuration * 15-Nov-2004 BJD Fixed uart configuration * 22-Feb-2005 BJD Added watchdog to uncompress + * 04-Apr-2005 LCVR Added support to S3C2400 (no cpuid at GSTATUS1) */ #ifndef __ASM_ARCH_UNCOMPRESS_H @@ -69,9 +70,12 @@ uart_rd(unsigned int reg) static void putc(char ch) { - int cpuid = *((volatile unsigned int *)S3C2410_GSTATUS1); + int cpuid = S3C2410_GSTATUS1_2410; +#ifndef CONFIG_CPU_S3C2400 + cpuid = *((volatile unsigned int *)S3C2410_GSTATUS1); cpuid &= S3C2410_GSTATUS1_IDMASK; +#endif if (ch == '\n') putc('\r'); /* expand newline to \r\n */ -- cgit v0.10.2 From eec99e345e0568767009341ac35fb5a499301499 Mon Sep 17 00:00:00 2001 From: Lucas Correia Villa Real Date: Mon, 25 Apr 2005 23:13:15 +0100 Subject: [PATCH] ARM: 2645/1: Adds IIS definitions for the S3C2400 Patch from Lucas Correia Villa Real Adds IISFCON definitions for the S3C2400 at include/asm-arm/arch-s3c2400/regs-iis.h. Signed-off-by: Lucas Correia Villa Real Signed-off-by: Ben Dooks Signed-off-by: Russell King diff --git a/include/asm-arm/arch-s3c2410/regs-iis.h b/include/asm-arm/arch-s3c2410/regs-iis.h index 7ae8e1f..385b07d 100644 --- a/include/asm-arm/arch-s3c2410/regs-iis.h +++ b/include/asm-arm/arch-s3c2410/regs-iis.h @@ -14,6 +14,7 @@ * 26-06-2003 BJD Finished off definitions for register addresses * 12-03-2004 BJD Updated include protection * 07-03-2005 BJD Added FIFO size flags and S3C2440 MPLL + * 05-04-2005 LCVR Added IISFCON definitions for the S3C2400 */ #ifndef __ASM_ARCH_REGS_IIS_H @@ -68,5 +69,14 @@ #define S3C2410_IISFCON_RXMASK (0x3f) #define S3C2410_IISFCON_RXSHIFT (0) +#define S3C2400_IISFCON_TXDMA (1<<11) +#define S3C2400_IISFCON_RXDMA (1<<10) +#define S3C2400_IISFCON_TXENABLE (1<<9) +#define S3C2400_IISFCON_RXENABLE (1<<8) +#define S3C2400_IISFCON_TXMASK (0x07 << 4) +#define S3C2400_IISFCON_TXSHIFT (4) +#define S3C2400_IISFCON_RXMASK (0x07) +#define S3C2400_IISFCON_RXSHIFT (0) + #define S3C2410_IISFIFO (0x10) #endif /* __ASM_ARCH_REGS_IIS_H */ -- cgit v0.10.2 From 483ba50bd41d14d5325d6cd9935de86a982d08a2 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 25 Apr 2005 15:14:03 -0700 Subject: [TG3]: Fix bug in tg3_rx() This patch fixes a bug that causes tg3_has_work() to always return 1. rx work is determined by comparing tp->rx_rcb_ptr with the current hw producer index. The hw producer index is modulo the ring size, but tp- >rx_rcb_ptr is a free running counter that goes up beyond the ring size. After the ring wraps around once, tg3_has_work() will always return 1. The fix is to always do modulo arithmetic on tp->rx_rcb_ptr. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 10d4761..e53c1dc 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -2686,8 +2686,8 @@ static int tg3_vlan_rx(struct tg3 *tp, struct sk_buff *skb, u16 vlan_tag) static int tg3_rx(struct tg3 *tp, int budget) { u32 work_mask; - u32 rx_rcb_ptr = tp->rx_rcb_ptr; - u16 hw_idx, sw_idx; + u32 sw_idx = tp->rx_rcb_ptr; + u16 hw_idx; int received; hw_idx = tp->hw_status->idx[0].rx_producer; @@ -2696,7 +2696,6 @@ static int tg3_rx(struct tg3 *tp, int budget) * the opaque cookie. */ rmb(); - sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp); work_mask = 0; received = 0; while (sw_idx != hw_idx && budget > 0) { @@ -2801,14 +2800,13 @@ static int tg3_rx(struct tg3 *tp, int budget) next_pkt: (*post_ptr)++; next_pkt_nopost: - rx_rcb_ptr++; - sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp); + sw_idx++; + sw_idx %= TG3_RX_RCB_RING_SIZE(tp); } /* ACK the status ring. */ - tp->rx_rcb_ptr = rx_rcb_ptr; - tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, - (rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp))); + tp->rx_rcb_ptr = sw_idx; + tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, sw_idx); /* Refill RX ring(s). */ if (work_mask & RXD_OPAQUE_RING_STD) { -- cgit v0.10.2 From 52f6d697dc0f2c039e8413e780b0f45ddf8161fc Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 25 Apr 2005 15:14:32 -0700 Subject: [TG3]: Refresh hw index in tg3_rx() This patch refreshes the hw rx producer in tg3_rx() so that additional work posted by the hardware can be processed. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e53c1dc..92b0e49 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -2802,6 +2802,12 @@ next_pkt: next_pkt_nopost: sw_idx++; sw_idx %= TG3_RX_RCB_RING_SIZE(tp); + + /* Refresh hw_idx to see if there is new work */ + if (sw_idx == hw_idx) { + hw_idx = tp->hw_status->idx[0].rx_producer; + rmb(); + } } /* ACK the status ring. */ -- cgit v0.10.2 From 04237dddd14375fce1df4bfb1be92a35aa1c247f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 25 Apr 2005 15:17:17 -0700 Subject: [TG3]: Fix tg3_restart_ints() tg3_restart_ints() is called to re-enable interrupts after tg3_poll() has finished all the work. It calls tg3_cond_int() to force an interrupt if the status block updated bit is set. The updated bit will be set if there is a new status block update sometime during tg3_poll() and it can be very often. The worst part is that even if all the work has been processed, the updated bit remains set and an interrupt will be forced unnecessarily. The fix is to call tg3_has_work() instead to determine if new work is posted before forcing an interrupt. The way to force an interrupt is also changed to use "coalesce_now" instead of "SETINT". The former is generally a safer way to force the interrupt. Also deleted the first parameter to tg3_has_work() which is unused. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 92b0e49..903d0ce 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -426,9 +426,30 @@ static void tg3_enable_ints(struct tg3 *tp) tg3_cond_int(tp); } +static inline unsigned int tg3_has_work(struct tg3 *tp) +{ + struct tg3_hw_status *sblk = tp->hw_status; + unsigned int work_exists = 0; + + /* check for phy events */ + if (!(tp->tg3_flags & + (TG3_FLAG_USE_LINKCHG_REG | + TG3_FLAG_POLL_SERDES))) { + if (sblk->status & SD_STATUS_LINK_CHG) + work_exists = 1; + } + /* check for RX/TX work to do */ + if (sblk->idx[0].tx_consumer != tp->tx_cons || + sblk->idx[0].rx_producer != tp->rx_rcb_ptr) + work_exists = 1; + + return work_exists; +} + /* tg3_restart_ints - * similar to tg3_enable_ints, but it can return without flushing the - * PIO write which reenables interrupts + * similar to tg3_enable_ints, but it accurately determines whether there + * is new work pending and can return without flushing the PIO write + * which reenables interrupts */ static void tg3_restart_ints(struct tg3 *tp) { @@ -437,7 +458,9 @@ static void tg3_restart_ints(struct tg3 *tp) tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000); mmiowb(); - tg3_cond_int(tp); + if (tg3_has_work(tp)) + tw32(HOSTCC_MODE, tp->coalesce_mode | + (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); } static inline void tg3_netif_stop(struct tg3 *tp) @@ -2891,26 +2914,6 @@ static int tg3_poll(struct net_device *netdev, int *budget) return (done ? 0 : 1); } -static inline unsigned int tg3_has_work(struct net_device *dev, struct tg3 *tp) -{ - struct tg3_hw_status *sblk = tp->hw_status; - unsigned int work_exists = 0; - - /* check for phy events */ - if (!(tp->tg3_flags & - (TG3_FLAG_USE_LINKCHG_REG | - TG3_FLAG_POLL_SERDES))) { - if (sblk->status & SD_STATUS_LINK_CHG) - work_exists = 1; - } - /* check for RX/TX work to do */ - if (sblk->idx[0].tx_consumer != tp->tx_cons || - sblk->idx[0].rx_producer != tp->rx_rcb_ptr) - work_exists = 1; - - return work_exists; -} - /* MSI ISR - No need to check for interrupt sharing and no need to * flush status block and interrupt mailbox. PCI ordering rules * guarantee that MSI will arrive after the status block. @@ -2934,7 +2937,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs) tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); sblk->status &= ~SD_STATUS_UPDATED; - if (likely(tg3_has_work(dev, tp))) + if (likely(tg3_has_work(tp))) netif_rx_schedule(dev); /* schedule NAPI poll */ else { /* no work, re-enable interrupts @@ -2981,7 +2984,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); sblk->status &= ~SD_STATUS_UPDATED; - if (likely(tg3_has_work(dev, tp))) + if (likely(tg3_has_work(tp))) netif_rx_schedule(dev); /* schedule NAPI poll */ else { /* no work, shared interrupt perhaps? re-enable -- cgit v0.10.2 From 41130d37a449dbff3593c8585a102d5e9173eea7 Mon Sep 17 00:00:00 2001 From: Jeff Lackey Date: Mon, 25 Apr 2005 23:38:55 +0100 Subject: [PATCH] ARM: 2650/1: PXA27x sleep - workaround Errata 39 & 50 (Patch 2667) Patch from Jeff Lackey This patch updates arch/arm/mach-pxa/sleep.S to support the PXA270 CPU. It works around Errata 39 & 50 from the Intel(R) PXA27x Processor Family Specification Update. Signed-off-by: Jeff Lackey Signed-off-by: Russell King diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S index 16cad2c..5786cca 100644 --- a/arch/arm/mach-pxa/sleep.S +++ b/arch/arm/mach-pxa/sleep.S @@ -18,6 +18,11 @@ #include +#ifdef CONFIG_PXA27x // workaround for Errata 50 +#define MDREFR_KDIV 0x200a4000 // all banks +#define CCCR_SLEEP 0x00000107 // L=7 2N=2 A=0 PPDIS=0 CPDIS=0 +#endif + .text /* @@ -28,7 +33,9 @@ ENTRY(pxa_cpu_suspend) +#ifndef CONFIG_IWMMXT mra r2, r3, acc0 +#endif stmfd sp!, {r2 - r12, lr} @ save registers on stack @ get coprocessor registers @@ -61,14 +68,23 @@ ENTRY(pxa_cpu_suspend) @ prepare value for sleep mode mov r1, #3 @ sleep mode - @ prepare to put SDRAM into self-refresh manually + @ prepare pointer to physical address 0 (virtual mapping in generic.c) + mov r2, #UNCACHED_PHYS_0 + + @ prepare SDRAM refresh settings ldr r4, =MDREFR ldr r5, [r4] + + @ enable SDRAM self-refresh mode orr r5, r5, #MDREFR_SLFRSH - @ prepare pointer to physical address 0 (virtual mapping in generic.c) - mov r2, #UNCACHED_PHYS_0 +#ifdef CONFIG_PXA27x + @ set SDCLKx divide-by-2 bits (this is part of a workaround for Errata 50) + ldr r6, =MDREFR_KDIV + orr r5, r5, r6 +#endif +#ifdef CONFIG_PXA25x @ Intel PXA255 Specification Update notes problems @ about suspending with PXBus operating above 133MHz @ (see Errata 31, GPIO output signals, ... unpredictable in sleep @@ -100,6 +116,18 @@ ENTRY(pxa_cpu_suspend) mov r0, #0 mcr p14, 0, r0, c6, c0, 0 orr r0, r0, #2 @ initiate change bit +#endif +#ifdef CONFIG_PXA27x + @ Intel PXA270 Specification Update notes problems sleeping + @ with core operating above 91 MHz + @ (see Errata 50, ...processor does not exit from sleep...) + + ldr r6, =CCCR + ldr r8, [r6] @ keep original value for resume + + ldr r7, =CCCR_SLEEP @ prepare CCCR sleep value + mov r0, #0x2 @ prepare value for CLKCFG +#endif @ align execution to a cache line b 1f @@ -111,6 +139,7 @@ ENTRY(pxa_cpu_suspend) @ All needed values are now in registers. @ These last instructions should be in cache +#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x) @ initiate the frequency change... str r7, [r6] mcr p14, 0, r0, c6, c0, 0 @@ -118,14 +147,27 @@ ENTRY(pxa_cpu_suspend) @ restore the original cpu speed value for resume str r8, [r6] - @ put SDRAM into self-refresh - str r5, [r4] + @ need 6 13-MHz cycles before changing PWRMODE + @ just set frequency to 91-MHz... 6*91/13 = 42 + + mov r0, #42 +10: subs r0, r0, #1 + bne 10b +#endif + + @ Do not reorder... + @ Intel PXA270 Specification Update notes problems performing + @ external accesses after SDRAM is put in self-refresh mode + @ (see Errata 39 ...hangs when entering self-refresh mode) @ force address lines low by reading at physical address 0 ldr r3, [r2] + @ put SDRAM into self-refresh + str r5, [r4] + @ enter sleep mode - mcr p14, 0, r1, c7, c0, 0 + mcr p14, 0, r1, c7, c0, 0 @ PWRMODE 20: b 20b @ loop waiting for sleep @@ -188,7 +230,9 @@ resume_after_mmu: bl cpu_xscale_proc_init #endif ldmfd sp!, {r2, r3} +#ifndef CONFIG_IWMMXT mar acc0, r2, r3 +#endif ldmfd sp!, {r4 - r12, pc} @ return to caller -- cgit v0.10.2 From 2fac6f3fec2303649e9cd572255776cb93d3f888 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Mon, 25 Apr 2005 23:40:05 +0100 Subject: [PATCH] ARM: 2653/1: Fix memset and memzero macro double-reference of parameters Patch from Deepak Saxena The current memset() and memzero() macros on ARM reference the incoming parameters more than once and this can cause uninted side-effects. The issue was found while debugging SCTP protocol and with the specific usage of memzero(skb_put(skb,size),size). This call would call skb_put(skb,size) twice leading to badness. The fixed version copies the incoming parameters into local variables and uses those instead. Signed-off-by: Deepak Saxena Signed-off-by: Russell King diff --git a/include/asm-arm/string.h b/include/asm-arm/string.h index 2a8ab16..e50c4a3 100644 --- a/include/asm-arm/string.h +++ b/include/asm-arm/string.h @@ -29,15 +29,22 @@ extern void __memzero(void *ptr, __kernel_size_t n); #define memset(p,v,n) \ ({ \ - if ((n) != 0) { \ + void *__p = (p); size_t __n = n; \ + if ((__n) != 0) { \ if (__builtin_constant_p((v)) && (v) == 0) \ - __memzero((p),(n)); \ + __memzero((__p),(__n)); \ else \ - memset((p),(v),(n)); \ + memset((__p),(v),(__n)); \ } \ - (p); \ + (__p); \ }) -#define memzero(p,n) ({ if ((n) != 0) __memzero((p),(n)); (p); }) +#define memzero(p,n) \ + ({ \ + void *__p = (p); size_t __n = n; \ + if ((__n) != 0) \ + __memzero((__p),(__n)); \ + (__p); \ + }) #endif -- cgit v0.10.2 From 2c6e75999000ebc942526466dbd0de37bfac73a4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 18:32:12 -0700 Subject: [PATCH] ppc annotations: mpsc Usual iomem annotations + NULL noise removal. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index d0dfc3c..a8314ae 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -329,8 +329,8 @@ mpsc_sdma_stop(struct mpsc_port_info *pi) mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT); /* Clear the SDMA current and first TX and RX pointers */ - mpsc_sdma_set_tx_ring(pi, 0); - mpsc_sdma_set_rx_ring(pi, 0); + mpsc_sdma_set_tx_ring(pi, NULL); + mpsc_sdma_set_rx_ring(pi, NULL); /* Disable interrupts */ mpsc_sdma_intr_mask(pi, 0xf); @@ -1540,8 +1540,8 @@ mpsc_shared_unmap_regs(void) MPSC_SDMA_INTR_REG_BLOCK_SIZE); } - mpsc_shared_regs.mpsc_routing_base = 0; - mpsc_shared_regs.sdma_intr_base = 0; + mpsc_shared_regs.mpsc_routing_base = NULL; + mpsc_shared_regs.sdma_intr_base = NULL; mpsc_shared_regs.mpsc_routing_base_p = 0; mpsc_shared_regs.sdma_intr_base_p = 0; @@ -1678,9 +1678,9 @@ mpsc_drv_unmap_regs(struct mpsc_port_info *pi) release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE); } - pi->mpsc_base = 0; - pi->sdma_base = 0; - pi->brg_base = 0; + pi->mpsc_base = NULL; + pi->sdma_base = NULL; + pi->brg_base = NULL; pi->mpsc_base_p = 0; pi->sdma_base_p = 0; diff --git a/drivers/serial/mpsc.h b/drivers/serial/mpsc.h index 1f7294b..678dbcf 100644 --- a/drivers/serial/mpsc.h +++ b/drivers/serial/mpsc.h @@ -83,8 +83,8 @@ struct mpsc_shared_regs { phys_addr_t mpsc_routing_base_p; phys_addr_t sdma_intr_base_p; - void *mpsc_routing_base; - void *sdma_intr_base; + void __iomem *mpsc_routing_base; + void __iomem *sdma_intr_base; u32 MPSC_MRR_m; u32 MPSC_RCRR_m; @@ -120,9 +120,9 @@ struct mpsc_port_info { phys_addr_t brg_base_p; /* Virtual addresses of various blocks of registers (from platform) */ - void *mpsc_base; - void *sdma_base; - void *brg_base; + void __iomem *mpsc_base; + void __iomem *sdma_base; + void __iomem *brg_base; /* Descriptor ring and buffer allocations */ void *dma_region; -- cgit v0.10.2 From 7366d36cb967d7a3ac324c789a8b718e61d01b31 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 18:32:12 -0700 Subject: [PATCH] ppc annotations: i2c-mpc Usual iomem annotations and NULL noise removal. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 75b8d86..6f33496 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -55,7 +55,7 @@ #define CSR_RXAK 0x01 struct mpc_i2c { - char *base; + void __iomem *base; u32 interrupt; wait_queue_head_t queue; struct i2c_adapter adap; @@ -444,7 +444,7 @@ static int fsl_i2c_probe(struct device *device) fail_add: if (i2c->irq != 0) - free_irq(i2c->irq, 0); + free_irq(i2c->irq, NULL); fail_irq: iounmap(i2c->base); fail_map: -- cgit v0.10.2 From 94f2f715771d0aa5554451d1e2a920f11b8be3fe Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 18:32:12 -0700 Subject: [PATCH] isofs includes sanitized fs/isofs includes trimmed down to something resembling sanity. Kernel-only parts of linux/iso_fs.h and entire linux/iso_fs_{sb,i}.h moved to fs/isofs/isofs.h. A lot of useless #include in fs/isofs/*.c killed. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c index fb42c3f..34a44e4 100644 --- a/fs/isofs/compress.c +++ b/fs/isofs/compress.c @@ -18,29 +18,12 @@ #include #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include + #include #include -#include - -#include -#include -#include +#include "isofs.h" #include "zisofs.h" /* This should probably be global. */ diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index 14d86de..6030956 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c @@ -10,20 +10,9 @@ * * isofs directory handling functions */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include - -#include +#include "isofs.h" static int isofs_readdir(struct file *, void *, filldir_t); diff --git a/fs/isofs/export.c b/fs/isofs/export.c index e4252c9..4af856a 100644 --- a/fs/isofs/export.c +++ b/fs/isofs/export.c @@ -13,11 +13,7 @@ * fs/exportfs/expfs.c. */ -#include -#include -#include -#include -#include +#include "isofs.h" static struct dentry * isofs_export_iget(struct super_block *sb, diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index b9256e6..abd7b12 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -12,29 +12,18 @@ */ #include +#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include #include #include #include -#include -#include -#include +#include +#include #include -#include -#include +#include "isofs.h" #include "zisofs.h" #define BEQUIET diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h new file mode 100644 index 0000000..9ce7b51 --- /dev/null +++ b/fs/isofs/isofs.h @@ -0,0 +1,190 @@ +#include +#include +#include +#include + +enum isofs_file_format { + isofs_file_normal = 0, + isofs_file_sparse = 1, + isofs_file_compressed = 2, +}; + +/* + * iso fs inode data in memory + */ +struct iso_inode_info { + unsigned long i_iget5_block; + unsigned long i_iget5_offset; + unsigned int i_first_extent; + unsigned char i_file_format; + unsigned char i_format_parm[3]; + unsigned long i_next_section_block; + unsigned long i_next_section_offset; + off_t i_section_size; + struct inode vfs_inode; +}; + +/* + * iso9660 super-block data in memory + */ +struct isofs_sb_info { + unsigned long s_ninodes; + unsigned long s_nzones; + unsigned long s_firstdatazone; + unsigned long s_log_zone_size; + unsigned long s_max_size; + + unsigned char s_high_sierra; /* A simple flag */ + unsigned char s_mapping; + int s_rock_offset; /* offset of SUSP fields within SU area */ + unsigned char s_rock; + unsigned char s_joliet_level; + unsigned char s_utf8; + unsigned char s_cruft; /* Broken disks with high + byte of length containing + junk */ + unsigned char s_unhide; + unsigned char s_nosuid; + unsigned char s_nodev; + unsigned char s_nocompress; + + mode_t s_mode; + gid_t s_gid; + uid_t s_uid; + struct nls_table *s_nls_iocharset; /* Native language support table */ +}; + +static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb) +{ + return sb->s_fs_info; +} + +static inline struct iso_inode_info *ISOFS_I(struct inode *inode) +{ + return container_of(inode, struct iso_inode_info, vfs_inode); +} + +static inline int isonum_711(char *p) +{ + return *(u8 *)p; +} +static inline int isonum_712(char *p) +{ + return *(s8 *)p; +} +static inline unsigned int isonum_721(char *p) +{ + return le16_to_cpu(get_unaligned((__le16 *)p)); +} +static inline unsigned int isonum_722(char *p) +{ + return be16_to_cpu(get_unaligned((__le16 *)p)); +} +static inline unsigned int isonum_723(char *p) +{ + /* Ignore bigendian datum due to broken mastering programs */ + return le16_to_cpu(get_unaligned((__le16 *)p)); +} +static inline unsigned int isonum_731(char *p) +{ + return le32_to_cpu(get_unaligned((__le32 *)p)); +} +static inline unsigned int isonum_732(char *p) +{ + return be32_to_cpu(get_unaligned((__le32 *)p)); +} +static inline unsigned int isonum_733(char *p) +{ + /* Ignore bigendian datum due to broken mastering programs */ + return le32_to_cpu(get_unaligned((__le32 *)p)); +} +extern int iso_date(char *, int); + +struct inode; /* To make gcc happy */ + +extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *); +extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *); +extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *); + +int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *); +int get_acorn_filename(struct iso_directory_record *, char *, struct inode *); + +extern struct dentry *isofs_lookup(struct inode *, struct dentry *, struct nameidata *); +extern struct buffer_head *isofs_bread(struct inode *, sector_t); +extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long); + +extern struct inode *isofs_iget(struct super_block *sb, + unsigned long block, + unsigned long offset); + +/* Because the inode number is no longer relevant to finding the + * underlying meta-data for an inode, we are free to choose a more + * convenient 32-bit number as the inode number. The inode numbering + * scheme was recommended by Sergey Vlasov and Eric Lammerts. */ +static inline unsigned long isofs_get_ino(unsigned long block, + unsigned long offset, + unsigned long bufbits) +{ + return (block << (bufbits - 5)) | (offset >> 5); +} + +/* Every directory can have many redundant directory entries scattered + * throughout the directory tree. First there is the directory entry + * with the name of the directory stored in the parent directory. + * Then, there is the "." directory entry stored in the directory + * itself. Finally, there are possibly many ".." directory entries + * stored in all the subdirectories. + * + * In order for the NFS get_parent() method to work and for the + * general consistency of the dcache, we need to make sure the + * "i_iget5_block" and "i_iget5_offset" all point to exactly one of + * the many redundant entries for each directory. We normalize the + * block and offset by always making them point to the "." directory. + * + * Notice that we do not use the entry for the directory with the name + * that is located in the parent directory. Even though choosing this + * first directory is more natural, it is much easier to find the "." + * entry in the NFS get_parent() method because it is implicitly + * encoded in the "extent + ext_attr_length" fields of _all_ the + * redundant entries for the directory. Thus, it can always be + * reached regardless of which directory entry you have in hand. + * + * This works because the "." entry is simply the first directory + * record when you start reading the file that holds all the directory + * records, and this file starts at "extent + ext_attr_length" blocks. + * Because the "." entry is always the first entry listed in the + * directories file, the normalized "offset" value is always 0. + * + * You should pass the directory entry in "de". On return, "block" + * and "offset" will hold normalized values. Only directories are + * affected making it safe to call even for non-directory file + * types. */ +static inline void +isofs_normalize_block_and_offset(struct iso_directory_record* de, + unsigned long *block, + unsigned long *offset) +{ + /* Only directories are normalized. */ + if (de->flags[0] & 2) { + *offset = 0; + *block = (unsigned long)isonum_733(de->extent) + + (unsigned long)isonum_711(de->ext_attr_length); + } +} + +extern struct inode_operations isofs_dir_inode_operations; +extern struct file_operations isofs_dir_operations; +extern struct address_space_operations isofs_symlink_aops; +extern struct export_operations isofs_export_ops; + +/* The following macros are used to check for memory leaks. */ +#ifdef LEAK_CHECK +#define free_s leak_check_free_s +#define malloc leak_check_malloc +#define sb_bread leak_check_bread +#define brelse leak_check_brelse +extern void * leak_check_malloc(unsigned int size); +extern void leak_check_free_s(void * obj, int size); +extern struct buffer_head * leak_check_bread(struct super_block *sb, int block); +extern void leak_check_brelse(struct buffer_head * bh); +#endif /* LEAK_CHECK */ diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c index 86c50e2..2931de7 100644 --- a/fs/isofs/joliet.c +++ b/fs/isofs/joliet.c @@ -6,11 +6,9 @@ * Joliet: Microsoft's Unicode extensions to iso9660 */ -#include +#include #include -#include -#include -#include +#include "isofs.h" /* * Convert Unicode 16 to UTF8 or ASCII. diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 9569fc4..690edf3 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -6,20 +6,9 @@ * (C) 1991 Linus Torvalds - minix filesystem */ -#include -#include -#include -#include -#include -#include -#include -#include #include /* Joliet? */ #include -#include -#include - -#include +#include "isofs.h" /* * ok, we cannot use strncmp, as the name is not in our data space. diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 8bdd3e4..089e79c 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -6,17 +6,11 @@ * Rock Ridge Extensions to iso9660 */ -#include -#include -#include -#include -#include #include #include #include -#include -#include +#include "isofs.h" #include "rock.h" /* These functions are designed to read the system areas of a directory record diff --git a/fs/isofs/util.c b/fs/isofs/util.c index 3f6d9c1..01e1ee7 100644 --- a/fs/isofs/util.c +++ b/fs/isofs/util.c @@ -2,9 +2,7 @@ * linux/fs/isofs/util.c */ -#include -#include -#include +#include "isofs.h" /* * We have to convert from a MM/DD/YY format to the Unix ctime format. @@ -80,4 +78,3 @@ int iso_date(char * p, int flag) } return crtime; } - diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h index 099039d..4796787 100644 --- a/include/linux/iso_fs.h +++ b/include/linux/iso_fs.h @@ -1,4 +1,3 @@ - #ifndef _ISOFS_FS_H #define _ISOFS_FS_H @@ -163,150 +162,4 @@ struct iso_directory_record { #define ISOFS_SUPER_MAGIC 0x9660 -#ifdef __KERNEL__ -/* Number conversion inlines, named after the section in ISO 9660 - they correspond to. */ - -#include -#include -#include -#include - -static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} - -static inline struct iso_inode_info *ISOFS_I(struct inode *inode) -{ - return container_of(inode, struct iso_inode_info, vfs_inode); -} - -static inline int isonum_711(char *p) -{ - return *(u8 *)p; -} -static inline int isonum_712(char *p) -{ - return *(s8 *)p; -} -static inline unsigned int isonum_721(char *p) -{ - return le16_to_cpu(get_unaligned((__le16 *)p)); -} -static inline unsigned int isonum_722(char *p) -{ - return be16_to_cpu(get_unaligned((__le16 *)p)); -} -static inline unsigned int isonum_723(char *p) -{ - /* Ignore bigendian datum due to broken mastering programs */ - return le16_to_cpu(get_unaligned((__le16 *)p)); -} -static inline unsigned int isonum_731(char *p) -{ - return le32_to_cpu(get_unaligned((__le32 *)p)); -} -static inline unsigned int isonum_732(char *p) -{ - return be32_to_cpu(get_unaligned((__le32 *)p)); -} -static inline unsigned int isonum_733(char *p) -{ - /* Ignore bigendian datum due to broken mastering programs */ - return le32_to_cpu(get_unaligned((__le32 *)p)); -} -extern int iso_date(char *, int); - -struct inode; /* To make gcc happy */ - -extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *); -extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *); -extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *); - -int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *); -int get_acorn_filename(struct iso_directory_record *, char *, struct inode *); - -extern struct dentry *isofs_lookup(struct inode *, struct dentry *, struct nameidata *); -extern struct buffer_head *isofs_bread(struct inode *, sector_t); -extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long); - -extern struct inode *isofs_iget(struct super_block *sb, - unsigned long block, - unsigned long offset); - -/* Because the inode number is no longer relevant to finding the - * underlying meta-data for an inode, we are free to choose a more - * convenient 32-bit number as the inode number. The inode numbering - * scheme was recommended by Sergey Vlasov and Eric Lammerts. */ -static inline unsigned long isofs_get_ino(unsigned long block, - unsigned long offset, - unsigned long bufbits) -{ - return (block << (bufbits - 5)) | (offset >> 5); -} - -/* Every directory can have many redundant directory entries scattered - * throughout the directory tree. First there is the directory entry - * with the name of the directory stored in the parent directory. - * Then, there is the "." directory entry stored in the directory - * itself. Finally, there are possibly many ".." directory entries - * stored in all the subdirectories. - * - * In order for the NFS get_parent() method to work and for the - * general consistency of the dcache, we need to make sure the - * "i_iget5_block" and "i_iget5_offset" all point to exactly one of - * the many redundant entries for each directory. We normalize the - * block and offset by always making them point to the "." directory. - * - * Notice that we do not use the entry for the directory with the name - * that is located in the parent directory. Even though choosing this - * first directory is more natural, it is much easier to find the "." - * entry in the NFS get_parent() method because it is implicitly - * encoded in the "extent + ext_attr_length" fields of _all_ the - * redundant entries for the directory. Thus, it can always be - * reached regardless of which directory entry you have in hand. - * - * This works because the "." entry is simply the first directory - * record when you start reading the file that holds all the directory - * records, and this file starts at "extent + ext_attr_length" blocks. - * Because the "." entry is always the first entry listed in the - * directories file, the normalized "offset" value is always 0. - * - * You should pass the directory entry in "de". On return, "block" - * and "offset" will hold normalized values. Only directories are - * affected making it safe to call even for non-directory file - * types. */ -static inline void -isofs_normalize_block_and_offset(struct iso_directory_record* de, - unsigned long *block, - unsigned long *offset) -{ - /* Only directories are normalized. */ - if (de->flags[0] & 2) { - *offset = 0; - *block = (unsigned long)isonum_733(de->extent) - + (unsigned long)isonum_711(de->ext_attr_length); - } -} - -extern struct inode_operations isofs_dir_inode_operations; -extern struct file_operations isofs_dir_operations; -extern struct address_space_operations isofs_symlink_aops; -extern struct export_operations isofs_export_ops; - -/* The following macros are used to check for memory leaks. */ -#ifdef LEAK_CHECK -#define free_s leak_check_free_s -#define malloc leak_check_malloc -#define sb_bread leak_check_bread -#define brelse leak_check_brelse -extern void * leak_check_malloc(unsigned int size); -extern void leak_check_free_s(void * obj, int size); -extern struct buffer_head * leak_check_bread(struct super_block *sb, int block); -extern void leak_check_brelse(struct buffer_head * bh); -#endif /* LEAK_CHECK */ - -#endif /* __KERNEL__ */ - #endif diff --git a/include/linux/iso_fs_i.h b/include/linux/iso_fs_i.h deleted file mode 100644 index 59065e9..0000000 --- a/include/linux/iso_fs_i.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _ISO_FS_I -#define _ISO_FS_I - -#include - -enum isofs_file_format { - isofs_file_normal = 0, - isofs_file_sparse = 1, - isofs_file_compressed = 2, -}; - -/* - * iso fs inode data in memory - */ -struct iso_inode_info { - unsigned long i_iget5_block; - unsigned long i_iget5_offset; - unsigned int i_first_extent; - unsigned char i_file_format; - unsigned char i_format_parm[3]; - unsigned long i_next_section_block; - unsigned long i_next_section_offset; - off_t i_section_size; - struct inode vfs_inode; -}; - -#endif diff --git a/include/linux/iso_fs_sb.h b/include/linux/iso_fs_sb.h deleted file mode 100644 index 043b97b..0000000 --- a/include/linux/iso_fs_sb.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _ISOFS_FS_SB -#define _ISOFS_FS_SB - -/* - * iso9660 super-block data in memory - */ -struct isofs_sb_info { - unsigned long s_ninodes; - unsigned long s_nzones; - unsigned long s_firstdatazone; - unsigned long s_log_zone_size; - unsigned long s_max_size; - - unsigned char s_high_sierra; /* A simple flag */ - unsigned char s_mapping; - int s_rock_offset; /* offset of SUSP fields within SU area */ - unsigned char s_rock; - unsigned char s_joliet_level; - unsigned char s_utf8; - unsigned char s_cruft; /* Broken disks with high - byte of length containing - junk */ - unsigned char s_unhide; - unsigned char s_nosuid; - unsigned char s_nodev; - unsigned char s_nocompress; - - mode_t s_mode; - gid_t s_gid; - uid_t s_uid; - struct nls_table *s_nls_iocharset; /* Native language support table */ -}; - -#endif -- cgit v0.10.2 From b453257f057b834fdf9f4a6ad6133598b79bd982 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 18:32:13 -0700 Subject: [PATCH] kill gratitious includes of major.h under net/* A lot of places in there are including major.h for no reason whatsoever. Removed. And yes, it still builds. The history of that stuff is often amusing. E.g. for net/core/sock.c the story looks so, as far as I've been able to reconstruct it: we used to need major.h in net/socket.c circa 1.1.early. In 1.1.13 that need had disappeared, along with register_chrdev(SOCKET_MAJOR, "socket", &net_fops) in sock_init(). Include had not. When 1.2 -> 1.3 reorg of net/* had moved a lot of stuff from net/socket.c to net/core/sock.c, this crap had followed... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 1650c6b..12b4334 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 9a8d99a..9778c6a 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 1e5c030..b2e7e38 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 20ce04f..2e341de 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 4c7f9e2..beb045b 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 71762d7..a31244e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 860dba7..fb55243 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8ccba8e..c4b592b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index c9792ba..ebdcce5 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 2cf98ce..affbc55 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index fabb36d..f8986f8 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c12babc..32fccfb 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 640028a..f3f6355 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 3e750ef..746c11f 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 44dfaf8..d8c198e 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/net/core/scm.c b/net/core/scm.c index a2ebf30..e887d19 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/net/core/sock.c b/net/core/sock.c index 4df4fa3..5c2f72f 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -97,7 +97,6 @@ #include #include #include -#include #include #include #include diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c34dab6..cdad476 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -73,7 +73,6 @@ #include #include #include -#include #include #include #include diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 53a6680..2b193e3 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 1d5905c..29a5fd2 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index acc73fe..c478fc8 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -85,7 +85,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From 088dd3a45fdb8fb726cd50575856562c4f6f1c3e Mon Sep 17 00:00:00 2001 From: James Morris Date: Mon, 25 Apr 2005 21:39:29 -0700 Subject: [TCP]: Trivial tcp_data_queue() cleanup This patch removes a superfluous intialization from tcp_data_queue(). Signed-off-by: James Morris Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2504927..6984042 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3517,7 +3517,6 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) goto drop; - th = skb->h.th; __skb_pull(skb, th->doff*4); TCP_ECN_accept_cwr(tp, skb); -- cgit v0.10.2 From 5523662c4cd585b892811d7bb3e25d9a787e19b3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 25 Apr 2005 21:40:39 -0700 Subject: [NET]: kill gratitious includes of major.h A lot of places in there are including major.h for no reason whatsoever. Removed. And yes, it still builds. The history of that stuff is often amusing. E.g. for net/core/sock.c the story looks so, as far as I've been able to reconstruct it: we used to need major.h in net/socket.c circa 1.1.early. In 1.1.13 that need had disappeared, along with register_chrdev(SOCKET_MAJOR, "socket", &net_fops) in sock_init(). Include had not. When 1.2 -> 1.3 reorg of net/* had moved a lot of stuff from net/socket.c to net/core/sock.c, this crap had followed... Signed-off-by: Al Viro Signed-off-by: David S. Miller diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 1650c6b..12b4334 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 9a8d99a..9778c6a 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 1e5c030..b2e7e38 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 20ce04f..2e341de 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 4c7f9e2..beb045b 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 71762d7..a31244e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 860dba7..fb55243 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8ccba8e..c4b592b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index c9792ba..ebdcce5 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 2cf98ce..affbc55 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index fabb36d..f8986f8 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c12babc..32fccfb 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 640028a..f3f6355 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 3e750ef..746c11f 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 44dfaf8..d8c198e 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/net/core/scm.c b/net/core/scm.c index a2ebf30..e887d19 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/net/core/sock.c b/net/core/sock.c index 4df4fa3..5c2f72f 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -97,7 +97,6 @@ #include #include #include -#include #include #include #include diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c34dab6..cdad476 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -73,7 +73,6 @@ #include #include #include -#include #include #include #include diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 53a6680..2b193e3 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 1d5905c..29a5fd2 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index acc73fe..c478fc8 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -85,7 +85,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From 7933523dc75823342dbd70a27760a82a5302baf4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:17:42 +0100 Subject: [PATCH] ARM: remove some entry initialisation asm code Convert the trivial vector entry initialisation code to C code. Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index bb27c31..37723bf 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -522,8 +522,9 @@ ENTRY(__switch_to) /* * Vector stubs. * - * This code is copied to 0x200 or 0xffff0200 so we can use branches in the - * vectors, rather than ldr's. + * This code is copied to 0xffff0200 so we can use branches in the + * vectors, rather than ldr's. Note that this code must not + * exceed 0x300 bytes. * * Common stub entry macro: * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC @@ -552,6 +553,7 @@ vector_\name: movs pc, lr @ Changes mode and branches .endm + .globl __stubs_start __stubs_start: /* * Interrupt dispatcher @@ -686,37 +688,24 @@ vector_addrexcptn: .LCsabt: .word __temp_abt + .globl __stubs_end __stubs_end: - .equ __real_stubs_start, .LCvectors + 0x200 + .equ stubs_offset, __vectors_start + 0x200 - __stubs_start -.LCvectors: + .globl __vectors_start +__vectors_start: swi SYS_ERROR0 - b __real_stubs_start + (vector_und - __stubs_start) - ldr pc, __real_stubs_start + (.LCvswi - __stubs_start) - b __real_stubs_start + (vector_pabt - __stubs_start) - b __real_stubs_start + (vector_dabt - __stubs_start) - b __real_stubs_start + (vector_addrexcptn - __stubs_start) - b __real_stubs_start + (vector_irq - __stubs_start) - b __real_stubs_start + (vector_fiq - __stubs_start) - -ENTRY(__trap_init) - stmfd sp!, {r4 - r6, lr} - - mov r0, #0xff000000 - orr r0, r0, #0x00ff0000 @ high vectors position - adr r1, .LCvectors @ set up the vectors - ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr} - stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr} - - add r2, r0, #0x200 - adr r0, __stubs_start @ copy stubs to 0x200 - adr r1, __stubs_end -1: ldr r3, [r0], #4 - str r3, [r2], #4 - cmp r0, r1 - blt 1b - LOADREGS(fd, sp!, {r4 - r6, pc}) + b vector_und + stubs_offset + ldr pc, .LCvswi + stubs_offset + b vector_pabt + stubs_offset + b vector_dabt + stubs_offset + b vector_addrexcptn + stubs_offset + b vector_irq + stubs_offset + b vector_fiq + stubs_offset + + .globl __vectors_end +__vectors_end: .data diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 6e31718..0078aeb 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -578,9 +578,16 @@ EXPORT_SYMBOL(abort); void __init trap_init(void) { - extern void __trap_init(void); + extern char __stubs_start[], __stubs_end[]; + extern char __vectors_start[], __vectors_end[]; - __trap_init(); + /* + * Copy the vectors and stubs (in entry-armv.S) into the + * vector page, mapped at 0xffff0000, and ensure these are + * visible to the instruction stream. + */ + memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start); + memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start); flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); } -- cgit v0.10.2 From 1ec42c0c97186fadc48810ccaf2dc573cd957ea1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:18:26 +0100 Subject: [PATCH] ARM: Remove argument for disable_irq/enable_irq Since we do not require a register for these operations, we can remove this unnecessary argument. Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 37723bf..fc14289 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -118,7 +118,7 @@ __dabt_svc: @ @ IRQs off again before pulling preserved data off the stack @ - disable_irq r0 + disable_irq @ @ restore SPSR and restart the instruction @@ -198,7 +198,7 @@ __und_svc: @ @ IRQs off again before pulling preserved data off the stack @ -1: disable_irq r0 +1: disable_irq @ @ restore SPSR and restart the instruction @@ -232,7 +232,7 @@ __pabt_svc: @ @ IRQs off again before pulling preserved data off the stack @ - disable_irq r0 + disable_irq @ @ restore SPSR and restart the instruction @@ -316,7 +316,7 @@ __dabt_usr: @ @ IRQs on, then call the main handler @ - enable_irq r2 + enable_irq mov r2, sp adr lr, ret_from_exception b do_DataAbort @@ -418,7 +418,7 @@ call_fpe: movcss r7, r5, lsr #(TIF_USING_IWMMXT + 1) bcs iwmmxt_task_enable #endif - enable_irq r7 + enable_irq add pc, pc, r8, lsr #6 mov r0, r0 @@ -472,7 +472,7 @@ fpundefinstr: __pabt_usr: usr_entry abt - enable_irq r0 @ Enable interrupts + enable_irq @ Enable interrupts mov r0, r2 @ address (pc) mov r1, sp @ regs bl do_PrefetchAbort @ call abort handler diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 53a7e0d..0cd9f7b 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -30,7 +30,7 @@ * stack. */ ret_fast_syscall: - disable_irq r1 @ disable interrupts + disable_irq @ disable interrupts ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne fast_work_pending @@ -49,7 +49,7 @@ work_pending: mov r0, sp @ 'regs' mov r2, why @ 'syscall' bl do_notify_resume - disable_irq r1 @ disable interrupts + disable_irq @ disable interrupts b no_work_pending work_resched: @@ -59,7 +59,7 @@ work_resched: */ ENTRY(ret_to_user) ret_slow_syscall: - disable_irq r1 @ disable interrupts + disable_irq @ disable interrupts ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne work_pending @@ -126,7 +126,7 @@ ENTRY(vector_swi) ldr ip, [ip] mcr p15, 0, ip, c1, c0 @ update control register #endif - enable_irq ip + enable_irq str r4, [sp, #-S_OFF]! @ push fifth arg diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 4039d8c..109f4f1 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -63,25 +63,21 @@ #define S_R0 0 #define S_OFF 8 - .macro set_cpsr_c, reg, mode - msr cpsr_c, \mode - .endm - #if __LINUX_ARM_ARCH__ >= 6 - .macro disable_irq, temp + .macro disable_irq cpsid i .endm - .macro enable_irq, temp + .macro enable_irq cpsie i .endm #else - .macro disable_irq, temp - set_cpsr_c \temp, #PSR_I_BIT | MODE_SVC + .macro disable_irq + msr cpsr_c, #PSR_I_BIT | SVC_MODE .endm - .macro enable_irq, temp - set_cpsr_c \temp, #MODE_SVC + .macro enable_irq + msr cpsr_c, #SVC_MODE .endm #endif -- cgit v0.10.2 From 925c8a1a8cb9d7a33a8e39516d7fb679030553fc Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:18:59 +0100 Subject: [PATCH] ARM: pt_regs offsets Generate pt_regs S_xx offsets from the structure itself instead of #defining them. Signed-off-by: Russell King diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 99d4325..c1ff4d1 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -64,6 +64,26 @@ int main(void) DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate)); DEFINE(TI_IWMMXT_STATE, (offsetof(struct thread_info, fpstate)+4)&~7); BLANK(); + DEFINE(S_R0, offsetof(struct pt_regs, ARM_r0)); + DEFINE(S_R1, offsetof(struct pt_regs, ARM_r1)); + DEFINE(S_R2, offsetof(struct pt_regs, ARM_r2)); + DEFINE(S_R3, offsetof(struct pt_regs, ARM_r3)); + DEFINE(S_R4, offsetof(struct pt_regs, ARM_r4)); + DEFINE(S_R5, offsetof(struct pt_regs, ARM_r5)); + DEFINE(S_R6, offsetof(struct pt_regs, ARM_r6)); + DEFINE(S_R7, offsetof(struct pt_regs, ARM_r7)); + DEFINE(S_R8, offsetof(struct pt_regs, ARM_r8)); + DEFINE(S_R9, offsetof(struct pt_regs, ARM_r9)); + DEFINE(S_R10, offsetof(struct pt_regs, ARM_r10)); + DEFINE(S_FP, offsetof(struct pt_regs, ARM_fp)); + DEFINE(S_IP, offsetof(struct pt_regs, ARM_ip)); + DEFINE(S_SP, offsetof(struct pt_regs, ARM_sp)); + DEFINE(S_LR, offsetof(struct pt_regs, ARM_lr)); + DEFINE(S_PC, offsetof(struct pt_regs, ARM_pc)); + DEFINE(S_PSR, offsetof(struct pt_regs, ARM_cpsr)); + DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0)); + DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); + BLANK(); #if __LINUX_ARM_ARCH__ >= 6 DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id)); BLANK(); diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 0cd9f7b..55201db 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -15,13 +15,6 @@ #include "entry-header.S" -/* - * We rely on the fact that R0 is at the bottom of the stack (due to - * slow/fast restore user regs). - */ -#if S_R0 != 0 -#error "Please fix" -#endif .align 5 /* diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 109f4f1..9d4d286 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -39,30 +39,19 @@ #define ARMSWI_OFFSET 0x000f0000 @ -@ Stack format (ensured by USER_* and SVC_*) +@ Most of the stack format comes from struct pt_regs, but with +@ the addition of 8 bytes for storing syscall args 5 and 6. @ -#define S_FRAME_SIZE 72 -#define S_OLD_R0 68 -#define S_PSR 64 - -#define S_PC 60 -#define S_LR 56 -#define S_SP 52 -#define S_IP 48 -#define S_FP 44 -#define S_R10 40 -#define S_R9 36 -#define S_R8 32 -#define S_R7 28 -#define S_R6 24 -#define S_R5 20 -#define S_R4 16 -#define S_R3 12 -#define S_R2 8 -#define S_R1 4 -#define S_R0 0 #define S_OFF 8 +/* + * The SWI code relies on the fact that R0 is at the bottom of the stack + * (due to slow/fast restore user regs). + */ +#if S_R0 != 0 +#error "Please fix" +#endif + #if __LINUX_ARM_ARCH__ >= 6 .macro disable_irq cpsid i -- cgit v0.10.2 From e0f9f4a622cec66d09a5d9339f048877c665cec3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:19:24 +0100 Subject: [PATCH] ARM: Use __NR_SYSCALL_BASE and __ARM_NR_BASE in asm code Don't define our own local constants, but use those already defined in asm/unistd.h instead. Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 55201db..65c58b3 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -111,7 +111,17 @@ ENTRY(ret_from_fork) ENTRY(vector_swi) save_user_regs zero_fp - get_scno + + /* + * Get the system call number. + */ +#ifdef CONFIG_ARM_THUMB + tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs + addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in + ldreq scno, [lr, #-4] +#else + ldr scno, [lr, #-4] @ get SWI instruction +#endif arm710_bug_check scno, ip #ifdef CONFIG_ALIGNMENT_TRAP @@ -126,7 +136,7 @@ ENTRY(vector_swi) get_thread_info tsk ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing bic scno, scno, #0xff000000 @ mask off SWI op-code - eor scno, scno, #OS_NUMBER << 20 @ check OS number + eor scno, scno, #__NR_SYSCALL_BASE @ check OS number adr tbl, sys_call_table @ load syscall table pointer tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? bne __sys_trace @@ -137,8 +147,8 @@ ENTRY(vector_swi) add r1, sp, #S_OFF 2: mov why, #0 @ no longer a real syscall - cmp scno, #ARMSWI_OFFSET - eor r0, scno, #OS_NUMBER << 20 @ put OS number back + cmp scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE) + eor r0, scno, #__NR_SYSCALL_BASE @ put OS number back bcs arm_syscall b sys_ni_syscall @ not private func @@ -183,7 +193,7 @@ ENTRY(sys_call_table) @ r5 = syscall table .type sys_syscall, #function sys_syscall: - eor scno, r0, #OS_NUMBER << 20 + eor scno, r0, #__NR_SYSCALL_BASE cmp scno, #__NR_syscall - __NR_SYSCALL_BASE cmpne scno, #NR_syscalls @ check range stmloia sp, {r5, r6} @ shuffle args diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 9d4d286..0eb7fc9 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -31,13 +31,6 @@ #define PT_TRACESYS 0x00000002 -@ OS version number used in SWIs -@ RISC OS is 0 -@ RISC iX is 8 -@ -#define OS_NUMBER 9 -#define ARMSWI_OFFSET 0x000f0000 - @ @ Most of the stack format comes from struct pt_regs, but with @ the addition of 8 bytes for storing syscall args 5 and 6. @@ -150,18 +143,3 @@ scno .req r7 @ syscall number tbl .req r8 @ syscall table pointer why .req r8 @ Linux syscall (!= 0) tsk .req r9 @ current thread_info - -/* - * Get the system call number. - */ - .macro get_scno -#ifdef CONFIG_ARM_THUMB - tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs - addne scno, r7, #OS_NUMBER << 20 @ put OS number in - ldreq scno, [lr, #-4] - -#else - mask_pc lr, lr - ldr scno, [lr, #-4] @ get SWI instruction -#endif - .endm -- cgit v0.10.2 From acaca3c91536491119e97d428c1da935f411cc9a Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:19:48 +0100 Subject: [PATCH] ARM: Remove SVC_MODE definition SVC_MODE reflects the MODE_SVC definition in asm/ptrace.h. Use the asm/ptrace.h definition instead, and remove SVC_MODE. Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index fc14289..4147056 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -545,7 +545,7 @@ vector_\name: @ mrs r13, cpsr bic r13, r13, #MODE_MASK - orr r13, r13, #MODE_SVC + orr r13, r13, #SVC_MODE msr spsr_cxsf, r13 @ switch to SVC_32 mode and lr, lr, #15 diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 0eb7fc9..5d8a845 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -8,10 +8,6 @@ #include #include -#ifndef MODE_SVC -#define MODE_SVC 0x13 -#endif - .macro zero_fp #ifdef CONFIG_FRAME_POINTER mov fp, #0 -- cgit v0.10.2 From cf88b417f9b1365c5aeeffa5c41208be68adfd76 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:20:12 +0100 Subject: [PATCH] ARM: remove PT_TRACESYS PT_TRACESYS is unused, remove it. Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 5d8a845..b7d54a4 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -25,8 +25,6 @@ #define BAD_IRQ 3 #define BAD_UNDEFINSTR 4 -#define PT_TRACESYS 0x00000002 - @ @ Most of the stack format comes from struct pt_regs, but with @ the addition of 8 bytes for storing syscall args 5 and 6. -- cgit v0.10.2 From f4dc9a4cf26278f5b608d6e4bd16e7b27ddcf1a5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:20:34 +0100 Subject: [PATCH] ARM: Remove single-use user save/restore macros Assembly macros are pointless if they're only used once. Move them inline. Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 65c58b3..07da010 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -27,7 +27,15 @@ ret_fast_syscall: ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne fast_work_pending - fast_restore_user_regs + + @ fast_restore_user_regs + ldr r1, [sp, #S_OFF + S_PSR] @ get calling cpsr + ldr lr, [sp, #S_OFF + S_PC]! @ get pc + msr spsr_cxsf, r1 @ save in spsr_svc + ldmdb sp, {r1 - lr}^ @ get calling r1 - lr + mov r0, r0 + add sp, sp, #S_FRAME_SIZE - S_PC + movs pc, lr @ return & move spsr_svc into cpsr /* * Ok, we need to do extra processing, enter the slow path. @@ -57,7 +65,14 @@ ret_slow_syscall: tst r1, #_TIF_WORK_MASK bne work_pending no_work_pending: - slow_restore_user_regs + @ slow_restore_user_regs + ldr r1, [sp, #S_PSR] @ get calling cpsr + ldr lr, [sp, #S_PC]! @ get pc + msr spsr_cxsf, r1 @ save in spsr_svc + ldmdb sp, {r0 - lr}^ @ get calling r1 - lr + mov r0, r0 + add sp, sp, #S_FRAME_SIZE - S_PC + movs pc, lr @ return & move spsr_svc into cpsr /* * This is how we return from a fork. @@ -109,7 +124,14 @@ ENTRY(ret_from_fork) .align 5 ENTRY(vector_swi) - save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0 - r12 + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ @ Calling sp, lr + mrs r8, spsr @ called from non-FIQ mode, so ok. + str lr, [sp, #S_PC] @ Save calling PC + str r8, [sp, #S_PSR] @ Save CPSR + str r0, [sp, #S_OLD_R0] @ Save OLD_R0 zero_fp /* diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index b7d54a4..956af0b 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -57,57 +57,6 @@ .endm #endif - .macro save_user_regs - sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - r12} @ Calling r0 - r12 - add r8, sp, #S_PC - stmdb r8, {sp, lr}^ @ Calling sp, lr - mrs r8, spsr @ called from non-FIQ mode, so ok. - str lr, [sp, #S_PC] @ Save calling PC - str r8, [sp, #S_PSR] @ Save CPSR - str r0, [sp, #S_OLD_R0] @ Save OLD_R0 - .endm - - .macro restore_user_regs - ldr r1, [sp, #S_PSR] @ Get calling cpsr - disable_irq ip @ disable IRQs - ldr lr, [sp, #S_PC]! @ Get PC - msr spsr_cxsf, r1 @ save in spsr_svc - ldmdb sp, {r0 - lr}^ @ Get calling r0 - lr - mov r0, r0 - add sp, sp, #S_FRAME_SIZE - S_PC - movs pc, lr @ return & move spsr_svc into cpsr - .endm - -/* - * Must be called with IRQs already disabled. - */ - .macro fast_restore_user_regs - ldr r1, [sp, #S_OFF + S_PSR] @ get calling cpsr - ldr lr, [sp, #S_OFF + S_PC]! @ get pc - msr spsr_cxsf, r1 @ save in spsr_svc - ldmdb sp, {r1 - lr}^ @ get calling r1 - lr - mov r0, r0 - add sp, sp, #S_FRAME_SIZE - S_PC - movs pc, lr @ return & move spsr_svc into cpsr - .endm - -/* - * Must be called with IRQs already disabled. - */ - .macro slow_restore_user_regs - ldr r1, [sp, #S_PSR] @ get calling cpsr - ldr lr, [sp, #S_PC]! @ get pc - msr spsr_cxsf, r1 @ save in spsr_svc - ldmdb sp, {r0 - lr}^ @ get calling r1 - lr - mov r0, r0 - add sp, sp, #S_FRAME_SIZE - S_PC - movs pc, lr @ return & move spsr_svc into cpsr - .endm - - .macro mask_pc, rd, rm - .endm - .macro get_thread_info, rd mov \rd, sp, lsr #13 mov \rd, \rd, lsl #13 -- cgit v0.10.2 From bce495d865829d7a1d8102a834d3e3af32616567 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:21:02 +0100 Subject: [PATCH] ARM: make entry*.S includes more logical Move common includes to entry-header, and file specific includes to the relevant file. Signed-off-by: Russell King diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 07a56ff..4a2af55 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -31,8 +31,3 @@ head-y := head.o obj-$(CONFIG_DEBUG_LL) += debug.o extra-y := $(head-y) init_task.o vmlinux.lds - -# Spell out some dependencies that aren't automatically figured out -$(obj)/entry-armv.o: $(obj)/entry-header.S include/asm-arm/constants.h -$(obj)/entry-common.o: $(obj)/entry-header.S include/asm-arm/constants.h \ - $(obj)/calls.S diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 4147056..2a5c3fe 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -14,12 +14,12 @@ * it to save wrong values... Be aware! */ #include -#include -#include #include -#include #include +#include @ should be moved into entry-macro.S +#include @ should be moved into entry-macro.S +#include #include "entry-header.S" diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 07da010..3f8d0e3 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -9,8 +9,6 @@ */ #include -#include -#include #include #include "entry-header.S" diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 956af0b..a3d40a0 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -1,20 +1,11 @@ -#include /* for CONFIG_ARCH_xxxx */ +#include +#include #include #include #include #include -#include -#include -#include - - .macro zero_fp -#ifdef CONFIG_FRAME_POINTER - mov fp, #0 -#endif - .endm - - .text +#include @ Bad Abort numbers @ ----------------- @@ -39,6 +30,12 @@ #error "Please fix" #endif + .macro zero_fp +#ifdef CONFIG_FRAME_POINTER + mov fp, #0 +#endif + .endm + #if __LINUX_ARM_ARCH__ >= 6 .macro disable_irq cpsid i -- cgit v0.10.2 From 45849282bfd7543253761cbf7db96151b05e5ed1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:29:44 +0100 Subject: [PATCH] Serial: Ensure error paths are marked with unlikely() Ensure ARM serial driver error paths are marked with the unlikely() compiler hint. Signed-off-by: Russell King diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index f8504b0..33fbda7 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -110,7 +110,7 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r port->icount.rx++; rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ; - if (rxs & RXSTAT_ANYERR) { + if (unlikely(rxs & RXSTAT_ANYERR)) { if (rxs & RXSTAT_PARITY) port->icount.parity++; else if (rxs & RXSTAT_FRAME) diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 484f6fb..f2a5e29 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -172,7 +172,7 @@ pl010_rx_chars(struct uart_port *port) * out of the main execution path */ rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX; - if (rsr & UART01x_RSR_ANY) { + if (unlikely(rsr & UART01x_RSR_ANY)) { if (rsr & UART01x_RSR_BE) { rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE); port->icount.brk++; diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index ff658a8..d5cbef3 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -137,7 +137,7 @@ pl011_rx_chars(struct uart_amba_port *uap) * out of the main execution path */ rsr = readw(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX; - if (rsr & UART01x_RSR_ANY) { + if (unlikely(rsr & UART01x_RSR_ANY)) { if (rsr & UART01x_RSR_BE) { rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE); uap->port.icount.brk++; diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index 16592fa..e145e19 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -116,7 +116,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re * Note that the error handling code is * out of the main execution path */ - if (ch & UART_ANY_ERR) + if (unlikely(ch & UART_ANY_ERR)) goto handle_error; if (uart_handle_sysrq_char(port, ch, regs)) diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index bd6782a..435750d 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -364,7 +364,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs) flag = TTY_NORMAL; port->icount.rx++; - if (uerstat & S3C2410_UERSTAT_ANY) { + if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) { dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n", ch, uerstat); diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index 4ce3a41..85cfa08 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c @@ -162,7 +162,7 @@ lh7a40xuart_rx_chars (struct uart_port* port) flag = TTY_NORMAL; ++port->icount.rx; - if (data & RxError) { /* Quick check, short-circuit */ + if (unlikely(data & RxError)) { /* Quick check, short-circuit */ if (data & RxBreak) { data &= ~(RxFramingError | RxParityError); ++port->icount.brk; -- cgit v0.10.2 From 2a9604b863c854e5bee409157aabb35b6ce8ecd3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:32:00 +0100 Subject: [PATCH] Serial: Move error path processing inline With unlikely() there's no need for the error path to use gotos. Signed-off-by: Russell King diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index e145e19..6242f30 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -116,54 +116,43 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re * Note that the error handling code is * out of the main execution path */ - if (unlikely(ch & UART_ANY_ERR)) - goto handle_error; + if (unlikely(ch & UART_ANY_ERR)) { + if (ch & UARTDR_PARERR) + port->icount.parity++; + else if (ch & UARTDR_FRMERR) + port->icount.frame++; + if (ch & UARTDR_OVERR) + port->icount.overrun++; - if (uart_handle_sysrq_char(port, ch, regs)) - goto ignore_char; + ch &= port->read_status_mask; - error_return: - tty_insert_flip_char(tty, ch, flg); - ignore_char: - status = clps_readl(SYSFLG(port)); - } - out: - tty_flip_buffer_push(tty); - return IRQ_HANDLED; + if (ch & UARTDR_PARERR) + flg = TTY_PARITY; + else if (ch & UARTDR_FRMERR) + flg = TTY_FRAME; - handle_error: - if (ch & UARTDR_PARERR) - port->icount.parity++; - else if (ch & UARTDR_FRMERR) - port->icount.frame++; - if (ch & UARTDR_OVERR) - port->icount.overrun++; - - if (ch & port->ignore_status_mask) { - if (++ignored > 100) - goto out; - goto ignore_char; - } - ch &= port->read_status_mask; +#ifdef SUPPORT_SYSRQ + port->sysrq = 0; +#endif + } - if (ch & UARTDR_PARERR) - flg = TTY_PARITY; - else if (ch & UARTDR_FRMERR) - flg = TTY_FRAME; + if (uart_handle_sysrq_char(port, ch, regs)) + goto ignore_char; - if (ch & UARTDR_OVERR) { /* * CHECK: does overrun affect the current character? * ASSUMPTION: it does not. */ - tty_insert_flip_char(tty, ch, flg); - ch = 0; - flg = TTY_OVERRUN; + if ((ch & port->ignore_status_mask & ~RXSTAT_OVERRUN) == 0) + tty_insert_flip_char(tty, ch, flg); + if ((ch & ~port->ignore_status_mask & RXSTAT_OVERRUN) == 0) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + ignore_char: + status = clps_readl(SYSFLG(port)); } -#ifdef SUPPORT_SYSRQ - port->sysrq = 0; -#endif - goto error_return; + tty_flip_buffer_push(tty); + return IRQ_HANDLED; } static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs) diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 0860652..157218b 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -214,56 +214,39 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs) * note that the error handling code is * out of the main execution path */ - if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) - goto handle_error; + if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) { + if (status & UTSR1_TO_SM(UTSR1_PRE)) + sport->port.icount.parity++; + else if (status & UTSR1_TO_SM(UTSR1_FRE)) + sport->port.icount.frame++; + if (status & UTSR1_TO_SM(UTSR1_ROR)) + sport->port.icount.overrun++; + + status &= sport->port.read_status_mask; + + if (status & UTSR1_TO_SM(UTSR1_PRE)) + flg = TTY_PARITY; + else if (status & UTSR1_TO_SM(UTSR1_FRE)) + flg = TTY_FRAME; + +#ifdef SUPPORT_SYSRQ + sport->port.sysrq = 0; +#endif + } if (uart_handle_sysrq_char(&sport->port, ch, regs)) goto ignore_char; - error_return: - tty_insert_flip_char(tty, ch, flg); + if ((status & port->ignore_status_mask & ~UTSR1_TO_SM(UTSR1_ROR)) == 0) + tty_insert_flip_char(tty, ch, flg); + if (status & ~port->ignore_status_mask & UTSR1_TO_SM(UTSR1_ROR)) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + ignore_char: status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | UTSR0_TO_SM(UART_GET_UTSR0(sport)); } - out: tty_flip_buffer_push(tty); - return; - - handle_error: - if (status & UTSR1_TO_SM(UTSR1_PRE)) - sport->port.icount.parity++; - else if (status & UTSR1_TO_SM(UTSR1_FRE)) - sport->port.icount.frame++; - if (status & UTSR1_TO_SM(UTSR1_ROR)) - sport->port.icount.overrun++; - - if (status & sport->port.ignore_status_mask) { - if (++ignored > 100) - goto out; - goto ignore_char; - } - - status &= sport->port.read_status_mask; - - if (status & UTSR1_TO_SM(UTSR1_PRE)) - flg = TTY_PARITY; - else if (status & UTSR1_TO_SM(UTSR1_FRE)) - flg = TTY_FRAME; - - if (status & UTSR1_TO_SM(UTSR1_ROR)) { - /* - * overrun does *not* affect the character - * we read from the FIFO - */ - tty_insert_flip_char(tty, ch, flg); - ch = 0; - flg = TTY_OVERRUN; - } -#ifdef SUPPORT_SYSRQ - sport->port.sysrq = 0; -#endif - goto error_return; } static void sa1100_tx_chars(struct sa1100_port *sport) -- cgit v0.10.2 From 2b49abac5855aff9b42cf2cdb5376ac805bebd86 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Apr 2005 15:37:45 +0100 Subject: [PATCH] Serial: Convert 8250_hp300 to use serial8250_{un,}register_port Convert 8250_hp300 to use serial8250_register_port() and serial8250_unregister_port(). Tested by Kars de Jong, 4/4/2005. Signed-off-by: Russell King diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c index b8d51eb..4315afe 100644 --- a/drivers/serial/8250_hp300.c +++ b/drivers/serial/8250_hp300.c @@ -9,15 +9,15 @@ #include #include #include -#include #include -#include #include #include #include #include #include +#include "8250.h" + #if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI) #warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure? #endif @@ -163,7 +163,7 @@ int __init hp300_setup_serial_console(void) static int __devinit hpdca_init_one(struct dio_dev *d, const struct dio_device_id *ent) { - struct serial_struct serial_req; + struct uart_port port; int line; #ifdef CONFIG_SERIAL_8250_CONSOLE @@ -172,21 +172,22 @@ static int __devinit hpdca_init_one(struct dio_dev *d, return 0; } #endif - memset(&serial_req, 0, sizeof(struct serial_struct)); + memset(&port, 0, sizeof(struct uart_port)); /* Memory mapped I/O */ - serial_req.io_type = SERIAL_IO_MEM; - serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; - serial_req.irq = d->ipl; - serial_req.baud_base = HPDCA_BAUD_BASE; - serial_req.iomap_base = (d->resource.start + UART_OFFSET); - serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE); - serial_req.iomem_reg_shift = 1; - line = register_serial(&serial_req); + port.iotype = UPIO_MEM; + port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; + port.irq = d->ipl; + port.uartclk = HPDCA_BAUD_BASE * 16; + port.mapbase = (d->resource.start + UART_OFFSET); + port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); + port.regshift = 1; + port.dev = &d->dev; + line = serial8250_register_port(&port); if (line < 0) { printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d" - " irq %d failed\n", d->scode, serial_req.irq); + " irq %d failed\n", d->scode, port.irq); return -ENOMEM; } @@ -209,7 +210,7 @@ static int __init hp300_8250_init(void) #ifdef CONFIG_HPAPCI int line; unsigned long base; - struct serial_struct serial_req; + struct uart_port uport; struct hp300_port *port; int i; #endif @@ -251,25 +252,25 @@ static int __init hp300_8250_init(void) if (!port) return -ENOMEM; - memset(&serial_req, 0, sizeof(struct serial_struct)); + memset(&uport, 0, sizeof(struct uart_port)); base = (FRODO_BASE + FRODO_APCI_OFFSET(i)); /* Memory mapped I/O */ - serial_req.io_type = SERIAL_IO_MEM; - serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; + uport.iotype = UPIO_MEM; + uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; /* XXX - no interrupt support yet */ - serial_req.irq = 0; - serial_req.baud_base = HPAPCI_BAUD_BASE; - serial_req.iomap_base = base; - serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE); - serial_req.iomem_reg_shift = 2; + uport.irq = 0; + uport.uartclk = HPAPCI_BAUD_BASE * 16; + uport.mapbase = base; + uport.membase = (char *)(base + DIO_VIRADDRBASE); + uport.regshift = 2; - line = register_serial(&serial_req); + line = serial8250_register_port(&uport); if (line < 0) { printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d" - " irq %d failed\n", i, serial_req.irq); + " irq %d failed\n", i, uport.irq); kfree(port); continue; } @@ -299,7 +300,7 @@ static void __devexit hpdca_remove_one(struct dio_dev *d) /* Disable board-interrupts */ out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0); } - unregister_serial(line); + serial8250_unregister_port(line); } #endif @@ -309,7 +310,7 @@ static void __exit hp300_8250_exit(void) struct hp300_port *port, *to_free; for (port = hp300_ports; port; ) { - unregister_serial(port->line); + serial8250_unregister_port(port->line); to_free = port; port = port->next; kfree(to_free); -- cgit v0.10.2 From 8cf381ca3c4a2410cea9615e205bc41bd4275e1e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 07:43:40 -0700 Subject: [PATCH] fix SND_POWERMAC dependencies This beast is pmac-only; moreover, it won't build on other subarchitectures. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig index b0a9ebf..75213bf 100644 --- a/sound/ppc/Kconfig +++ b/sound/ppc/Kconfig @@ -11,7 +11,7 @@ comment "ALSA PowerMac requires INPUT" config SND_POWERMAC tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)" - depends on SND && I2C && INPUT + depends on SND && I2C && INPUT && PPC_PMAC select SND_PCM help Say Y here to include support for the integrated sound device. -- cgit v0.10.2 From b76be681f8b296c00f707220b9891934d5d74778 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 07:43:41 -0700 Subject: [PATCH] tpm 64bit fixes (size_t) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index ca36087..8723533 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -143,7 +143,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, return -ENODATA; if (count > bufsiz) { dev_err(&chip->pci_dev->dev, - "invalid count value %x %x \n", count, bufsiz); + "invalid count value %x %zx \n", count, bufsiz); return -E2BIG; } @@ -151,7 +151,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, if ((len = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { dev_err(&chip->pci_dev->dev, - "tpm_transmit: tpm_send: error %d\n", len); + "tpm_transmit: tpm_send: error %zd\n", len); return len; } @@ -188,7 +188,7 @@ out_recv: len = chip->vendor->recv(chip, (u8 *) buf, bufsiz); if (len < 0) dev_err(&chip->pci_dev->dev, - "tpm_transmit: tpm_recv: error %d\n", len); + "tpm_transmit: tpm_recv: error %zd\n", len); up(&chip->tpm_mutex); return len; } -- cgit v0.10.2 From 9727d04aa6d58e131128b4178e742c423480d476 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 07:43:41 -0700 Subject: [PATCH] pegasus NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index a02be79..d976790 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -1388,11 +1388,11 @@ static int pegasus_resume (struct usb_interface *intf) if (netif_running(pegasus->net)) { pegasus->rx_urb->status = 0; pegasus->rx_urb->actual_length = 0; - read_bulk_callback(pegasus->rx_urb, 0); + read_bulk_callback(pegasus->rx_urb, NULL); pegasus->intr_urb->status = 0; pegasus->intr_urb->actual_length = 0; - intr_callback(pegasus->intr_urb, 0); + intr_callback(pegasus->intr_urb, NULL); queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, CARRIER_CHECK_DELAY); -- cgit v0.10.2 From 0d3e8fe662c31d614f809d0131e134e2692d6a68 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 07:43:41 -0700 Subject: [PATCH] savagefb iomem annotations trivial iomem annotations + memset() replaced with memset_io() in a place that deals with ioremapped area. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 5bb8d60..03d74e8 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -1498,7 +1498,7 @@ static int __devinit savage_map_mmio (struct fb_info *info) info->fix.mmio_start = par->mmio.pbase; info->fix.mmio_len = par->mmio.len; - par->bci_base = (u32*)(par->mmio.vbase + BCI_BUFFER_OFFSET); + par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET); par->bci_ptr = 0; savage_enable_mmio (par); @@ -1514,7 +1514,7 @@ static void __devinit savage_unmap_mmio (struct fb_info *info) savage_disable_mmio(par); if (par->mmio.vbase) { - iounmap ((void *)par->mmio.vbase); + iounmap(par->mmio.vbase); par->mmio.vbase = NULL; } } @@ -1553,7 +1553,7 @@ static int __devinit savage_map_video (struct fb_info *info, #endif /* Clear framebuffer, it's all white in memory after boot */ - memset (par->video.vbase, 0, par->video.len); + memset_io (par->video.vbase, 0, par->video.len); return 0; } -- cgit v0.10.2 From 66768eb26c471091dc4ea1ed59b4bab7edc3d7bd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 07:43:41 -0700 Subject: [PATCH] ppc-opc NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/xmon/ppc-opc.c b/arch/ppc64/xmon/ppc-opc.c index 1e4e7e3..5ee8fc3 100644 --- a/arch/ppc64/xmon/ppc-opc.c +++ b/arch/ppc64/xmon/ppc-opc.c @@ -20,6 +20,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include "nonstdio.h" #include "ppc.h" @@ -110,12 +111,12 @@ const struct powerpc_operand powerpc_operands[] = /* The zero index is used to indicate the end of the list of operands. */ #define UNUSED 0 - { 0, 0, 0, 0, 0 }, + { 0, 0, NULL, NULL, 0 }, /* The BA field in an XL form instruction. */ #define BA UNUSED + 1 #define BA_MASK (0x1f << 16) - { 5, 16, 0, 0, PPC_OPERAND_CR }, + { 5, 16, NULL, NULL, PPC_OPERAND_CR }, /* The BA field in an XL form instruction when it must be the same as the BT field in the same instruction. */ @@ -125,7 +126,7 @@ const struct powerpc_operand powerpc_operands[] = /* The BB field in an XL form instruction. */ #define BB BAT + 1 #define BB_MASK (0x1f << 11) - { 5, 11, 0, 0, PPC_OPERAND_CR }, + { 5, 11, NULL, NULL, PPC_OPERAND_CR }, /* The BB field in an XL form instruction when it must be the same as the BA field in the same instruction. */ @@ -168,21 +169,21 @@ const struct powerpc_operand powerpc_operands[] = /* The BF field in an X or XL form instruction. */ #define BF BDPA + 1 - { 3, 23, 0, 0, PPC_OPERAND_CR }, + { 3, 23, NULL, NULL, PPC_OPERAND_CR }, /* An optional BF field. This is used for comparison instructions, in which an omitted BF field is taken as zero. */ #define OBF BF + 1 - { 3, 23, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, + { 3, 23, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, /* The BFA field in an X or XL form instruction. */ #define BFA OBF + 1 - { 3, 18, 0, 0, PPC_OPERAND_CR }, + { 3, 18, NULL, NULL, PPC_OPERAND_CR }, /* The BI field in a B form or XL form instruction. */ #define BI BFA + 1 #define BI_MASK (0x1f << 16) - { 5, 16, 0, 0, PPC_OPERAND_CR }, + { 5, 16, NULL, NULL, PPC_OPERAND_CR }, /* The BO field in a B form instruction. Certain values are illegal. */ @@ -197,36 +198,36 @@ const struct powerpc_operand powerpc_operands[] = /* The BT field in an X or XL form instruction. */ #define BT BOE + 1 - { 5, 21, 0, 0, PPC_OPERAND_CR }, + { 5, 21, NULL, NULL, PPC_OPERAND_CR }, /* The condition register number portion of the BI field in a B form or XL form instruction. This is used for the extended conditional branch mnemonics, which set the lower two bits of the BI field. This field is optional. */ #define CR BT + 1 - { 3, 18, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, + { 3, 18, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, /* The CRB field in an X form instruction. */ #define CRB CR + 1 - { 5, 6, 0, 0, 0 }, + { 5, 6, NULL, NULL, 0 }, /* The CRFD field in an X form instruction. */ #define CRFD CRB + 1 - { 3, 23, 0, 0, PPC_OPERAND_CR }, + { 3, 23, NULL, NULL, PPC_OPERAND_CR }, /* The CRFS field in an X form instruction. */ #define CRFS CRFD + 1 - { 3, 0, 0, 0, PPC_OPERAND_CR }, + { 3, 0, NULL, NULL, PPC_OPERAND_CR }, /* The CT field in an X form instruction. */ #define CT CRFS + 1 - { 5, 21, 0, 0, PPC_OPERAND_OPTIONAL }, + { 5, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, /* The D field in a D form instruction. This is a displacement off a register, and implies that the next operand is a register in parentheses. */ #define D CT + 1 - { 16, 0, 0, 0, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + { 16, 0, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, /* The DE field in a DE form instruction. This is like D, but is 12 bits only. */ @@ -252,40 +253,40 @@ const struct powerpc_operand powerpc_operands[] = /* The E field in a wrteei instruction. */ #define E DS + 1 - { 1, 15, 0, 0, 0 }, + { 1, 15, NULL, NULL, 0 }, /* The FL1 field in a POWER SC form instruction. */ #define FL1 E + 1 - { 4, 12, 0, 0, 0 }, + { 4, 12, NULL, NULL, 0 }, /* The FL2 field in a POWER SC form instruction. */ #define FL2 FL1 + 1 - { 3, 2, 0, 0, 0 }, + { 3, 2, NULL, NULL, 0 }, /* The FLM field in an XFL form instruction. */ #define FLM FL2 + 1 - { 8, 17, 0, 0, 0 }, + { 8, 17, NULL, NULL, 0 }, /* The FRA field in an X or A form instruction. */ #define FRA FLM + 1 #define FRA_MASK (0x1f << 16) - { 5, 16, 0, 0, PPC_OPERAND_FPR }, + { 5, 16, NULL, NULL, PPC_OPERAND_FPR }, /* The FRB field in an X or A form instruction. */ #define FRB FRA + 1 #define FRB_MASK (0x1f << 11) - { 5, 11, 0, 0, PPC_OPERAND_FPR }, + { 5, 11, NULL, NULL, PPC_OPERAND_FPR }, /* The FRC field in an A form instruction. */ #define FRC FRB + 1 #define FRC_MASK (0x1f << 6) - { 5, 6, 0, 0, PPC_OPERAND_FPR }, + { 5, 6, NULL, NULL, PPC_OPERAND_FPR }, /* The FRS field in an X form instruction or the FRT field in a D, X or A form instruction. */ #define FRS FRC + 1 #define FRT FRS - { 5, 21, 0, 0, PPC_OPERAND_FPR }, + { 5, 21, NULL, NULL, PPC_OPERAND_FPR }, /* The FXM field in an XFX instruction. */ #define FXM FRS + 1 @@ -298,11 +299,11 @@ const struct powerpc_operand powerpc_operands[] = /* The L field in a D or X form instruction. */ #define L FXM4 + 1 - { 1, 21, 0, 0, PPC_OPERAND_OPTIONAL }, + { 1, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, /* The LEV field in a POWER SC form instruction. */ #define LEV L + 1 - { 7, 5, 0, 0, 0 }, + { 7, 5, NULL, NULL, 0 }, /* The LI field in an I form instruction. The lower two bits are forced to zero. */ @@ -316,24 +317,24 @@ const struct powerpc_operand powerpc_operands[] = /* The LS field in an X (sync) form instruction. */ #define LS LIA + 1 - { 2, 21, 0, 0, PPC_OPERAND_OPTIONAL }, + { 2, 21, NULL, NULL, PPC_OPERAND_OPTIONAL }, /* The MB field in an M form instruction. */ #define MB LS + 1 #define MB_MASK (0x1f << 6) - { 5, 6, 0, 0, 0 }, + { 5, 6, NULL, NULL, 0 }, /* The ME field in an M form instruction. */ #define ME MB + 1 #define ME_MASK (0x1f << 1) - { 5, 1, 0, 0, 0 }, + { 5, 1, NULL, NULL, 0 }, /* The MB and ME fields in an M form instruction expressed a single operand which is a bitmask indicating which bits to select. This is a two operand form using PPC_OPERAND_NEXT. See the description in opcode/ppc.h for what this means. */ #define MBE ME + 1 - { 5, 6, 0, 0, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT }, + { 5, 6, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT }, { 32, 0, insert_mbe, extract_mbe, 0 }, /* The MB or ME field in an MD or MDS form instruction. The high @@ -345,7 +346,7 @@ const struct powerpc_operand powerpc_operands[] = /* The MO field in an mbar instruction. */ #define MO MB6 + 1 - { 5, 21, 0, 0, 0 }, + { 5, 21, NULL, NULL, 0 }, /* The NB field in an X form instruction. The value 32 is stored as 0. */ @@ -361,34 +362,34 @@ const struct powerpc_operand powerpc_operands[] = /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction. */ #define RA NSI + 1 #define RA_MASK (0x1f << 16) - { 5, 16, 0, 0, PPC_OPERAND_GPR }, + { 5, 16, NULL, NULL, PPC_OPERAND_GPR }, /* The RA field in the DQ form lq instruction, which has special value restrictions. */ #define RAQ RA + 1 - { 5, 16, insert_raq, 0, PPC_OPERAND_GPR }, + { 5, 16, insert_raq, NULL, PPC_OPERAND_GPR }, /* The RA field in a D or X form instruction which is an updating load, which means that the RA field may not be zero and may not equal the RT field. */ #define RAL RAQ + 1 - { 5, 16, insert_ral, 0, PPC_OPERAND_GPR }, + { 5, 16, insert_ral, NULL, PPC_OPERAND_GPR }, /* The RA field in an lmw instruction, which has special value restrictions. */ #define RAM RAL + 1 - { 5, 16, insert_ram, 0, PPC_OPERAND_GPR }, + { 5, 16, insert_ram, NULL, PPC_OPERAND_GPR }, /* The RA field in a D or X form instruction which is an updating store or an updating floating point load, which means that the RA field may not be zero. */ #define RAS RAM + 1 - { 5, 16, insert_ras, 0, PPC_OPERAND_GPR }, + { 5, 16, insert_ras, NULL, PPC_OPERAND_GPR }, /* The RB field in an X, XO, M, or MDS form instruction. */ #define RB RAS + 1 #define RB_MASK (0x1f << 11) - { 5, 11, 0, 0, PPC_OPERAND_GPR }, + { 5, 11, NULL, NULL, PPC_OPERAND_GPR }, /* The RB field in an X form instruction when it must be the same as the RS field in the instruction. This is used for extended @@ -402,22 +403,22 @@ const struct powerpc_operand powerpc_operands[] = #define RS RBS + 1 #define RT RS #define RT_MASK (0x1f << 21) - { 5, 21, 0, 0, PPC_OPERAND_GPR }, + { 5, 21, NULL, NULL, PPC_OPERAND_GPR }, /* The RS field of the DS form stq instruction, which has special value restrictions. */ #define RSQ RS + 1 - { 5, 21, insert_rsq, 0, PPC_OPERAND_GPR }, + { 5, 21, insert_rsq, NULL, PPC_OPERAND_GPR }, /* The RT field of the DQ form lq instruction, which has special value restrictions. */ #define RTQ RSQ + 1 - { 5, 21, insert_rtq, 0, PPC_OPERAND_GPR }, + { 5, 21, insert_rtq, NULL, PPC_OPERAND_GPR }, /* The SH field in an X or M form instruction. */ #define SH RTQ + 1 #define SH_MASK (0x1f << 11) - { 5, 11, 0, 0, 0 }, + { 5, 11, NULL, NULL, 0 }, /* The SH field in an MD form instruction. This is split. */ #define SH6 SH + 1 @@ -426,12 +427,12 @@ const struct powerpc_operand powerpc_operands[] = /* The SI field in a D form instruction. */ #define SI SH6 + 1 - { 16, 0, 0, 0, PPC_OPERAND_SIGNED }, + { 16, 0, NULL, NULL, PPC_OPERAND_SIGNED }, /* The SI field in a D form instruction when we accept a wide range of positive values. */ #define SISIGNOPT SI + 1 - { 16, 0, 0, 0, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT }, + { 16, 0, NULL, NULL, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT }, /* The SPR field in an XFX form instruction. This is flipped--the lower 5 bits are stored in the upper 5 and vice- versa. */ @@ -443,25 +444,25 @@ const struct powerpc_operand powerpc_operands[] = /* The BAT index number in an XFX form m[ft]ibat[lu] instruction. */ #define SPRBAT SPR + 1 #define SPRBAT_MASK (0x3 << 17) - { 2, 17, 0, 0, 0 }, + { 2, 17, NULL, NULL, 0 }, /* The SPRG register number in an XFX form m[ft]sprg instruction. */ #define SPRG SPRBAT + 1 #define SPRG_MASK (0x3 << 16) - { 2, 16, 0, 0, 0 }, + { 2, 16, NULL, NULL, 0 }, /* The SR field in an X form instruction. */ #define SR SPRG + 1 - { 4, 16, 0, 0, 0 }, + { 4, 16, NULL, NULL, 0 }, /* The STRM field in an X AltiVec form instruction. */ #define STRM SR + 1 #define STRM_MASK (0x3 << 21) - { 2, 21, 0, 0, 0 }, + { 2, 21, NULL, NULL, 0 }, /* The SV field in a POWER SC form instruction. */ #define SV STRM + 1 - { 14, 2, 0, 0, 0 }, + { 14, 2, NULL, NULL, 0 }, /* The TBR field in an XFX form instruction. This is like the SPR field, but it is optional. */ @@ -471,52 +472,52 @@ const struct powerpc_operand powerpc_operands[] = /* The TO field in a D or X form instruction. */ #define TO TBR + 1 #define TO_MASK (0x1f << 21) - { 5, 21, 0, 0, 0 }, + { 5, 21, NULL, NULL, 0 }, /* The U field in an X form instruction. */ #define U TO + 1 - { 4, 12, 0, 0, 0 }, + { 4, 12, NULL, NULL, 0 }, /* The UI field in a D form instruction. */ #define UI U + 1 - { 16, 0, 0, 0, 0 }, + { 16, 0, NULL, NULL, 0 }, /* The VA field in a VA, VX or VXR form instruction. */ #define VA UI + 1 #define VA_MASK (0x1f << 16) - { 5, 16, 0, 0, PPC_OPERAND_VR }, + { 5, 16, NULL, NULL, PPC_OPERAND_VR }, /* The VB field in a VA, VX or VXR form instruction. */ #define VB VA + 1 #define VB_MASK (0x1f << 11) - { 5, 11, 0, 0, PPC_OPERAND_VR }, + { 5, 11, NULL, NULL, PPC_OPERAND_VR }, /* The VC field in a VA form instruction. */ #define VC VB + 1 #define VC_MASK (0x1f << 6) - { 5, 6, 0, 0, PPC_OPERAND_VR }, + { 5, 6, NULL, NULL, PPC_OPERAND_VR }, /* The VD or VS field in a VA, VX, VXR or X form instruction. */ #define VD VC + 1 #define VS VD #define VD_MASK (0x1f << 21) - { 5, 21, 0, 0, PPC_OPERAND_VR }, + { 5, 21, NULL, NULL, PPC_OPERAND_VR }, /* The SIMM field in a VX form instruction. */ #define SIMM VD + 1 - { 5, 16, 0, 0, PPC_OPERAND_SIGNED}, + { 5, 16, NULL, NULL, PPC_OPERAND_SIGNED}, /* The UIMM field in a VX form instruction. */ #define UIMM SIMM + 1 - { 5, 16, 0, 0, 0 }, + { 5, 16, NULL, NULL, 0 }, /* The SHB field in a VA form instruction. */ #define SHB UIMM + 1 - { 4, 6, 0, 0, 0 }, + { 4, 6, NULL, NULL, 0 }, /* The other UIMM field in a EVX form instruction. */ #define EVUIMM SHB + 1 - { 5, 11, 0, 0, 0 }, + { 5, 11, NULL, NULL, 0 }, /* The other UIMM field in a half word EVX form instruction. */ #define EVUIMM_2 EVUIMM + 1 @@ -533,11 +534,11 @@ const struct powerpc_operand powerpc_operands[] = /* The WS field. */ #define WS EVUIMM_8 + 1 #define WS_MASK (0x7 << 11) - { 3, 11, 0, 0, 0 }, + { 3, 11, NULL, NULL, 0 }, /* The L field in an mtmsrd instruction */ #define MTMSRD_L WS + 1 - { 1, 16, 0, 0, PPC_OPERAND_OPTIONAL }, + { 1, 16, NULL, NULL, PPC_OPERAND_OPTIONAL }, }; -- cgit v0.10.2 From f815e8182b94f8fb5913b66454b40b484a2f70cc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 07:43:42 -0700 Subject: [PATCH] imsttfb missing iomem annotations write_reg_le32() and read_reg_le32() expect iomem pointers... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 5a72ca3..7b9bf45 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -1287,12 +1287,12 @@ imsttfb_ioctl(struct inode *inode, struct file *file, u_int cmd, case FBIMSTT_SETCMAPREG: if (copy_from_user(reg, argp, 8) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0])) return -EFAULT; - write_reg_le32(((u_int *)par->cmap_regs), reg[0], reg[1]); + write_reg_le32(((u_int __iomem *)par->cmap_regs), reg[0], reg[1]); return 0; case FBIMSTT_GETCMAPREG: if (copy_from_user(reg, argp, 4) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0])) return -EFAULT; - reg[1] = read_reg_le32(((u_int *)par->cmap_regs), reg[0]); + reg[1] = read_reg_le32(((u_int __iomem *)par->cmap_regs), reg[0]); if (copy_to_user((void __user *)(arg + 4), ®[1], 4)) return -EFAULT; return 0; -- cgit v0.10.2 From 0f73832fd8fc42dd7cc73487147f5d5b8f8d2cf0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 07:43:42 -0700 Subject: [PATCH] drivers/scsi NULL noise removal NULL noise in sbus scsi drivers got missed Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 891f97f..f690053 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -1147,7 +1147,7 @@ static int __init esp_detect(struct scsi_host_template *tpnt) static struct sbus_dev esp_dev; int esps_in_use = 0; - espchain = 0; + espchain = NULL; if (sun4_esp_physaddr) { memset (&esp_dev, 0, sizeof(esp_dev)); @@ -2513,7 +2513,7 @@ static inline void esp_reconnect(struct esp *esp, struct scsi_cmnd *sp) ESPLOG(("esp%d: Weird, being reselected but disconnected " "command queue is empty.\n", esp->esp_id)); esp->snip = 0; - esp->current_SC = 0; + esp->current_SC = NULL; sp->SCp.phase = not_issued; append_SC(&esp->issue_SC, sp); } @@ -4148,7 +4148,7 @@ static int esp_work_bus(struct esp *esp) } static espfunc_t isvc_vector[] = { - 0, + NULL, esp_do_phase_determine, esp_do_resetbus, esp_finish_reset, diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c index 7bb0a2e..c01b719 100644 --- a/drivers/scsi/pluto.c +++ b/drivers/scsi/pluto.c @@ -45,7 +45,7 @@ static struct ctrl_inquiry { Scsi_Cmnd cmd; char inquiry[256]; fc_channel *fc; -} *fcs __initdata = { 0 }; +} *fcs __initdata; static int fcscount __initdata = 0; static atomic_t fcss __initdata = ATOMIC_INIT(0); DECLARE_MUTEX_LOCKED(fc_sem); -- cgit v0.10.2 From 993fb38b1c0cd1a56d15aa99b337c780a538baa8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 07:43:42 -0700 Subject: [PATCH] amd64 rt_sigframe user annotation ->pretcode in struct rt_sigframe is a userland pointer (and already treated as such by code using that field). Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index 7760224..d439ced 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -83,7 +83,7 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct rt_sigframe { - char *pretcode; + char __user *pretcode; struct ucontext uc; struct siginfo info; }; -- cgit v0.10.2 From 9be80c0f0f61e8c0572d7c9d73b3ef839754a953 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 07:43:42 -0700 Subject: [PATCH] oprofile trivial user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 9abedea..a72006c 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -18,13 +18,13 @@ unsigned long fs_buffer_size = 131072; unsigned long fs_cpu_buffer_size = 8192; unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */ -static ssize_t depth_read(struct file * file, char * buf, size_t count, loff_t * offset) +static ssize_t depth_read(struct file * file, char __user * buf, size_t count, loff_t * offset) { return oprofilefs_ulong_to_user(backtrace_depth, buf, count, offset); } -static ssize_t depth_write(struct file * file, char const * buf, size_t count, loff_t * offset) +static ssize_t depth_write(struct file * file, char const __user * buf, size_t count, loff_t * offset) { unsigned long val; int retval; -- cgit v0.10.2 From 766f2fa170e65948053b06c6106c8dc8526c3e14 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 07:43:43 -0700 Subject: [PATCH] qla trivial iomem annotation Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 0e75fbb..32583bb 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -85,7 +85,7 @@ qla2x00_unlock_nvram_access(scsi_qla_host_t *ha) void qla2x00_release_nvram_protection(scsi_qla_host_t *ha) { - device_reg_t *reg; + device_reg_t __iomem *reg; uint32_t word; reg = ha->iobase; -- cgit v0.10.2 From 2d29306b231a1a0e7a70166c10e4c0f917b21334 Mon Sep 17 00:00:00 2001 From: Martin Hicks Date: Tue, 26 Apr 2005 09:04:31 -0700 Subject: [IA64] re-enable preempt before page allocation for pgtable quicklist This is a fix to the pgtable_quicklist code. There is a GFP_KERNEL allocation in pgtable_quicklist_alloc(), which spews the usual warnings if the kernel is under heavy VM pressure and the reclaim code is invoked. re-enable preempt before we allocate the new page. This patch is against 2.6.12-rc2-mm2 Signed-off-by: Martin Hicks Signed-off-by: Tony Luck diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h index 2b71273..a5f2145 100644 --- a/include/asm-ia64/pgalloc.h +++ b/include/asm-ia64/pgalloc.h @@ -49,12 +49,12 @@ static inline void *pgtable_quicklist_alloc(void) pgtable_quicklist = (unsigned long *)(*ret); ret[0] = 0; --pgtable_quicklist_size; + preempt_enable(); } else { + preempt_enable(); ret = (unsigned long *)__get_free_page(GFP_KERNEL | __GFP_ZERO); } - preempt_enable(); - return ret; } -- cgit v0.10.2 From 5330e9273e2b3e372b01bb1cb75be4364f02db78 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 11:26:53 -0700 Subject: [PATCH] size_t portability fixes - drivers/usb size_t is zu, ssize_t is zd... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c index c3c3e5a..c53e226 100644 --- a/drivers/usb/media/pwc/pwc-if.c +++ b/drivers/usb/media/pwc/pwc-if.c @@ -322,7 +322,7 @@ static int pwc_allocate_buffers(struct pwc_device *pdev) case 730: case 740: case 750: - Trace(TRACE_MEMORY,"private_data(%Zd)\n",sizeof(struct pwc_dec23_private)); + Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private)); kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */ break; case 645: @@ -1179,7 +1179,7 @@ static ssize_t pwc_video_read(struct file *file, char __user * buf, DECLARE_WAITQUEUE(wait, current); int bytes_to_read; - Trace(TRACE_READ, "video_read(0x%p, %p, %Zd) called.\n", vdev, buf, count); + Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count); if (vdev == NULL) return -EFAULT; pdev = vdev->priv; diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 4bdbd0c..2fd1226 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -983,7 +983,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, msgcount++; if (msgcount < 500) printk(KERN_ERR - "sisusbvga[%d]: Wrote %Zd of " + "sisusbvga[%d]: Wrote %zd of " "%d bytes, error %d\n", sisusb->minor, *bytes_written, length, ret); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 1748159..a45ea7c 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -431,7 +431,7 @@ static void skb_return (struct usbnet *dev, struct sk_buff *skb) dev->stats.rx_bytes += skb->len; if (netif_msg_rx_status (dev)) - devdbg (dev, "< rx, len %zd, type 0x%x", + devdbg (dev, "< rx, len %zu, type 0x%x", skb->len + sizeof (struct ethhdr), skb->protocol); memset (skb->cb, 0, sizeof (struct skb_data)); status = netif_rx (skb); -- cgit v0.10.2 From efa545791ff439d778f79d02255d59ff1f7ea0fc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Apr 2005 11:26:53 -0700 Subject: [PATCH] ppc64: trivial user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/rtas_flash.c b/arch/ppc64/kernel/rtas_flash.c index 3213837..923e2e2 100644 --- a/arch/ppc64/kernel/rtas_flash.c +++ b/arch/ppc64/kernel/rtas_flash.c @@ -218,7 +218,7 @@ static void get_flash_status_msg(int status, char *buf) } /* Reading the proc file will show status (not the firmware contents) */ -static ssize_t rtas_flash_read(struct file *file, char *buf, +static ssize_t rtas_flash_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); @@ -256,7 +256,7 @@ static ssize_t rtas_flash_read(struct file *file, char *buf, * count is. If the system is low on memory it will be just as well * that we fail.... */ -static ssize_t rtas_flash_write(struct file *file, const char *buffer, +static ssize_t rtas_flash_write(struct file *file, const char __user *buffer, size_t count, loff_t *off) { struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); @@ -356,7 +356,7 @@ static void manage_flash(struct rtas_manage_flash_t *args_buf) args_buf->status = rc; } -static ssize_t manage_flash_read(struct file *file, char *buf, +static ssize_t manage_flash_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); @@ -386,7 +386,7 @@ static ssize_t manage_flash_read(struct file *file, char *buf, return msglen; } -static ssize_t manage_flash_write(struct file *file, const char *buf, +static ssize_t manage_flash_write(struct file *file, const char __user *buf, size_t count, loff_t *off) { struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); @@ -466,7 +466,7 @@ static int get_validate_flash_msg(struct rtas_validate_flash_t *args_buf, return n; } -static ssize_t validate_flash_read(struct file *file, char *buf, +static ssize_t validate_flash_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); @@ -494,7 +494,7 @@ static ssize_t validate_flash_read(struct file *file, char *buf, return msglen; } -static ssize_t validate_flash_write(struct file *file, const char *buf, +static ssize_t validate_flash_write(struct file *file, const char __user *buf, size_t count, loff_t *off) { struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); diff --git a/arch/ppc64/kernel/scanlog.c b/arch/ppc64/kernel/scanlog.c index 189b81a..4d70736 100644 --- a/arch/ppc64/kernel/scanlog.c +++ b/arch/ppc64/kernel/scanlog.c @@ -43,7 +43,7 @@ static int scanlog_debug; static unsigned int ibm_scan_log_dump; /* RTAS token */ static struct proc_dir_entry *proc_ppc64_scan_log_dump; /* The proc file */ -static ssize_t scanlog_read(struct file *file, char *buf, +static ssize_t scanlog_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct inode * inode = file->f_dentry->d_inode; @@ -129,7 +129,7 @@ static ssize_t scanlog_read(struct file *file, char *buf, /*NOTREACHED*/ } -static ssize_t scanlog_write(struct file * file, const char * buf, +static ssize_t scanlog_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { char stkbuf[20]; -- cgit v0.10.2 From e8108c98dd6d65613fa0ec9d2300f89c48d554bf Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Tue, 26 Apr 2005 13:09:35 -0700 Subject: [PATCH] PC300 pci_enable_device fix Call pci_enable_device() before looking at IRQ and resources, and pci_disable_device() when shutting the interface down. The driver requires this fix or the "pci=routeirq" workaround on 2.6.10 and later kernels. Reported and tested by Artur Lipowski. From: Bjorn Helgaas Signed-off-by: Marcelo Tosatti Signed-off-by: Linus Torvalds diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index d67be25..3e7753b 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -3427,7 +3427,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int first_time = 1; ucchar cpc_rev_id; - int err = 0, eeprom_outdated = 0; + int err, eeprom_outdated = 0; ucshort device_id; pc300_t *card; @@ -3439,15 +3439,21 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) #endif } + if ((err = pci_enable_device(pdev)) < 0) + return err; + card = (pc300_t *) kmalloc(sizeof(pc300_t), GFP_KERNEL); if (card == NULL) { printk("PC300 found at RAM 0x%08lx, " "but could not allocate card structure.\n", pci_resource_start(pdev, 3)); - return -ENOMEM; + err = -ENOMEM; + goto err_disable_dev; } memset(card, 0, sizeof(pc300_t)); + err = -ENODEV; + /* read PCI configuration area */ device_id = ent->device; card->hw.irq = pdev->irq; @@ -3507,7 +3513,6 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) printk("PC300 found at RAM 0x%08x, " "but could not allocate PLX mem region.\n", card->hw.ramphys); - err = -ENODEV; goto err_release_io; } if (!request_mem_region(card->hw.ramphys, card->hw.alloc_ramsize, @@ -3515,7 +3520,6 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) printk("PC300 found at RAM 0x%08x, " "but could not allocate RAM mem region.\n", card->hw.ramphys); - err = -ENODEV; goto err_release_plx; } if (!request_mem_region(card->hw.scaphys, card->hw.scasize, @@ -3523,13 +3527,9 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) printk("PC300 found at RAM 0x%08x, " "but could not allocate SCA mem region.\n", card->hw.ramphys); - err = -ENODEV; goto err_release_ram; } - if ((err = pci_enable_device(pdev)) != 0) - goto err_release_sca; - card->hw.plxbase = ioremap(card->hw.plxphys, card->hw.plxsize); card->hw.rambase = ioremap(card->hw.ramphys, card->hw.alloc_ramsize); card->hw.scabase = ioremap(card->hw.scaphys, card->hw.scasize); @@ -3619,7 +3619,6 @@ err_io_unmap: iounmap(card->hw.falcbase); release_mem_region(card->hw.falcphys, card->hw.falcsize); } -err_release_sca: release_mem_region(card->hw.scaphys, card->hw.scasize); err_release_ram: release_mem_region(card->hw.ramphys, card->hw.alloc_ramsize); @@ -3628,7 +3627,9 @@ err_release_plx: err_release_io: release_region(card->hw.iophys, card->hw.iosize); kfree(card); - return -ENODEV; +err_disable_dev: + pci_disable_device(pdev); + return err; } static void __devexit cpc_remove_one(struct pci_dev *pdev) @@ -3662,6 +3663,7 @@ static void __devexit cpc_remove_one(struct pci_dev *pdev) if (card->hw.irq) free_irq(card->hw.irq, card); kfree(card); + pci_disable_device(pdev); } } -- cgit v0.10.2 From 036d618434516103adb4d36db28a57968d2f2e7b Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Tue, 26 Apr 2005 22:54:58 -0700 Subject: [SCSI] aacraid: Fix adapter open error This fixes an error on the device open code that allows a non-existent device to be opened causing later panic problems. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index c9b8268..242fa77 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -450,7 +450,7 @@ static int aac_cfg_open(struct inode *inode, struct file *file) } } - return 0; + return err; } /** -- cgit v0.10.2 From ea3f4eaca09de1bcc80e922e56a6dabba5882f56 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 27 Apr 2005 18:19:55 +0100 Subject: [PATCH] ARM: Add further explaination for clk_get() clk_get() comments can be confusing. Add extra explaination of the dev and id parameters to ensure correct usage. Signed-off-by: Russell King diff --git a/include/asm-arm/hardware/clock.h b/include/asm-arm/hardware/clock.h index 4983449..19da861 100644 --- a/include/asm-arm/hardware/clock.h +++ b/include/asm-arm/hardware/clock.h @@ -26,10 +26,13 @@ struct clk; /** * clk_get - lookup and obtain a reference to a clock producer. * @dev: device for clock "consumer" - * @id: device ID + * @id: clock comsumer ID * * Returns a struct clk corresponding to the clock producer, or - * valid IS_ERR() condition containing errno. + * valid IS_ERR() condition containing errno. The implementation + * uses @dev and @id to determine the clock consumer, and thereby + * the clock producer. (IOW, @id may be identical strings, but + * clk_get may return different clock producers depending on @dev.) */ struct clk *clk_get(struct device *dev, const char *id); -- cgit v0.10.2 From 5fc3e624ad7278604628c598e92aa77c67064166 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 27 Apr 2005 15:39:03 -0700 Subject: [PATCH] NFS4: Don't use __user with compat_uptr_t The attached patch removes __user from compat_uptr_t types in the NFS4 mount 32-bit->64-bit compatibility structures. Signed-Off-By: David Howells Signed-off-by: Linus Torvalds diff --git a/fs/compat.c b/fs/compat.c index 67c0b94..728cd83 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -809,7 +809,7 @@ static void *do_smb_super_data_conv(void *raw_data) struct compat_nfs_string { compat_uint_t len; - compat_uptr_t __user data; + compat_uptr_t data; }; static inline void compat_nfs_string(struct nfs_string *dst, @@ -834,10 +834,10 @@ struct compat_nfs4_mount_data_v1 { struct compat_nfs_string mnt_path; struct compat_nfs_string hostname; compat_uint_t host_addrlen; - compat_uptr_t __user host_addr; + compat_uptr_t host_addr; compat_int_t proto; compat_int_t auth_flavourlen; - compat_uptr_t __user auth_flavours; + compat_uptr_t auth_flavours; }; static int do_nfs4_super_data_conv(void *raw_data) -- cgit v0.10.2 From bdceb6a0162274934386f19f3ea5a9d44feb0b20 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Apr 2005 18:04:45 -0700 Subject: [PATCH] ppc64: Fix return value of some vDSO calls The ppc vDSO would not properly clear the return value for some calls, which will be a problem when interfacing those calls with glibc. This should be fixed before 2.6.12 is released (as it is the first kernel with the ppc vDSO) so that we don't have to play with symbol versioning and ugly workarounds. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/vdso32/cacheflush.S b/arch/ppc64/kernel/vdso32/cacheflush.S index c74fddb..0ed7ea7 100644 --- a/arch/ppc64/kernel/vdso32/cacheflush.S +++ b/arch/ppc64/kernel/vdso32/cacheflush.S @@ -47,6 +47,7 @@ V_FUNCTION_BEGIN(__kernel_sync_dicache) addi r6,r6,128 bdnz 1b isync + li r3,0 blr .cfi_endproc V_FUNCTION_END(__kernel_sync_dicache) @@ -59,6 +60,7 @@ V_FUNCTION_BEGIN(__kernel_sync_dicache_p5) .cfi_startproc sync isync + li r3,0 blr .cfi_endproc V_FUNCTION_END(__kernel_sync_dicache_p5) diff --git a/arch/ppc64/kernel/vdso32/gettimeofday.S b/arch/ppc64/kernel/vdso32/gettimeofday.S index ca7f415..2b48bf1 100644 --- a/arch/ppc64/kernel/vdso32/gettimeofday.S +++ b/arch/ppc64/kernel/vdso32/gettimeofday.S @@ -58,6 +58,7 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday) stw r5,TZONE_TZ_DSTTIME(r11) 1: mtlr r12 + li r3,0 blr 2: mr r3,r10 diff --git a/arch/ppc64/kernel/vdso64/cacheflush.S b/arch/ppc64/kernel/vdso64/cacheflush.S index d9696ff..e0725b7 100644 --- a/arch/ppc64/kernel/vdso64/cacheflush.S +++ b/arch/ppc64/kernel/vdso64/cacheflush.S @@ -47,6 +47,7 @@ V_FUNCTION_BEGIN(__kernel_sync_dicache) addi r6,r6,128 bdnz 1b isync + li r3,0 blr .cfi_endproc V_FUNCTION_END(__kernel_sync_dicache) @@ -59,6 +60,7 @@ V_FUNCTION_BEGIN(__kernel_sync_dicache_p5) .cfi_startproc sync isync + li r3,0 blr .cfi_endproc V_FUNCTION_END(__kernel_sync_dicache_p5) -- cgit v0.10.2 From c4d12b98ead8bb2437f656c17e7ef065fa160e13 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 28 Apr 2005 10:38:19 +0100 Subject: [PATCH] ARM: Fix AMBA CLCD fb driver for 1bpp/STN mono panels Fix the AMBA CLCD framebuffer driver for 1bpp modes and STN monochrome LCD panels. Signed-off-by: Russell King diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index acdba0c..075d396 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -125,11 +125,11 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) case 2: case 4: case 8: - var->red.length = 8; + var->red.length = var->bits_per_pixel; var->red.offset = 0; - var->green.length = 8; + var->green.length = var->bits_per_pixel; var->green.offset = 0; - var->blue.length = 8; + var->blue.length = var->bits_per_pixel; var->blue.offset = 0; break; case 16: diff --git a/include/asm-arm/hardware/amba_clcd.h b/include/asm-arm/hardware/amba_clcd.h index 2149be7..476b639 100644 --- a/include/asm-arm/hardware/amba_clcd.h +++ b/include/asm-arm/hardware/amba_clcd.h @@ -153,7 +153,7 @@ struct clcd_fb { static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) { - u32 val; + u32 val, cpl; /* * Program the CLCD controller registers and start the CLCD @@ -164,7 +164,10 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) val |= (fb->fb.var.left_margin - 1) << 24; regs->tim0 = val; - val = fb->fb.var.yres - 1; + val = fb->fb.var.yres; + if (fb->panel->cntl & CNTL_LCDDUAL) + val /= 2; + val -= 1; val |= (fb->fb.var.vsync_len - 1) << 10; val |= fb->fb.var.lower_margin << 16; val |= fb->fb.var.upper_margin << 24; @@ -174,13 +177,17 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) val |= fb->fb.var.sync & FB_SYNC_HOR_HIGH_ACT ? 0 : TIM2_IHS; val |= fb->fb.var.sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS; - if (fb->panel->cntl & CNTL_LCDTFT) - val |= (fb->fb.var.xres_virtual - 1) << 16; - else if (fb->panel->cntl & CNTL_LCDBW) - printk("what value for CPL for stnmono panels?"); - else - val |= ((fb->fb.var.xres_virtual * 8 / 3) - 1) << 16; - regs->tim2 = val; + cpl = fb->fb.var.xres_virtual; + if (fb->panel->cntl & CNTL_LCDTFT) /* TFT */ + /* / 1 */; + else if (!fb->fb.var.grayscale) /* STN color */ + cpl = cpl * 8 / 3; + else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */ + cpl /= 8; + else /* STN monochrome, 4bit */ + cpl /= 4; + + regs->tim2 = val | ((cpl - 1) << 16); regs->tim3 = fb->panel->tim3; @@ -216,7 +223,7 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var) { var->xres_virtual = var->xres = (var->xres + 7) & ~7; - var->yres_virtual = var->yres; + var->yres_virtual = var->yres = (var->yres + 1) & ~1; #define CHECK(e,l,h) (var->e < l || var->e > h) if (CHECK(right_margin, (5+1), 256) || /* back porch */ -- cgit v0.10.2 From 82235e9170f19fa327361ee82a76618e60f2db47 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 28 Apr 2005 10:43:52 +0100 Subject: [PATCH] ARM: Fix AMBA CLCD fb driver for 32bpp We were supporting 24bpp. However, the pixel organisation in memory was 0RGB, so it was 24bpp in 32bit words. This means we're actually supporting 32bpp and not 24bpp. Also, add a check to ensure that we don't exceed the available framebuffer when changing display resolutions. Signed-off-by: Russell King diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 075d396..3e386fd 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -146,7 +146,7 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) var->blue.offset = 10; } break; - case 24: + case 32: if (fb->panel->cntl & CNTL_LCDTFT) { var->red.length = 8; var->green.length = 8; @@ -178,6 +178,12 @@ static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) if (fb->board->check) ret = fb->board->check(fb, var); + + if (ret == 0 && + var->xres_virtual * var->bits_per_pixel / 8 * + var->yres_virtual > fb->fb.fix.smem_len) + ret = -EINVAL; + if (ret == 0) ret = clcdfb_set_bitfields(fb, var); diff --git a/include/asm-arm/hardware/amba_clcd.h b/include/asm-arm/hardware/amba_clcd.h index 476b639..d6ad33e 100644 --- a/include/asm-arm/hardware/amba_clcd.h +++ b/include/asm-arm/hardware/amba_clcd.h @@ -211,7 +211,7 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) case 16: val |= CNTL_LCDBPP16; break; - case 24: + case 32: val |= CNTL_LCDBPP24; break; } -- cgit v0.10.2 From 0f7ad450394560a6b6c72115e04bf7afd6230e70 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 28 Apr 2005 10:46:15 +0100 Subject: [PATCH] ARM: AMBA CLCD: X resolutions must be multiples of 16 We ignore the bottom 4 bits of the X resolution, so we should round X resolutions up to the nearest multiple of 16. Signed-off-by: Russell King diff --git a/include/asm-arm/hardware/amba_clcd.h b/include/asm-arm/hardware/amba_clcd.h index d6ad33e..ce4cf5c 100644 --- a/include/asm-arm/hardware/amba_clcd.h +++ b/include/asm-arm/hardware/amba_clcd.h @@ -222,7 +222,7 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var) { - var->xres_virtual = var->xres = (var->xres + 7) & ~7; + var->xres_virtual = var->xres = (var->xres + 15) & ~15; var->yres_virtual = var->yres = (var->yres + 1) & ~1; #define CHECK(e,l,h) (var->e < l || var->e > h) -- cgit v0.10.2 From 9acf6597c533f3d5c991f730c6a1be296679018e Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Thu, 28 Apr 2005 08:13:58 -0700 Subject: [PATCH] time interpolator: Fix settimeofday inaccuracy settimeofday will set the time a little bit too early on systems using time interpolation since it subtracts the current interpolator offset from the time. This used to be necessary with the code in 2.6.9 and earlier but the new code resets the time interpolator after setting the time. Thus the time is set too early and gettimeofday will return a time slightly before the time specified with settimeofday if invoked immeditely after settimeofday. This removes the obsolete subtraction of the time interpolator offset and makes settimeofday set the time accurately. Signed-off-by: Christoph Lameter Signed-off-by: Linus Torvalds diff --git a/kernel/time.c b/kernel/time.c index 96fd0f4..d4335c1 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -516,14 +516,6 @@ int do_settimeofday (struct timespec *tv) write_seqlock_irq(&xtime_lock); { - /* - * This is revolting. We need to set "xtime" correctly. However, the value - * in this location is the value at the most recent update of wall time. - * Discover what correction gettimeofday would have done, and then undo - * it! - */ - nsec -= time_interpolator_get_offset(); - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); -- cgit v0.10.2 From f4d0ee983ec01e59a77e157ab702246f397b2a2b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2005 11:33:20 -0700 Subject: [TG3]: Set SA_SAMPLE_RANDOM in request_irq() calls. Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 903d0ce..058c70c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5830,7 +5830,7 @@ static int tg3_test_interrupt(struct tg3 *tp) free_irq(tp->pdev->irq, dev); err = request_irq(tp->pdev->irq, tg3_test_isr, - SA_SHIRQ, dev->name, dev); + SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); if (err) return err; @@ -5852,10 +5852,10 @@ static int tg3_test_interrupt(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) err = request_irq(tp->pdev->irq, tg3_msi, - 0, dev->name, dev); + SA_SAMPLE_RANDOM, dev->name, dev); else err = request_irq(tp->pdev->irq, tg3_interrupt, - SA_SHIRQ, dev->name, dev); + SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); if (err) return err; @@ -5908,7 +5908,7 @@ static int tg3_test_msi(struct tg3 *tp) tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; err = request_irq(tp->pdev->irq, tg3_interrupt, - SA_SHIRQ, dev->name, dev); + SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); if (err) return err; @@ -5965,10 +5965,10 @@ static int tg3_open(struct net_device *dev) } if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) err = request_irq(tp->pdev->irq, tg3_msi, - 0, dev->name, dev); + SA_SAMPLE_RANDOM, dev->name, dev); else err = request_irq(tp->pdev->irq, tg3_interrupt, - SA_SHIRQ, dev->name, dev); + SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); if (err) { if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { -- cgit v0.10.2 From 173372162ddbd414cc471c1a3a52ad7ea279aaf4 Mon Sep 17 00:00:00 2001 From: Vladislav Yasevich Date: Thu, 28 Apr 2005 11:57:54 -0700 Subject: [SCTP] Fix SCTP_ASSOCINFO getsockopt for 1-1 style Signed-off-by: Vladislav Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller diff --git a/net/sctp/socket.c b/net/sctp/socket.c index e8c2101..32f2249 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3473,7 +3473,7 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len, return -EINVAL; /* Values correspoinding to the specific association */ - if (assocparams.sasoc_assoc_id != 0) { + if (asoc) { assocparams.sasoc_asocmaxrxt = asoc->max_retrans; assocparams.sasoc_peer_rwnd = asoc->peer.rwnd; assocparams.sasoc_local_rwnd = asoc->a_rwnd; -- cgit v0.10.2 From 047a2428a14216a83980ed26b6a59b3ca40a1fb0 Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Thu, 28 Apr 2005 11:58:43 -0700 Subject: [SCTP] Implement Sec 2.41 of SCTP Implementers guide. - Fixed sctp_vtag_verify_either() to comply with impguide 2.41 B) and C). - Make sure vtag is reflected when T-bit is set in SHUTDOWN-COMPLETE sent due to an OOTB SHUTDOWN-ACK and in ABORT sent due to an OOTB packet. - Do not set T-Bit in ABORT chunk in response to INIT. - Fixed some comments to reflect the new meaning of the T-Bit. Signed-off-by: Jerome Forissier Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 5576db5..f4fcee1 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -407,32 +407,38 @@ sctp_vtag_verify(const struct sctp_chunk *chunk, return 0; } -/* Check VTAG of the packet matches the sender's own tag OR its peer's - * tag and the T bit is set in the Chunk Flags. +/* Check VTAG of the packet matches the sender's own tag and the T bit is + * not set, OR its peer's tag and the T bit is set in the Chunk Flags. */ static inline int sctp_vtag_verify_either(const struct sctp_chunk *chunk, const struct sctp_association *asoc) { - /* RFC 2960 Section 8.5.1, sctpimpguide-06 Section 2.13.2 + /* RFC 2960 Section 8.5.1, sctpimpguide Section 2.41 * - * B) The receiver of a ABORT shall accept the packet if the - * Verification Tag field of the packet matches its own tag OR it - * is set to its peer's tag and the T bit is set in the Chunk - * Flags. Otherwise, the receiver MUST silently discard the packet - * and take no further action. - * - * (C) The receiver of a SHUTDOWN COMPLETE shall accept the - * packet if the Verification Tag field of the packet - * matches its own tag OR it is set to its peer's tag and - * the T bit is set in the Chunk Flags. Otherwise, the - * receiver MUST silently discard the packet and take no - * further action.... + * B) The receiver of a ABORT MUST accept the packet + * if the Verification Tag field of the packet matches its own tag + * and the T bit is not set + * OR + * it is set to its peer's tag and the T bit is set in the Chunk + * Flags. + * Otherwise, the receiver MUST silently discard the packet + * and take no further action. * + * C) The receiver of a SHUTDOWN COMPLETE shall accept the packet + * if the Verification Tag field of the packet matches its own tag + * and the T bit is not set + * OR + * it is set to its peer's tag and the T bit is set in the Chunk + * Flags. + * Otherwise, the receiver MUST silently discard the packet + * and take no further action. An endpoint MUST ignore the + * SHUTDOWN COMPLETE if it is not in the SHUTDOWN-ACK-SENT state. */ - if ((ntohl(chunk->sctp_hdr->vtag) == asoc->c.my_vtag) || - (sctp_test_T_bit(chunk) && (ntohl(chunk->sctp_hdr->vtag) - == asoc->c.peer_vtag))) { + if ((!sctp_test_T_bit(chunk) && + (ntohl(chunk->sctp_hdr->vtag) == asoc->c.my_vtag)) || + (sctp_test_T_bit(chunk) && + (ntohl(chunk->sctp_hdr->vtag) == asoc->c.peer_vtag))) { return 1; } diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 1db12cc..33ac8bf 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -710,7 +710,9 @@ struct sctp_chunk *sctp_make_shutdown_complete( struct sctp_chunk *retval; __u8 flags = 0; - /* Maybe set the T-bit if we have no association. */ + /* Set the T-bit if we have no association (vtag will be + * reflected) + */ flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); @@ -732,7 +734,7 @@ struct sctp_chunk *sctp_make_shutdown_complete( } /* Create an ABORT. Note that we set the T bit if we have no - * association. + * association, except when responding to an INIT (sctpimpguide 2.41). */ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc, const struct sctp_chunk *chunk, @@ -741,8 +743,16 @@ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc, struct sctp_chunk *retval; __u8 flags = 0; - /* Maybe set the T-bit if we have no association. */ - flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; + /* Set the T-bit if we have no association and 'chunk' is not + * an INIT (vtag will be reflected). + */ + if (!asoc) { + if (chunk && chunk->chunk_hdr && + chunk->chunk_hdr->type == SCTP_CID_INIT) + flags = 0; + else + flags = SCTP_CHUNK_FLAG_T; + } retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint); @@ -2744,7 +2754,6 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, hint = (nstreams + 1) * sizeof(__u32); - /* Maybe set the T-bit if we have no association. */ retval = sctp_make_chunk(asoc, SCTP_CID_FWD_TSN, 0, hint); if (!retval) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 278c56a..8e01b8f 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -126,15 +126,18 @@ sctp_chunk_length_valid(struct sctp_chunk *chunk, * should stop the T2-shutdown timer and remove all knowledge of the * association (and thus the association enters the CLOSED state). * - * Verification Tag: 8.5.1(C) + * Verification Tag: 8.5.1(C), sctpimpguide 2.41. * C) Rules for packet carrying SHUTDOWN COMPLETE: * ... - * - The receiver of a SHUTDOWN COMPLETE shall accept the packet if the - * Verification Tag field of the packet matches its own tag OR it is - * set to its peer's tag and the T bit is set in the Chunk Flags. - * Otherwise, the receiver MUST silently discard the packet and take - * no further action. An endpoint MUST ignore the SHUTDOWN COMPLETE if - * it is not in the SHUTDOWN-ACK-SENT state. + * - The receiver of a SHUTDOWN COMPLETE shall accept the packet + * if the Verification Tag field of the packet matches its own tag and + * the T bit is not set + * OR + * it is set to its peer's tag and the T bit is set in the Chunk + * Flags. + * Otherwise, the receiver MUST silently discard the packet + * and take no further action. An endpoint MUST ignore the + * SHUTDOWN COMPLETE if it is not in the SHUTDOWN-ACK-SENT state. * * Inputs * (endpoint, asoc, chunk) @@ -2858,16 +2861,16 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep, /* * Generate an ABORT in response to a packet. * - * Section: 8.4 Handle "Out of the blue" Packets + * Section: 8.4 Handle "Out of the blue" Packets, sctpimpguide 2.41 * - * 8) The receiver should respond to the sender of the OOTB packet - * with an ABORT. When sending the ABORT, the receiver of the - * OOTB packet MUST fill in the Verification Tag field of the - * outbound packet with the value found in the Verification Tag - * field of the OOTB packet and set the T-bit in the Chunk Flags - * to indicate that no TCB was found. After sending this ABORT, - * the receiver of the OOTB packet shall discard the OOTB packet - * and take no further action. + * 8) The receiver should respond to the sender of the OOTB packet with + * an ABORT. When sending the ABORT, the receiver of the OOTB packet + * MUST fill in the Verification Tag field of the outbound packet + * with the value found in the Verification Tag field of the OOTB + * packet and set the T-bit in the Chunk Flags to indicate that the + * Verification Tag is reflected. After sending this ABORT, the + * receiver of the OOTB packet shall discard the OOTB packet and take + * no further action. * * Verification Tag: * @@ -2895,6 +2898,10 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, return SCTP_DISPOSITION_NOMEM; } + /* Reflect vtag if T-Bit is set */ + if (sctp_test_T_bit(abort)) + packet->vtag = ntohl(chunk->sctp_hdr->vtag); + /* Set the skb to the belonging sock for accounting. */ abort->skb->sk = ep->base.sk; @@ -3026,22 +3033,24 @@ nomem: } /* - * RFC 2960, 8.4 - Handle "Out of the blue" Packets + * RFC 2960, 8.4 - Handle "Out of the blue" Packets, sctpimpguide 2.41. + * * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should * respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. * When sending the SHUTDOWN COMPLETE, the receiver of the OOTB * packet must fill in the Verification Tag field of the outbound * packet with the Verification Tag received in the SHUTDOWN ACK and - * set the T-bit in the Chunk Flags to indicate that no TCB was - * found. Otherwise, + * set the T-bit in the Chunk Flags to indicate that the Verification + * Tag is reflected. * * 8) The receiver should respond to the sender of the OOTB packet with * an ABORT. When sending the ABORT, the receiver of the OOTB packet * MUST fill in the Verification Tag field of the outbound packet * with the value found in the Verification Tag field of the OOTB - * packet and set the T-bit in the Chunk Flags to indicate that no - * TCB was found. After sending this ABORT, the receiver of the OOTB - * packet shall discard the OOTB packet and take no further action. + * packet and set the T-bit in the Chunk Flags to indicate that the + * Verification Tag is reflected. After sending this ABORT, the + * receiver of the OOTB packet shall discard the OOTB packet and take + * no further action. */ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, const struct sctp_association *asoc, @@ -3090,13 +3099,15 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, /* * Handle an "Out of the blue" SHUTDOWN ACK. * - * Section: 8.4 5) + * Section: 8.4 5, sctpimpguide 2.41. + * * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should - * respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. - * When sending the SHUTDOWN COMPLETE, the receiver of the OOTB packet - * must fill in the Verification Tag field of the outbound packet with - * the Verification Tag received in the SHUTDOWN ACK and set the - * T-bit in the Chunk Flags to indicate that no TCB was found. + * respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. + * When sending the SHUTDOWN COMPLETE, the receiver of the OOTB + * packet must fill in the Verification Tag field of the outbound + * packet with the Verification Tag received in the SHUTDOWN ACK and + * set the T-bit in the Chunk Flags to indicate that the Verification + * Tag is reflected. * * Inputs * (endpoint, asoc, type, arg, commands) @@ -3128,6 +3139,10 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep, return SCTP_DISPOSITION_NOMEM; } + /* Reflect vtag if T-Bit is set */ + if (sctp_test_T_bit(shut)) + packet->vtag = ntohl(chunk->sctp_hdr->vtag); + /* Set the skb to the belonging sock for accounting. */ shut->skb->sk = ep->base.sk; @@ -3591,7 +3606,6 @@ sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep, * * 2) If the OOTB packet contains an ABORT chunk, the receiver MUST * silently discard the OOTB packet and take no further action. - * Otherwise, * * Verification Tag: No verification necessary * @@ -4961,6 +4975,11 @@ static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep, sctp_ootb_pkt_free(packet); return NULL; } + + /* Reflect vtag if T-Bit is set */ + if (sctp_test_T_bit(abort)) + packet->vtag = ntohl(chunk->sctp_hdr->vtag); + /* Add specified error causes, i.e., payload, to the * end of the chunk. */ -- cgit v0.10.2 From b9b9e10f180fa63b55b93412edf0ab9648675646 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Thu, 28 Apr 2005 11:59:16 -0700 Subject: [SCTP] Use ipv6_addr_any() rather than ipv6_addr_type() in sctp_v6_is_any(). Signed-off-by: Brian Haley Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index e42c74e..c9d9ea0 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -496,9 +496,7 @@ static void sctp_v6_inaddr_any(union sctp_addr *addr, unsigned short port) /* Is this a wildcard address? */ static int sctp_v6_is_any(const union sctp_addr *addr) { - int type; - type = ipv6_addr_type((struct in6_addr *)&addr->v6.sin6_addr); - return IPV6_ADDR_ANY == type; + return ipv6_addr_any(&addr->v6.sin6_addr); } /* Should this be available for binding? */ -- cgit v0.10.2 From 5e6bc34f86e450ff14c4817902d66aa9c786bc06 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 28 Apr 2005 11:59:49 -0700 Subject: [SCTP] Fix bug in sctp_init() error handling code. Signed-off-by: Neil Horman Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index b9813cf..23c85a2 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1159,8 +1159,6 @@ SCTP_STATIC __init int sctp_init(void) status = 0; out: return status; -err_add_protocol: - proto_unregister(&sctp_prot); err_ctl_sock_init: sctp_v6_exit(); err_v6_init: @@ -1188,6 +1186,8 @@ err_bucket_cachep: inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); inet_unregister_protosw(&sctp_seqpacket_protosw); inet_unregister_protosw(&sctp_stream_protosw); +err_add_protocol: + proto_unregister(&sctp_prot); goto out; } -- cgit v0.10.2 From 594ccc14dfe4d61b476491758425a1c2ca4ec71b Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Thu, 28 Apr 2005 12:00:23 -0700 Subject: [SCTP] Replace incorrect use of dev_alloc_skb with alloc_skb in sctp_packet_transmit(). Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller diff --git a/net/sctp/output.c b/net/sctp/output.c index 9013f64..84b5b37 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -313,12 +313,12 @@ int sctp_packet_transmit(struct sctp_packet *packet) sk = chunk->skb->sk; /* Allocate the new skb. */ - nskb = dev_alloc_skb(packet->size); + nskb = alloc_skb(packet->size + LL_MAX_HEADER, GFP_ATOMIC); if (!nskb) goto nomem; /* Make sure the outbound skb has enough header room reserved. */ - skb_reserve(nskb, packet->overhead); + skb_reserve(nskb, packet->overhead + LL_MAX_HEADER); /* Set the owning socket so that we know where to get the * destination IP address. -- cgit v0.10.2 From 4eb701dfc618491c9b97377df6e61de36dfc39ce Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 28 Apr 2005 12:02:04 -0700 Subject: [SCTP] Fix SCTP sendbuffer accouting. - Include chunk and skb sizes in sendbuffer accounting. - 2 policies are supported. 0: per socket accouting, 1: per association accounting DaveM: I've made the default per-socket. Signed-off-by: Neil Horman Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 358d52b..7729981 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -643,6 +643,7 @@ enum { NET_SCTP_MAX_BURST = 12, NET_SCTP_ADDIP_ENABLE = 13, NET_SCTP_PRSCTP_ENABLE = 14, + NET_SCTP_SNDBUF_POLICY = 15, }; /* /proc/sys/net/bridge */ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 7e64cf6..6c24d9c 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -154,6 +154,13 @@ extern struct sctp_globals { int max_retrans_path; int max_retrans_init; + /* + * Policy for preforming sctp/socket accounting + * 0 - do socket level accounting, all assocs share sk_sndbuf + * 1 - do sctp accounting, each asoc may use sk_sndbuf bytes + */ + int sndbuf_policy; + /* HB.interval - 30 seconds */ int hb_interval; @@ -207,6 +214,7 @@ extern struct sctp_globals { #define sctp_valid_cookie_life (sctp_globals.valid_cookie_life) #define sctp_cookie_preserve_enable (sctp_globals.cookie_preserve_enable) #define sctp_max_retrans_association (sctp_globals.max_retrans_association) +#define sctp_sndbuf_policy (sctp_globals.sndbuf_policy) #define sctp_max_retrans_path (sctp_globals.max_retrans_path) #define sctp_max_retrans_init (sctp_globals.max_retrans_init) #define sctp_hb_interval (sctp_globals.hb_interval) @@ -1212,7 +1220,8 @@ struct sctp_endpoint { /* Default timeouts. */ int timeouts[SCTP_NUM_TIMEOUT_TYPES]; - /* Various thresholds. */ + /* sendbuf acct. policy. */ + __u32 sndbuf_policy; /* Name for debugging output... */ char *debug_name; diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 544b750..334f617 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -125,6 +125,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, sp->autoclose * HZ; /* Use SCTP specific send buffer space queues. */ + ep->sndbuf_policy = sctp_sndbuf_policy; sk->sk_write_space = sctp_write_space; sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 23c85a2..2e1f9c3 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1043,6 +1043,9 @@ SCTP_STATIC __init int sctp_init(void) sctp_max_retrans_path = 5; sctp_max_retrans_init = 8; + /* Sendbuffer growth - do per-socket accounting */ + sctp_sndbuf_policy = 0; + /* HB.interval - 30 seconds */ sctp_hb_interval = 30 * HZ; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 32f2249..0b338ec 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -115,9 +115,17 @@ static inline int sctp_wspace(struct sctp_association *asoc) struct sock *sk = asoc->base.sk; int amt = 0; - amt = sk->sk_sndbuf - asoc->sndbuf_used; + if (asoc->ep->sndbuf_policy) { + /* make sure that no association uses more than sk_sndbuf */ + amt = sk->sk_sndbuf - asoc->sndbuf_used; + } else { + /* do socket level accounting */ + amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + } + if (amt < 0) amt = 0; + return amt; } @@ -138,12 +146,21 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk) /* The sndbuf space is tracked per association. */ sctp_association_hold(asoc); + skb_set_owner_w(chunk->skb, sk); + chunk->skb->destructor = sctp_wfree; /* Save the chunk pointer in skb for sctp_wfree to use later. */ *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; - asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); - sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); + asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) + + sizeof(struct sk_buff) + + sizeof(struct sctp_chunk); + + sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk) + + sizeof(struct sk_buff) + + sizeof(struct sctp_chunk); + + atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); } /* Verify that this is a valid address. */ @@ -4422,8 +4439,17 @@ static void sctp_wfree(struct sk_buff *skb) chunk = *((struct sctp_chunk **)(skb->cb)); asoc = chunk->asoc; sk = asoc->base.sk; - asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); - sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk); + asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) + + sizeof(struct sk_buff) + + sizeof(struct sctp_chunk); + + sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk) + + sizeof(struct sk_buff) + + sizeof(struct sctp_chunk); + + atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); + + sock_wfree(skb); __sctp_write_space(asoc); sctp_association_put(asoc); diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 89fa20c..7fc3184 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -110,6 +110,14 @@ static ctl_table sctp_table[] = { .proc_handler = &proc_dointvec }, { + .ctl_name = NET_SCTP_SNDBUF_POLICY, + .procname = "sndbuf_policy", + .data = &sctp_sndbuf_policy, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { .ctl_name = NET_SCTP_PATH_MAX_RETRANS, .procname = "path_max_retrans", .data = &sctp_max_retrans_path, -- cgit v0.10.2 From 7e3e0360b711568fb8ba5973accf51d51e746abc Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 28 Apr 2005 12:11:03 -0700 Subject: [IPV4]: Incorrect permissions on route flush sysctl This has been brought up before.. http://lkml.org/lkml/2000/1/21/116 but didnt seem to get resolved. This morning I got someone file a bugzilla about it breaking sysctl(8). Signed-off-by: Dave Jones Signed-off-by: David S. Miller diff --git a/net/ipv4/route.c b/net/ipv4/route.c index bb90a0c..a61a577 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2843,7 +2843,7 @@ ctl_table ipv4_route_table[] = { .procname = "flush", .data = &flush_delay, .maxlen = sizeof(int), - .mode = 0644, + .mode = 0200, .proc_handler = &ipv4_sysctl_rtcache_flush, .strategy = &ipv4_sysctl_rtcache_flush_strategy, }, -- cgit v0.10.2 From 89c8b3a11086a2a43ac4240116da77b707f37fbf Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 28 Apr 2005 12:11:49 -0700 Subject: [IPV6]: Incorrect permissions on route flush sysctl On Mon, Apr 25, 2005 at 12:01:13PM -0400, Dave Jones wrote: > This has been brought up before.. http://lkml.org/lkml/2000/1/21/116 > but didnt seem to get resolved. This morning I got someone > file a bugzilla about it breaking sysctl(8). And here's its ipv6 counterpart. Signed-off-by: Dave Jones Signed-off-by: David S. Miller diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 1838029..3bf8a02 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2005,7 +2005,7 @@ ctl_table ipv6_route_table[] = { .procname = "flush", .data = &flush_delay, .maxlen = sizeof(int), - .mode = 0644, + .mode = 0200, .proc_handler = &ipv6_sysctl_rtcache_flush }, { -- cgit v0.10.2 From 7b3c63ac7cb5e2e6680727045aa35c2e5f1bace7 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 28 Apr 2005 12:14:37 -0700 Subject: [PKT_SCHED]: Fix range in psched_tod_diff() to 0..bound Signed-off-by: Nicolas Dichtel Signed-off-by: Thomas Graf Signed-off-by: David S. Miller diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 87496e3..7352e45 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -140,7 +140,7 @@ psched_tod_diff(int delta_sec, int bound) if (bound <= 1000000 || delta_sec > (0x7FFFFFFF/1000000)-1) return bound; delta = delta_sec * 1000000; - if (delta > bound) + if (delta > bound || delta < 0) delta = bound; return delta; } @@ -156,7 +156,8 @@ psched_tod_diff(int delta_sec, int bound) __delta += 1000000; \ case 1: \ __delta += 1000000; \ - case 0: ; \ + case 0: \ + __delta = abs(__delta); \ } \ __delta; \ }) -- cgit v0.10.2 From 5bec0039f4ac8d707d7afe7739cc2e7004447e38 Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Thu, 28 Apr 2005 12:16:08 -0700 Subject: [NET]: /proc/net/stat/* header cleanup Signed-off-by: Olaf Rempel Signed-off-by: David S. Miller diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0a2f67b..43bdc52 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1953,7 +1953,7 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v) struct neigh_statistics *st = v; if (v == SEQ_START_TOKEN) { - seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs forced_gc_goal_miss\n"); + seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs\n"); return 0; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a61a577..1993117 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -397,7 +397,7 @@ static int rt_cpu_seq_show(struct seq_file *seq, void *v) struct rt_cache_stat *st = v; if (v == SEQ_START_TOKEN) { - seq_printf(seq, "entries in_hit in_slow_tot in_no_route in_brd in_martian_dst in_martian_src out_hit out_slow_tot out_slow_mc gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n"); + seq_printf(seq, "entries in_hit in_slow_tot in_slow_mc in_no_route in_brd in_martian_dst in_martian_src out_hit out_slow_tot out_slow_mc gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n"); return 0; } -- cgit v0.10.2 From 18c8baff8fe151ea02e00047afc369ee31939e9b Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 28 Apr 2005 15:17:19 -0700 Subject: [PATCH] Fix error recovery path for arch_setup_additional_pages If arch_setup_additional_pages fails, the error path will do some double-frees. This fixes it. Signed-off-by: Roland McGrath Signed-off-by: Linus Torvalds diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 6ae62cb..ce9423b 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -945,7 +945,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) retval = arch_setup_additional_pages(bprm, executable_stack); if (retval < 0) { send_sig(SIGKILL, current, 0); - goto out_free_dentry; + goto out; } #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ -- cgit v0.10.2 From 1da0c78b32abe122a959d2a57ba3d41563d8e39f Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:04 -0700 Subject: [PATCH] cifs: Only send POSIX ACL calls to server if server claims to support that capability bit Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 549afa1..9a41bee 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -161,18 +161,20 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, strlen(POSIX_ACL_XATTR_ACCESS)); if (temp == 0) { #ifdef CONFIG_CIFS_POSIX - rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value, - (const int)value_size, ACL_TYPE_ACCESS, - cifs_sb->local_nls); + if(sb->s_flags & MS_POSIXACL) + rc = CIFSSMBSetPosixACL(xid, pTcon,full_path, + ea_value, (const int)value_size, + ACL_TYPE_ACCESS,cifs_sb->local_nls); cFYI(1,("set POSIX ACL rc %d",rc)); #else cFYI(1,("set POSIX ACL not supported")); #endif } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { #ifdef CONFIG_CIFS_POSIX - rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value, - (const int)value_size, ACL_TYPE_DEFAULT, - cifs_sb->local_nls); + if(sb->s_flags & MS_POSIXACL) + rc = CIFSSMBSetPosixACL(xid, pTcon,full_path, + ea_value, (const int)value_size, + ACL_TYPE_DEFAULT, cifs_sb->local_nls); cFYI(1,("set POSIX default ACL rc %d",rc)); #else cFYI(1,("set default POSIX ACL not supported")); @@ -248,7 +250,8 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, buf_size, cifs_sb->local_nls); } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { #ifdef CONFIG_CIFS_POSIX - rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, + if(sb->s_flags & MS_POSIXACL) + rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, ea_value, buf_size, ACL_TYPE_ACCESS, cifs_sb->local_nls); #else @@ -256,7 +259,8 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, #endif /* CONFIG_CIFS_POSIX */ } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { #ifdef CONFIG_CIFS_POSIX - rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, + if(sb->s_flags & MS_POSIXACL) + rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, ea_value, buf_size, ACL_TYPE_DEFAULT, cifs_sb->local_nls); #else -- cgit v0.10.2 From f654bac2227adc5c6956405290eeb4f81f09e9ff Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:04 -0700 Subject: [PATCH] cifs: add support for chattr/lsattr in new CIFS POSIX extensions Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 5316c8d..7fd0269 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,7 +1,14 @@ -Version 1.31 +Version 1.32 ------------ Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one transact response for an SMB request and search entry split across two frames. +Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server) +as new protocol extensions. Do not send Get/Set calls for POSIX ACLs +unless server explicitly claims to support them in CIFS Unix extensions +POSIX ACL capability bit. + +Version 1.31 +------------ Fix updates of DOS attributes and time fields so that files on NT4 servers do not get marked delete on close. Display sizes of cifs buffer pools in cifs stats. Fix oops in unmount when cifsd thread being killed by diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 451f18a..e0e46f4 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -91,8 +91,10 @@ extern int cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname); extern int cifs_removexattr(struct dentry *, const char *); extern int cifs_setxattr(struct dentry *, const char *, const void *, - size_t, int); + size_t, int); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); -#define CIFS_VERSION "1.31" +extern int cifs_ioctl (struct inode * inode, struct file * filep, + unsigned int command, unsigned long arg); +#define CIFS_VERSION "1.32" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index bcd4a61..085109d 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -762,6 +762,16 @@ typedef struct smb_com_lock_req { LOCKING_ANDX_RANGE Locks[1]; } LOCK_REQ; + +typedef struct cifs_posix_lock { + __le16 lock_type; /* 0 = Read, 1 = Write, 2 = Unlock */ + __le16 lock_flags; /* 1 = Wait (only valid for setlock) */ + __le32 pid; + __le64 start; + __le64 length; + /* BB what about additional owner info to identify network client */ +} CIFS_POSIX_LOCK; + typedef struct smb_com_lock_rsp { struct smb_hdr hdr; /* wct = 2 */ __u8 AndXCommand; @@ -1098,6 +1108,8 @@ struct smb_t2_rsp { #define SMB_QUERY_POSIX_ACL 0x204 #define SMB_QUERY_XATTR 0x205 #define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */ +#define SMB_QUERY_POSIX_PERMISSION 0x207 +#define SMB_QUERY_POSIX_LOCK 0x208 #define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee #define SMB_QUERY_FILE_ACCESS_INFO 0x3f0 #define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */ @@ -1116,6 +1128,7 @@ struct smb_t2_rsp { #define SMB_SET_POSIX_ACL 0x204 #define SMB_SET_XATTR 0x205 #define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */ +#define SMB_SET_POSIX_LOCK 0x208 #define SMB_SET_FILE_BASIC_INFO2 0x3ec #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */ #define SMB_FILE_ALL_INFO2 0x3fa @@ -1237,9 +1250,27 @@ struct smb_com_transaction2_sfi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; - __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ + __u16 Reserved2; /* parameter word reserved - + present for infolevels > 100 */ +}; + +struct smb_t2_qfi_req { + struct smb_hdr hdr; + struct trans2_req t2; + __u8 Pad; + __u16 Pad1; + __u16 Fid; + __le16 InformationLevel; + __u16 Pad2; }; +struct smb_t2_qfi_rsp { + struct smb_hdr hdr; /* wct = 10 + SetupCount */ + struct trans2_resp t2; + __u16 ByteCount; + __u16 Reserved2; /* parameter word reserved - + present for infolevels > 100 */ +}; /* * Flags on T2 FINDFIRST and FINDNEXT @@ -1524,8 +1555,9 @@ typedef struct { } FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ /* Linux/Unix extensions capability flags */ #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ -#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 -#define CIFS_UNIX_XATTR_CAP 0x00000004 /*support for new namespace*/ +#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ +#define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ +#define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ typedef struct { /* For undefined recommended transfer size return -1 in that field */ @@ -1971,14 +2003,39 @@ struct xsymlink { char path[1024]; }; -typedef struct { +typedef struct file_xattr_info { /* BB do we need another field for flags? BB */ __u32 xattr_name_len; __u32 xattr_value_len; char xattr_name[0]; /* followed by xattr_value[xattr_value_len], no pad */ -} FILE_XATTR_INFO; /* extended attribute, info level 205 */ - +} FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ + + +/* flags for chattr command */ +#define EXT_SECURE_DELETE 0x00000001 /* EXT3_SECRM_FL */ +#define EXT_ENABLE_UNDELETE 0x00000002 /* EXT3_UNRM_FL */ +/* Reserved for compress file 0x4 */ +#define EXT_SYNCHRONOUS 0x00000008 /* EXT3_SYNC_FL */ +#define EXT_IMMUTABLE_FL 0x00000010 /* EXT3_IMMUTABLE_FL */ +#define EXT_OPEN_APPEND_ONLY 0x00000020 /* EXT3_APPEND_FL */ +#define EXT_DO_NOT_BACKUP 0x00000040 /* EXT3_NODUMP_FL */ +#define EXT_NO_UPDATE_ATIME 0x00000080 /* EXT3_NOATIME_FL */ +/* 0x100 through 0x800 reserved for compression flags and are GET-ONLY */ +#define EXT_HASH_TREE_INDEXED_DIR 0x00001000 /* GET-ONLY EXT3_INDEX_FL */ +/* 0x2000 reserved for IMAGIC_FL */ +#define EXT_JOURNAL_THIS_FILE 0x00004000 /* GET-ONLY EXT3_JOURNAL_DATA_FL */ +/* 0x8000 reserved for EXT3_NOTAIL_FL */ +#define EXT_SYNCHRONOUS_DIR 0x00010000 /* EXT3_DIRSYNC_FL */ +#define EXT_TOPDIR 0x00020000 /* EXT3_TOPDIR_FL */ + +#define EXT_SET_MASK 0x000300FF +#define EXT_GET_MASK 0x0003DFFF + +typedef struct file_chattr_info { + __le64 mask; /* list of all possible attribute bits */ + __le64 mode; /* list of actual attribute bits on this inode */ +} FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */ #endif diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 787eef4..82ae59d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -264,6 +264,8 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *fileName, const char *local_acl, const int buflen, const int acl_type, const struct nls_table *nls_codepage); -int cifs_ioctl (struct inode * inode, struct file * filep, +extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, + const int netfid, __u64 * pExtAttrBits, __u64 *pMask); +extern int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index df6a619..36d3c12 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2072,7 +2072,91 @@ setACLerrorExit: return rc; } -#endif +/* BB fix tabs in this function FIXME BB */ +int +CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, + const int netfid, __u64 * pExtAttrBits, __u64 *pMask) +{ + int rc = 0; + struct smb_t2_qfi_req *pSMB = NULL; + struct smb_t2_qfi_rsp *pSMBr = NULL; + int bytes_returned; + __u16 params, byte_count; + + cFYI(1,("In GetExtAttr")); + if(tcon == NULL) + return -ENODEV; + +GetExtAttrRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + params = 2 /* level */ +2 /* fid */ + 2 /* rsrvd */; + pSMB->t2.TotalDataCount = 0; + pSMB->t2.MaxParameterCount = cpu_to_le16(2); + /* BB find exact max data count below from sess structure BB */ + pSMB->t2.MaxDataCount = cpu_to_le16(4000); + pSMB->t2.MaxSetupCount = 0; + pSMB->t2.Reserved = 0; + pSMB->t2.Flags = 0; + pSMB->t2.Timeout = 0; + pSMB->t2.Reserved2 = 0; + pSMB->t2.ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->t2.DataCount = 0; + pSMB->t2.DataOffset = 0; + pSMB->t2.SetupCount = 1; + pSMB->t2.Reserved3 = 0; + pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); + byte_count = params + 3 /* pad */ ; + pSMB->t2.TotalParameterCount = cpu_to_le16(params); + pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); + pSMB->Pad1 = 0; + pSMB->Pad2 = 0; + pSMB->Fid = netfid; + pSMB->hdr.smb_buf_length += byte_count; + pSMB->t2.ByteCount = cpu_to_le16(byte_count); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("error %d in GetExtAttr", rc)); + } else { + /* decode response */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + if (rc || (pSMBr->ByteCount < 2)) + /* BB also check enough total bytes returned */ + /* If rc should we check for EOPNOSUPP and + disable the srvino flag? or in caller? */ + rc = -EIO; /* bad smb */ + else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + __u16 count = le16_to_cpu(pSMBr->t2.DataCount); + struct file_chattr_info * pfinfo; + /* BB Do we need a cast or hash here ? */ + if(count != 16) { + cFYI(1, ("Illegal size ret in GetExtAttr")); + rc = -EIO; + goto GetExtAttrOut; + } + pfinfo = (struct file_chattr_info *) + (data_offset + (char *) &pSMBr->hdr.Protocol); + *pExtAttrBits = le64_to_cpu(pfinfo->mode); + *pMask = le64_to_cpu(pfinfo->mask); + } + } +GetExtAttrOut: + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto GetExtAttrRetry; + return rc; +} + + +#endif /* CONFIG_POSIX */ int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index b4b8e20..7b84b2b 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -20,6 +20,7 @@ * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include #include #include "cifspdu.h" @@ -32,18 +33,63 @@ int cifs_ioctl (struct inode * inode, struct file * filep, { int rc = -ENOTTY; /* strange error - but the precedent */ #ifdef CONFIG_CIFS_POSIX + __u64 ExtAttrBits = 0; + __u64 ExtAttrMask = 0; + __u64 caps; +#endif /* CONFIG_CIFS_POSIX */ + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *tcon; + struct cifsFileInfo *pSMBFile = + (struct cifsFileInfo *)filep->private_data; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + tcon = cifs_sb->tcon; + if (pSMBFile == NULL) + goto cifs_ioctl_out; + +#ifdef CONFIG_CIFS_POSIX + if(tcon) + caps = le64_to_cpu(tcon->fsUnixInfo.Capability); + else { + rc = -EIO; + goto cifs_ioctl_out; + } + cFYI(1,("ioctl file %p cmd %u arg %lu",filep,command,arg)); switch(command) { case EXT2_IOC_GETFLAGS: - cFYI(1,("get flags not implemented yet")); - return -EOPNOTSUPP; + if(CIFS_UNIX_EXTATTR_CAP & caps) { + rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, + &ExtAttrBits, &ExtAttrMask); + if(rc == 0) + rc = put_user(ExtAttrBits & + EXT2_FL_USER_VISIBLE, + (int __user *)arg); + } + break; + case EXT2_IOC_SETFLAGS: + if(CIFS_UNIX_EXTATTR_CAP & caps) { + if(get_user(ExtAttrBits,(int __user *)arg)) { + rc = -EFAULT; + goto cifs_ioctl_out; + } + /* rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, + extAttrBits, &ExtAttrMask);*/ + + } cFYI(1,("set flags not implemented yet")); - return -EOPNOTSUPP; + break; default: cFYI(1,("unsupported ioctl")); return rc; } #endif /* CONFIG_CIFS_POSIX */ + +cifs_ioctl_out: + FreeXid(xid); return rc; } -- cgit v0.10.2 From 75cf6bdc52d86ca815f1129529e43f0d904b18d5 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:04 -0700 Subject: [PATCH] cifs: Gracefully turn off serverino (when serverino is enabled on mount) Old servers such as NT4 do not support this level of FindFirst (and retry with a lower infolevel) Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 4e34c89..dfaabc8 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -206,7 +206,7 @@ static const struct { { ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, { ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, { - ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, { + ERRDOS, ERRinvlevel, NT_STATUS_INVALID_INFO_CLASS}, { ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, { ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, { ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, { diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index f8bea39..07838a5 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -323,6 +323,7 @@ static int initiate_cifs_search(const int xid, struct file *file) cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); +ffirst_retry: /* test for Unix extensions */ if (pTcon->ses->capabilities & CAP_UNIX) { cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; @@ -336,6 +337,11 @@ static int initiate_cifs_search(const int xid, struct file *file) &cifsFile->netfid, &cifsFile->srch_inf); if(rc == 0) cifsFile->invalidHandle = FALSE; + if((rc == -EOPNOTSUPP) && + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; + goto ffirst_retry; + } kfree(full_path); return rc; } -- cgit v0.10.2 From c67593a03129967eae8939c4899767182eb6d6cd Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:04 -0700 Subject: [PATCH] cifs: Enable ioctl support in POSIX extensions to handle lsattr remove sparse warnings, unnecessary pad in QueryFileInfo and redundant function define. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5082fce..ae48ef0 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -559,6 +559,10 @@ struct file_operations cifs_file_ops = { .flush = cifs_flush, .mmap = cifs_file_mmap, .sendfile = generic_file_sendfile, +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ + #ifdef CONFIG_CIFS_EXPERIMENTAL .readv = generic_file_readv, .writev = generic_file_writev, @@ -579,6 +583,10 @@ struct file_operations cifs_file_direct_ops = { .fsync = cifs_fsync, .flush = cifs_flush, .sendfile = generic_file_sendfile, /* BB removeme BB */ +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ + #ifdef CONFIG_CIFS_EXPERIMENTAL .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 085109d..5b35289 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1258,10 +1258,8 @@ struct smb_t2_qfi_req { struct smb_hdr hdr; struct trans2_req t2; __u8 Pad; - __u16 Pad1; __u16 Fid; __le16 InformationLevel; - __u16 Pad2; }; struct smb_t2_qfi_rsp { diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 82ae59d..1b0070d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -266,6 +266,4 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, const struct nls_table *nls_codepage); extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, const int netfid, __u64 * pExtAttrBits, __u64 *pMask); -extern int cifs_ioctl (struct inode * inode, struct file * filep, - unsigned int command, unsigned long arg); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 36d3c12..237e3bf 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2093,9 +2093,9 @@ GetExtAttrRetry: if (rc) return rc; - params = 2 /* level */ +2 /* fid */ + 2 /* rsrvd */; + params = 2 /* level */ +2 /* fid */; pSMB->t2.TotalDataCount = 0; - pSMB->t2.MaxParameterCount = cpu_to_le16(2); + pSMB->t2.MaxParameterCount = cpu_to_le16(4); /* BB find exact max data count below from sess structure BB */ pSMB->t2.MaxDataCount = cpu_to_le16(4000); pSMB->t2.MaxSetupCount = 0; @@ -2103,19 +2103,18 @@ GetExtAttrRetry: pSMB->t2.Flags = 0; pSMB->t2.Timeout = 0; pSMB->t2.Reserved2 = 0; - pSMB->t2.ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, + Fid) - 4); pSMB->t2.DataCount = 0; pSMB->t2.DataOffset = 0; pSMB->t2.SetupCount = 1; pSMB->t2.Reserved3 = 0; pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION); - byte_count = params + 3 /* pad */ ; + byte_count = params + 1 /* pad */ ; pSMB->t2.TotalParameterCount = cpu_to_le16(params); pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); - pSMB->Pad1 = 0; - pSMB->Pad2 = 0; + pSMB->Pad = 0; pSMB->Fid = netfid; pSMB->hdr.smb_buf_length += byte_count; pSMB->t2.ByteCount = cpu_to_le16(byte_count); diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 7b84b2b..a4f1c34a 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -27,6 +27,7 @@ #include "cifsglob.h" #include "cifsproto.h" #include "cifs_debug.h" +#include "cifsfs.h" int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg) -- cgit v0.10.2 From ad009ac96509e005d9978d0ae9e9ec4d63ad2990 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:05 -0700 Subject: [PATCH] cifs: Fix multiuser packet signing to use the right sequence number and mac session key Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 7fd0269..43b3119 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -5,7 +5,8 @@ transact response for an SMB request and search entry split across two frames. Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server) as new protocol extensions. Do not send Get/Set calls for POSIX ACLs unless server explicitly claims to support them in CIFS Unix extensions -POSIX ACL capability bit. +POSIX ACL capability bit. Fix packet signing when multiuser mounting with +different users from the same client to the same server. Version 1.31 ------------ diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 78829e7..1959c7c 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -50,7 +50,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char return 0; } -int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, +int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server, __u32 * pexpected_response_sequence_number) { int rc = 0; @@ -59,21 +59,21 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ /* BB remember to add code to save expected sequence number in midQ entry BB */ - if((cifs_pdu == NULL) || (ses == NULL)) + if((cifs_pdu == NULL) || (server == NULL)) return -EINVAL; if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) return rc; spin_lock(&GlobalMid_Lock); - cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number); + cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number); cifs_pdu->Signature.Sequence.Reserved = 0; - *pexpected_response_sequence_number = ses->sequence_number++; - ses->sequence_number++; + *pexpected_response_sequence_number = server->sequence_number++; + server->sequence_number++; spin_unlock(&GlobalMid_Lock); - rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); + rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature); if(rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); else @@ -190,7 +190,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ hmac_md5_update((const unsigned char *) unicode_buf, (user_name_len+dom_name_len)*2,&ctx); - hmac_md5_final(ses->mac_signing_key,&ctx); + hmac_md5_final(ses->server->mac_signing_key,&ctx); kfree(ucase_buf); kfree(unicode_buf); return 0; @@ -200,7 +200,7 @@ void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_respon struct HMACMD5Context context; memcpy(v2_session_response + 8, ses->server->cryptKey,8); /* gen_blob(v2_session_response + 16); */ - hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context); + hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); hmac_md5_update(ses->server->cryptKey,8,&context); /* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 69aff1a7..1b3082d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -149,6 +149,8 @@ struct TCP_Server_Info { __u16 timeZone; char cryptKey[CIFS_CRYPTO_KEY_SIZE]; char workstation_RFC1001_name[16]; /* 16th byte is always zero */ + __u32 sequence_number; /* needed for CIFS PDU signature */ + char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; }; /* @@ -174,17 +176,16 @@ struct cifsSesInfo { struct TCP_Server_Info *server; /* pointer to server info */ atomic_t inUse; /* # of mounts (tree connections) on this ses */ enum statusEnum status; - __u32 sequence_number; /* needed for CIFS PDU signature */ __u16 ipc_tid; /* special tid for connection to IPC share */ __u16 flags; - char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; - char *serverOS; /* name of operating system underlying the server */ - char *serverNOS; /* name of network operating system that the server is running */ + char *serverOS; /* name of operating system underlying server */ + char *serverNOS; /* name of network operating system of server */ char *serverDomain; /* security realm of server */ int Suid; /* remote smb uid */ uid_t linux_uid; /* local Linux uid */ int capabilities; - char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ + char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for + TCP names - will ipv6 and sctp addresses fit? */ char userName[MAX_USERNAME_SIZE + 1]; char domainName[MAX_USERNAME_SIZE + 1]; char * password; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1b0070d..dd95c2b 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -230,7 +230,7 @@ extern void tconInfoFree(struct cifsTconInfo *); extern int cifs_reconnect(struct TCP_Server_Info *server); -extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); +extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *); extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, __u32 expected_sequence_number); extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 40470b9..814e709 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -182,7 +182,8 @@ cifs_reconnect(struct TCP_Server_Info *server) spin_lock(&GlobalMid_Lock); if(server->tcpStatus != CifsExiting) server->tcpStatus = CifsGood; - spin_unlock(&GlobalMid_Lock); + server->sequence_number = 0; + spin_unlock(&GlobalMid_Lock); /* atomic_set(&server->inFlight,0);*/ wake_up(&server->response_q); } @@ -1352,6 +1353,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, } else rc = 0; memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); + srvTcp->sequence_number = 0; } } @@ -2959,6 +2961,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, int rc = 0; char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; int ntlmv2_flag = FALSE; + int first_time = 0; /* what if server changes its buffer size after dropping the session? */ if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { @@ -2977,12 +2980,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, spin_unlock(&GlobalMid_Lock); } + first_time = 1; } if (!rc) { pSesInfo->capabilities = pSesInfo->server->capabilities; if(linuxExtEnabled == 0) pSesInfo->capabilities &= (~CAP_UNIX); - pSesInfo->sequence_number = 0; + /* pSesInfo->sequence_number = 0;*/ cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", pSesInfo->server->secMode, pSesInfo->server->capabilities, @@ -3015,7 +3019,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); if(v2_response) { CalcNTLMv2_response(pSesInfo,v2_response); -/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ + /* if(first_time) + cifs_calculate_ntlmv2_mac_key( + pSesInfo->server->mac_signing_key, + response, ntlm_session_key, */ kfree(v2_response); /* BB Put dummy sig in SessSetup PDU? */ } else { @@ -3028,9 +3035,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, pSesInfo->server->cryptKey, ntlm_session_key); - cifs_calculate_mac_key(pSesInfo->mac_signing_key, - ntlm_session_key, - pSesInfo->password); + if(first_time) + cifs_calculate_mac_key( + pSesInfo->server->mac_signing_key, + ntlm_session_key, + pSesInfo->password); } /* for better security the weaker lanman hash not sent in AuthSessSetup so we no longer calculate it */ @@ -3046,8 +3055,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, pSesInfo->server->cryptKey, ntlm_session_key); - cifs_calculate_mac_key(pSesInfo->mac_signing_key, - ntlm_session_key, pSesInfo->password); + if(first_time) + cifs_calculate_mac_key( + pSesInfo->server->mac_signing_key, + ntlm_session_key, pSesInfo->password); + rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info); } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index af13e52..a9e4f98 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -346,7 +346,7 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, } /* BB can we sign efficiently in this path? */ - rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); + rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; /* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec, @@ -475,7 +475,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, return -EIO; } - rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); + rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, @@ -559,8 +559,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, } if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { - cERROR(1, - ("Frame too large received. Length: %d Xid: %d", + cERROR(1, ("Frame too large received. Length: %d Xid: %d", receive_len, xid)); rc = -EIO; } else { /* rcvd frame is ok */ @@ -575,15 +574,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, dump_smb(out_buf, 92); /* convert the length into a more usable form */ if((receive_len > 24) && - (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { - rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */ - if(rc) - cFYI(1,("Unexpected signature received from server")); + (ses->server->secMode & (SECMODE_SIGN_REQUIRED | + SECMODE_SIGN_ENABLED))) { + rc = cifs_verify_signature(out_buf, + ses->server->mac_signing_key, + midQ->sequence_number+1); + if(rc) { + cERROR(1,("Unexpected packet signature received from server")); + /* BB FIXME - add code to kill session here */ + } } *pbytes_returned = out_buf->smb_buf_length; - /* BB special case reconnect tid and reconnect uid here? */ + /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf); /* convert ByteCount if necessary */ -- cgit v0.10.2 From cbe0476fa6a76b01b79e7c117963d45ed0a28758 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:05 -0700 Subject: [PATCH] cifs: fix rare oops in cifs_close Protect access to cifs file list in cifs_close path Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 43b3119..ce16b0a 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -6,7 +6,8 @@ Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server) as new protocol extensions. Do not send Get/Set calls for POSIX ACLs unless server explicitly claims to support them in CIFS Unix extensions POSIX ACL capability bit. Fix packet signing when multiuser mounting with -different users from the same client to the same server. +different users from the same client to the same server. Fix oops in +cifs_close. Version 1.31 ------------ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index dcab7cf..9c77550 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -465,8 +465,10 @@ int cifs_close(struct inode *inode, struct file *file) write_lock(&file->f_owner.lock); } } + write_lock(&GlobalSMBSeslock); list_del(&pSMBFile->flist); list_del(&pSMBFile->tlist); + write_unlock(&GlobalSMBSeslock); write_unlock(&file->f_owner.lock); kfree(pSMBFile->search_resume_name); kfree(file->private_data); -- cgit v0.10.2 From 6a0b48245a135cd132e747815854e3999967f8a7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:05 -0700 Subject: [PATCH] cifs: Add new mount parm mapchars For handling seven special characters that shells use for filenames. This first parts implements conversions from Unicode. Signed-off-by: Steve French Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index ce16b0a..412b6d2 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -7,7 +7,9 @@ as new protocol extensions. Do not send Get/Set calls for POSIX ACLs unless server explicitly claims to support them in CIFS Unix extensions POSIX ACL capability bit. Fix packet signing when multiuser mounting with different users from the same client to the same server. Fix oops in -cifs_close. +cifs_close. Add mount option for remapping reserved characters in +filenames (also allow recognizing files with created by SFU which have any +of these seven reserved characters to be recognized). Version 1.31 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index 0f20edc..83e0545 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -376,6 +376,17 @@ A partial list of the supported mount options follows: attributes) to the server (default) e.g. via setfattr and getfattr utilities. nouser_xattr Do not allow getfattr/setfattr to get/set xattrs + mapchars Translate the seven reserved characters + *?<>|:\ + to the remap range (above 0xF000), which also + allows the CIFS client to recognize files created with + such characters by Windows's POSIX emulation. This can + also be useful when mounting to most versions of Samba + (which also forbids creating and opening files + whose names contain any of these seven characters). + This has no effect if the server does not support + Unicode on the wire. + nomapchars Do not translate any of these seven characters (default). The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/TODO b/fs/cifs/TODO index f4e3e1f..a692274 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -1,4 +1,4 @@ -version 1.22 July 30, 2004 +version 1.32 April 3, 2005 A Partial List of Missing Features ================================== @@ -14,7 +14,7 @@ b) Better pam/winbind integration (e.g. to handle uid mapping better) c) multi-user mounts - multiplexed sessionsetups over single vc -(ie tcp session) - prettying up needed, and more testing needed +(ie tcp session) - more testing needed d) Kerberos/SPNEGO session setup support - (started) @@ -67,12 +67,15 @@ q) implement support for security and trusted categories of xattrs r) Implement O_DIRECT flag on open (already supported on mount) -KNOWN BUGS (updated December 10, 2004) +KNOWN BUGS (updated April 3, 2005) ==================================== +See http://bugzilla.samba.org - search on product "CifsVFS" for +current bug list. + 1) existing symbolic links (Windows reparse points) are recognized but can not be created remotely. They are implemented for Samba and those that -support the CIFS Unix extensions but Samba has a bug currently handling -symlink text beginning with slash +support the CIFS Unix extensions, although earlier versions of Samba +overly restrict the pathnames. 2) follow_link and readdir code does not follow dfs junctions but recognizes them 3) create of new files to FAT partitions on Windows servers can @@ -98,7 +101,5 @@ there are some easy changes that can be done to parallelize sequential writes, and when signing is disabled to request larger read sizes (larger than negotiated size) and send larger write sizes to modern servers. -4) More exhaustively test the recently added NT4 support against various -NT4 service pack levels, and fix cifs_setattr for setting file times and -size to fall back to level 1 when error invalid level returned. - +4) More exhaustively test against less common servers. More testing +against Windows 9x, Windows ME servers. diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 77da902..ec00d61 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -23,6 +23,7 @@ #define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */ #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ +#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index dd95c2b..b486ba7 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -212,6 +212,8 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 * inode_number, const struct nls_table *nls_codepage); +extern int cifs_convertUCSpath(char *target, const __u16 *source, int maxlen, + const struct nls_table * codepage); #endif /* CONFIG_CIFS_EXPERIMENTAL */ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 814e709..3d036bf 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -72,6 +72,7 @@ struct smb_vol { unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ unsigned direct_io:1; + unsigned remap:1; /* set to remap seven reserved chars in filenames */ unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -771,6 +772,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) vol->noperm = 0; } else if (strnicmp(data, "noperm", 6) == 0) { vol->noperm = 1; + } else if (strnicmp(data, "mapchars", 8) == 0) { + vol->remap = 1; + } else if (strnicmp(data, "nomapchars", 10) == 0) { + vol->remap = 0; } else if (strnicmp(data, "setuids", 7) == 0) { vol->setuids = 1; } else if (strnicmp(data, "nosetuids", 9) == 0) { @@ -1421,6 +1426,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; if(volume_info.server_ino) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; + if(volume_info.remap) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; if(volume_info.no_xattr) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; if(volume_info.direct_io) { diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 7b38d30..f2a0260 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -514,3 +514,72 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) printk( " | %s\n", debug_line); return; } + +#ifdef CONFIG_CIFS_EXPERIMENTAL +/* Windows maps these to the user defined 16 bit Unicode range since they are + reserved symbols (along with \ and /), otherwise illegal to store + in filenames in NTFS */ +#define UNI_ASTERIK cpu_to_le16('*' + 0xF000) +#define UNI_QUESTION cpu_to_le16('?' + 0xF000) +#define UNI_COLON cpu_to_le16(':' + 0xF000) +#define UNI_GRTRTHAN cpu_to_le16('>' + 0xF000) +#define UNI_LESSTHAN cpu_to_le16('<' + 0xF000) +#define UNI_PIPE cpu_to_le16('|' + 0xF000) +#define UNI_SLASH cpu_to_le16('\\' + 0xF000) + +/* Convert 16 bit Unicode pathname from wire format to string in current code + page. Conversion may involve remapping up the seven characters that are + only legal in POSIX-like OS (if they are present in the string). Path + names are little endian 16 bit Unicode on the wire */ +int +cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, + const struct nls_table * cp) +{ + int i,j,len; + wchar_t src_char; + + for(i = 0, j = 0; i < maxlen; i++) { + src_char = le16_to_cpu(source[i]); + switch (src_char) { + case 0: + goto cUCS_out; /* BB check this BB */ + case UNI_COLON: + target[j] = ':'; + break; + case UNI_ASTERIK: + target[j] = '*'; + break; + case UNI_QUESTION: + target[j] = '?'; + break; + case UNI_SLASH: + target[j] = '\\'; /* BB check this - is there risk here of converting path sep BB */ + break; + case UNI_PIPE: + target[j] = '|'; + break; + case UNI_GRTRTHAN: + target[j] = '>'; + break; + case UNI_LESSTHAN: + target[j] = '<'; + default: + len = cp->uni2char(src_char, &target[j], + NLS_MAX_CHARSET_SIZE); + if(len > 0) { + j += len; + continue; + } else { + target[j] = '?'; + } + } + j++; + /* check to make sure we do not overrun callers allocated temp buffer */ + if(j >= (2 * NAME_MAX)) + break; + } +cUCS_out: + target[j] = 0; + return j; +} +#endif /* CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 07838a5..4a33add 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -600,7 +600,14 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, if(unicode) { /* BB fixme - test with long names */ /* Note converted filename can be longer than in unicode */ - pqst->len = cifs_strfromUCS_le((char *)pqst->name,(wchar_t *)filename,len/2,nlt); +#ifdef CONFIG_CIFS_EXPERIMENTAL + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) + pqst->len = cifs_convertUCSpath((char *)pqst->name, + (__le16 *)filename, len/2, nlt); + else +#endif /* CIFS_EXPERIMENTAL */ + pqst->len = cifs_strfromUCS_le((char *)pqst->name, + (wchar_t *)filename,len/2,nlt); } else { pqst->name = filename; pqst->len = len; @@ -829,7 +836,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + smbCalcSize((struct smb_hdr *) cifsFile->srch_inf.ntwrk_buf_start); - tmp_buf = kmalloc(NAME_MAX+1,GFP_KERNEL); + /* To be safe - for UCS to UTF-8 with strings loaded + with the rare long characters alloc more to account for + such multibyte target UTF-8 characters. cifs_unicode.c, + which actually does the conversion, has the same limit */ + tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); for(i=0;(i Date: Thu, 28 Apr 2005 22:41:05 -0700 Subject: [PATCH] cifs: remove a few redundant null pointer checks, and cleanup misc source formatting Mostly suggested by Jesper Juhl Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f54e186..12ba81d 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -284,51 +284,48 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, /* mknod case - do not leave file open */ CIFSSMBClose(xid, pTcon, fileHandle); } else if(newinode) { - pCifsFile = (struct cifsFileInfo *) + pCifsFile = kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); - - if (pCifsFile) { - memset((char *)pCifsFile, 0, - sizeof (struct cifsFileInfo)); - pCifsFile->netfid = fileHandle; - pCifsFile->pid = current->tgid; - pCifsFile->pInode = newinode; - pCifsFile->invalidHandle = FALSE; - pCifsFile->closePend = FALSE; - init_MUTEX(&pCifsFile->fh_sem); - /* put the following in at open now */ - /* pCifsFile->pfile = file; */ - write_lock(&GlobalSMBSeslock); - list_add(&pCifsFile->tlist,&pTcon->openFileList); - pCifsInode = CIFS_I(newinode); - if(pCifsInode) { + + if(pCifsFile == NULL) + goto cifs_create_out; + memset((char *)pCifsFile, 0, + sizeof (struct cifsFileInfo)); + pCifsFile->netfid = fileHandle; + pCifsFile->pid = current->tgid; + pCifsFile->pInode = newinode; + pCifsFile->invalidHandle = FALSE; + pCifsFile->closePend = FALSE; + init_MUTEX(&pCifsFile->fh_sem); + /* set the following in open now + pCifsFile->pfile = file; */ + write_lock(&GlobalSMBSeslock); + list_add(&pCifsFile->tlist,&pTcon->openFileList); + pCifsInode = CIFS_I(newinode); + if(pCifsInode) { /* if readable file instance put first in list*/ - if (write_only == TRUE) { - list_add_tail(&pCifsFile->flist, - &pCifsInode->openFileList); - } else { - list_add(&pCifsFile->flist, - &pCifsInode->openFileList); - } - if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { - pCifsInode->clientCanCacheAll = TRUE; - pCifsInode->clientCanCacheRead = TRUE; - cFYI(1,("Exclusive Oplock granted on inode %p", - newinode)); - } else if((oplock & 0xF) == OPLOCK_READ) - pCifsInode->clientCanCacheRead = TRUE; + if (write_only == TRUE) { + list_add_tail(&pCifsFile->flist, + &pCifsInode->openFileList); + } else { + list_add(&pCifsFile->flist, + &pCifsInode->openFileList); } - write_unlock(&GlobalSMBSeslock); + if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { + pCifsInode->clientCanCacheAll = TRUE; + pCifsInode->clientCanCacheRead = TRUE; + cFYI(1,("Exclusive Oplock for inode %p", + newinode)); + } else if((oplock & 0xF) == OPLOCK_READ) + pCifsInode->clientCanCacheRead = TRUE; } + write_unlock(&GlobalSMBSeslock); } } - - if (buf) - kfree(buf); - if (full_path) - kfree(full_path); +cifs_create_out: + kfree(buf); + kfree(full_path); FreeXid(xid); - return rc; } @@ -375,10 +372,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev } } - if (full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); - return rc; } @@ -447,8 +442,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name if file exists or not but no access BB */ } - if (full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); return ERR_PTR(rc); } @@ -478,8 +472,7 @@ cifs_dir_open(struct inode *inode, struct file *file) cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path)); - if (full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); return rc; } diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index e21f138..1b53dcd 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h @@ -22,94 +22,155 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define SUCCESS 0 /* The request was successful. */ -#define ERRDOS 0x01 /* Error is from the core DOS operating system set */ -#define ERRSRV 0x02 /* Error is generated by the file server daemon */ -#define ERRHRD 0x03 /* Error is a hardware error. */ -#define ERRCMD 0xFF /* Command was not in the "SMB" format. */ +#define SUCCESS 0x00 /* The request was successful. */ +#define ERRDOS 0x01 /* Error is from the core DOS operating system set */ +#define ERRSRV 0x02 /* Error is generated by the file server daemon */ +#define ERRHRD 0x03 /* Error is a hardware error. */ +#define ERRCMD 0xFF /* Command was not in the "SMB" format. */ /* The following error codes may be generated with the SUCCESS error class.*/ -#define SUCCESS 0 /* The request was successful. */ +/*#define SUCCESS 0 The request was successful. */ /* The following error codes may be generated with the ERRDOS error class.*/ -#define ERRbadfunc 1 /* Invalid function. The server did not recognize or could not perform a system call generated by the server, e.g., set the DIRECTORY attribute on a data file, invalid seek mode. */ -#define ERRbadfile 2 /*File not found. The last component of a file's pathname could not be found. */ -#define ERRbadpath 3 /* Directory invalid. A directory component in a pathname could not be found. */ -#define ERRnofids 4 /* Too many open files. The server has no file handles available. */ -#define ERRnoaccess 5 /* Access denied, the client's context does not permit the requested function. This includes the following conditions: invalid rename command, write to Fid open for read only, read on Fid open for write only, attempt to delete a non-empty directory */ -#define ERRbadfid 6 /* Invalid file handle. The file handle specified was not recognized by the server. */ -#define ERRbadmcb 7 /* Memory control blocks destroyed. */ -#define ERRnomem 8 /* Insufficient server memory to perform the requested function. */ -#define ERRbadmem 9 /* Invalid memory block address. */ -#define ERRbadenv 10 /* Invalid environment. */ -#define ERRbadformat 11 /* Invalid format. */ -#define ERRbadaccess 12 /* Invalid open mode. */ -#define ERRbaddata 13 /* Invalid data (generated only by IOCTL calls within the server). */ -#define ERRbaddrive 15 /* Invalid drive specified. */ -#define ERRremcd 16 /* A Delete Directory request attempted to remove the server's current directory. */ -#define ERRdiffdevice 17 /* Not same device (e.g., a cross volume rename was attempted */ -#define ERRnofiles 18 /* A File Search command can find no more files matching the specified criteria. */ -#define ERRgeneral 31 -#define ERRbadshare 32 /* The sharing mode specified for an Open conflicts with existing FIDs on the file. */ -#define ERRlock 33 /* A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process. */ -#define ERRunsup 50 -#define ERRnosuchshare 67 -#define ERRfilexists 80 /* The file named in the request already exists. */ -#define ERRinvparm 87 -#define ERRdiskfull 112 -#define ERRinvname 123 -#define ERRinvlevel 124 -#define ERRdirnotempty 145 -#define ERRnotlocked 158 -#define ERRalreadyexists 183 -#define ERRbadpipe 230 -#define ERRpipebusy 231 -#define ERRpipeclosing 232 -#define ERRnotconnected 233 -#define ERRmoredata 234 -#define ERReasnotsupported 282 -#define ErrQuota 0x200 /* The operation would cause a quota limit to be exceeded. */ -#define ErrNotALink 0x201 /* A link operation was performed on a pathname that - was not a link. */ +#define ERRbadfunc 1 /* Invalid function. The server did not + recognize or could not perform a + system call generated by the server, + e.g., set the DIRECTORY attribute on + a data file, invalid seek mode. */ +#define ERRbadfile 2 /* File not found. The last component + of a file's pathname could not be + found. */ +#define ERRbadpath 3 /* Directory invalid. A directory + component in a pathname could not be + found. */ +#define ERRnofids 4 /* Too many open files. The server has + no file handles available. */ +#define ERRnoaccess 5 /* Access denied, the client's context + does not permit the requested + function. This includes the + following conditions: invalid rename + command, write to Fid open for read + only, read on Fid open for write + only, attempt to delete a non-empty + directory */ +#define ERRbadfid 6 /* Invalid file handle. The file handle + specified was not recognized by the + server. */ +#define ERRbadmcb 7 /* Memory control blocks destroyed. */ +#define ERRnomem 8 /* Insufficient server memory to + perform the requested function. */ +#define ERRbadmem 9 /* Invalid memory block address. */ +#define ERRbadenv 10 /* Invalid environment. */ +#define ERRbadformat 11 /* Invalid format. */ +#define ERRbadaccess 12 /* Invalid open mode. */ +#define ERRbaddata 13 /* Invalid data (generated only by + IOCTL calls within the server). */ +#define ERRbaddrive 15 /* Invalid drive specified. */ +#define ERRremcd 16 /* A Delete Directory request attempted + to remove the server's current + directory. */ +#define ERRdiffdevice 17 /* Not same device (e.g., a cross + volume rename was attempted */ +#define ERRnofiles 18 /* A File Search command can find no + more files matching the specified + criteria. */ +#define ERRgeneral 31 +#define ERRbadshare 32 /* The sharing mode specified for an + Open conflicts with existing FIDs on + the file. */ +#define ERRlock 33 /* A Lock request conflicted with an + existing lock or specified an + invalid mode, or an Unlock requested + attempted to remove a lock held by + another process. */ +#define ERRunsup 50 +#define ERRnosuchshare 67 +#define ERRfilexists 80 /* The file named in the request + already exists. */ +#define ERRinvparm 87 +#define ERRdiskfull 112 +#define ERRinvname 123 +#define ERRinvlevel 124 +#define ERRdirnotempty 145 +#define ERRnotlocked 158 +#define ERRalreadyexists 183 +#define ERRbadpipe 230 +#define ERRpipebusy 231 +#define ERRpipeclosing 232 +#define ERRnotconnected 233 +#define ERRmoredata 234 +#define ERReasnotsupported 282 +#define ErrQuota 0x200 /* The operation would cause a quota + limit to be exceeded. */ +#define ErrNotALink 0x201 /* A link operation was performed on a + pathname that was not a link. */ -/* Following error codes may be generated with the ERRSRV error -class.*/ +/* Following error codes may be generated with the ERRSRV error class.*/ -#define ERRerror 1 /* Non-specific error code. It is returned under the following conditions: resource other than disk space exhausted (e.g. TIDs), first SMB command was not negotiate, multiple negotiates attempted, and internal server error. */ -#define ERRbadpw 2 /* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */ -#define ERRbadtype 3 /* used for indicating DFS referral needed */ -#define ERRaccess 4 /* The client does not have the necessary access rights within the specified context for requested function. */ -#define ERRinvtid 5 /* The Tid specified in a command was invalid. */ -#define ERRinvnetname 6 /* Invalid network name in tree connect. */ -#define ERRinvdevice 7 /* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */ -#define ERRqfull 49 /* Print queue full (files) -- returned by open print file. */ -#define ERRqtoobig 50 /* Print queue full -- no space. */ -#define ERRqeof 51 /* EOF on print queue dump */ -#define ERRinvpfid 52 /* Invalid print file FID. */ -#define ERRsmbcmd 64 /* The server did not recognize the command received. */ -#define ERRsrverror 65 /* The server encountered an internal error, e.g., system file unavailable. */ -#define ERRbadBID 66 /* (obsolete) */ -#define ERRfilespecs 67 /* The Fid and pathname parameters contained an invalid combination of values. */ -#define ERRbadLink 68 /* (obsolete) */ -#define ERRbadpermits 69 /* The access permissions specified for a file or directory are not a valid combination. */ -#define ERRbadPID 70 -#define ERRsetattrmode 71 /* attribute (mode) is invalid */ -#define ERRpaused 81 /* Server is paused */ -#define ERRmsgoff 82 /* reserved - messaging off */ -#define ERRnoroom 83 /* reserved - no room for message */ -#define ERRrmuns 87 /* reserved - too many remote names */ -#define ERRtimeout 88 /* operation timed out */ -#define ERRnoresource 89 /* No resources available for request */ -#define ERRtoomanyuids 90 /* Too many UIDs active on this session */ -#define ERRbaduid 91 /* The UID is not known as a valid user */ -#define ERRusempx 250 /* temporarily unable to use raw */ -#define ERRusestd 251 /* temporarily unable to use either raw or mpx */ -#define ERR_NOTIFY_ENUM_DIR 1024 -#define ERRaccountexpired 2239 -#define ERRbadclient 2240 -#define ERRbadLogonTime 2241 -#define ERRpasswordExpired 2242 -#define ERRnetlogonNotStarted 2455 -#define ERRnosupport 0xFFFF +#define ERRerror 1 /* Non-specific error code. It is + returned under the following + conditions: resource other than disk + space exhausted (e.g. TIDs), first + SMB command was not negotiate, + multiple negotiates attempted, and + internal server error. */ +#define ERRbadpw 2 /* Bad password - name/password pair in + a TreeConnect or Session Setup are + invalid. */ +#define ERRbadtype 3 /* used for indicating DFS referral + needed */ +#define ERRaccess 4 /* The client does not have the + necessary access rights within the + specified context for requested + function. */ +#define ERRinvtid 5 /* The Tid specified in a command was + invalid. */ +#define ERRinvnetname 6 /* Invalid network name in tree + connect. */ +#define ERRinvdevice 7 /* Invalid device - printer request + made to non-printer connection or + non-printer request made to printer + connection. */ +#define ERRqfull 49 /* Print queue full (files) -- returned + by open print file. */ +#define ERRqtoobig 50 /* Print queue full -- no space. */ +#define ERRqeof 51 /* EOF on print queue dump */ +#define ERRinvpfid 52 /* Invalid print file FID. */ +#define ERRsmbcmd 64 /* The server did not recognize the + command received. */ +#define ERRsrverror 65 /* The server encountered an internal + error, e.g., system file + unavailable. */ +#define ERRbadBID 66 /* (obsolete) */ +#define ERRfilespecs 67 /* The Fid and pathname parameters + contained an invalid combination of + values. */ +#define ERRbadLink 68 /* (obsolete) */ +#define ERRbadpermits 69 /* The access permissions specified for + a file or directory are not a valid + combination. */ +#define ERRbadPID 70 +#define ERRsetattrmode 71 /* attribute (mode) is invalid */ +#define ERRpaused 81 /* Server is paused */ +#define ERRmsgoff 82 /* reserved - messaging off */ +#define ERRnoroom 83 /* reserved - no room for message */ +#define ERRrmuns 87 /* reserved - too many remote names */ +#define ERRtimeout 88 /* operation timed out */ +#define ERRnoresource 89 /* No resources available for request + */ +#define ERRtoomanyuids 90 /* Too many UIDs active on this session + */ +#define ERRbaduid 91 /* The UID is not known as a valid user + */ +#define ERRusempx 250 /* temporarily unable to use raw */ +#define ERRusestd 251 /* temporarily unable to use either raw + or mpx */ +#define ERR_NOTIFY_ENUM_DIR 1024 +#define ERRaccountexpired 2239 +#define ERRbadclient 2240 +#define ERRbadLogonTime 2241 +#define ERRpasswordExpired 2242 +#define ERRnetlogonNotStarted 2455 +#define ERRnosupport 0xFFFF -- cgit v0.10.2 From 6c91d362f1e1ebbd4513adb68fc79d552c11e2c0 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:06 -0700 Subject: [PATCH] cifs: finish up of special character mapping capable unicode conversion routine part 2 of 3 Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index db28b56..e7bd93e 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -29,6 +29,7 @@ #include "cifsglob.h" #include "cifsproto.h" #include "cifs_debug.h" +#include "cifsfs.h" void cifs_dump_mem(char *label, void *data, int length) @@ -78,8 +79,9 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, "Display Internal CIFS Data Structures for Debugging\n" "---------------------------------------------------\n"); buf += length; - - length = sprintf(buf, "Servers:\n"); + length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION); + buf += length; + length = sprintf(buf, "Servers:"); buf += length; i = 0; @@ -100,7 +102,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ses->server->secMode, atomic_read(&ses->server->inFlight)); - length = sprintf(buf, "\nMIDs: \n"); + length = sprintf(buf, "\nMIDs:\n"); buf += length; spin_lock(&GlobalMid_Lock); @@ -121,7 +123,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, sprintf(buf, "\n"); buf++; - length = sprintf(buf, "\nShares:\n"); + length = sprintf(buf, "Shares:"); buf += length; i = 0; diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index a17adf4..99a096d 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -76,8 +76,8 @@ cifs_strtoUCS(wchar_t * to, const char *from, int len, charlen)); to[i] = cpu_to_le16(0x003f); /* a question mark */ charlen = 1; - } - to[i] = cpu_to_le16(to[i]); + } else + to[i] = cpu_to_le16(to[i]); } diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index f2a0260..6d7bb42 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -28,6 +28,7 @@ #include "cifs_debug.h" #include "smberr.h" #include "nterr.h" +#include "cifs_unicode.h" extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; @@ -515,7 +516,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) return; } -#ifdef CONFIG_CIFS_EXPERIMENTAL /* Windows maps these to the user defined 16 bit Unicode range since they are reserved symbols (along with \ and /), otherwise illegal to store in filenames in NTFS */ @@ -552,9 +552,12 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, case UNI_QUESTION: target[j] = '?'; break; - case UNI_SLASH: - target[j] = '\\'; /* BB check this - is there risk here of converting path sep BB */ - break; + /* BB We can not handle remapping slash until + all the calls to build_path_from_dentry + are modified, as they use slash as separator BB */ + /* case UNI_SLASH: + target[j] = '\\'; + break;*/ case UNI_PIPE: target[j] = '|'; break; @@ -582,4 +585,71 @@ cUCS_out: target[j] = 0; return j; } -#endif /* CIFS_EXPERIMENTAL */ + +/* Convert 16 bit Unicode pathname to wire format from string in current code + page. Conversion may involve remapping up the seven characters that are + only legal in POSIX-like OS (if they are present in the string). Path + names are little endian 16 bit Unicode on the wire */ +int +cifsConvertToUCS(__le16 * target, const char *source, int maxlen, + const struct nls_table * cp, int mapChars) +{ + int i,j,charlen; + int len_remaining = maxlen; + char src_char; + + if(!mapChars) + return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); + + for(i = 0, j = 0; i < maxlen; j++) { + src_char = source[i]; + switch (src_char) { + case 0: + goto ctoUCS_out; + case ':': + target[j] = cpu_to_le16(UNI_COLON); + break; + case '*': + target[j] = cpu_to_le16(UNI_ASTERIK); + break; + case '?': + target[j] = cpu_to_le16(UNI_QUESTION); + break; + case '<': + target[j] = cpu_to_le16(UNI_LESSTHAN); + break; + case '>': + target[j] = cpu_to_le16(UNI_GRTRTHAN); + break; + case '|': + target[j] = cpu_to_le16(UNI_PIPE); + break; + /* BB We can not handle remapping slash until + all the calls to build_path_from_dentry + are modified, as they use slash as separator BB */ + /* case '\\': + target[j] = cpu_to_le16(UNI_SLASH); + break;*/ + default: + charlen = cp->char2uni(source+i, + len_remaining, target+j); + /* if no match, use question mark, which + at least in some cases servers as wild card */ + if(charlen < 1) { + target[j] = cpu_to_le16(0x003f); + charlen = 1; + } + len_remaining -= charlen; + /* character may take more than one byte in the + the source string, but will take exactly two + bytes in the target string */ + i+= charlen; + continue; + } + i++; /* move to next char in source string */ + len_remaining--; + } + +ctoUCS_out: + return i; +} -- cgit v0.10.2 From 737b758c965a9b223ac1243ab38d9e507ac86c64 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:06 -0700 Subject: [PATCH] cifs: character mapping of special characters (part 3 of 3) Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 412b6d2..de88580 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -9,7 +9,7 @@ POSIX ACL capability bit. Fix packet signing when multiuser mounting with different users from the same client to the same server. Fix oops in cifs_close. Add mount option for remapping reserved characters in filenames (also allow recognizing files with created by SFU which have any -of these seven reserved characters to be recognized). +of these seven reserved characters, except backslash, to be recognized). Version 1.31 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index 83e0545..93900fc 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -376,8 +376,8 @@ A partial list of the supported mount options follows: attributes) to the server (default) e.g. via setfattr and getfattr utilities. nouser_xattr Do not allow getfattr/setfattr to get/set xattrs - mapchars Translate the seven reserved characters - *?<>|:\ + mapchars Translate six of the seven reserved characters (not backslash) + *?<>|: to the remap range (above 0xF000), which also allows the CIFS client to recognize files created with such characters by Windows's POSIX emulation. This can diff --git a/fs/cifs/TODO b/fs/cifs/TODO index a692274..1e8490e 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -67,6 +67,9 @@ q) implement support for security and trusted categories of xattrs r) Implement O_DIRECT flag on open (already supported on mount) +s) Allow remapping of last remaining character (\) to +0xF000 which +(this character is valid for POSIX but not for Windows) + KNOWN BUGS (updated April 3, 2005) ==================================== See http://bugzilla.samba.org - search on product "CifsVFS" for diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ae48ef0..3d5365b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -191,13 +191,13 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) #ifdef CONFIG_CIFS_EXPERIMENTAL /* BB we could add a second check for a QFS Unix capability bit */ if (pTcon->ses->capabilities & CAP_UNIX) - rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf, cifs_sb->local_nls); + rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf); /* Only need to call the old QFSInfo if failed on newer one */ if(rc) #endif /* CIFS_EXPERIMENTAL */ - rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls); + rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* int f_type; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index b486ba7..0010511 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -57,10 +57,11 @@ extern int decode_negTokenInit(unsigned char *security_blob, int length, extern int cifs_inet_pton(int, char * source, void *dst); extern int map_smb_to_linux_error(struct smb_hdr *smb); extern void header_assemble(struct smb_hdr *, char /* command */ , - const struct cifsTconInfo *, int - /* length of fixed section (word count) in two byte units */ + const struct cifsTconInfo *, int /* specifies length + of fixed section (word count) in two byte units */ ); -extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *); +extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, + struct cifsTconInfo *); extern void DeleteOplockQEntry(struct oplock_q_entry *); extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); extern u64 cifs_UnixTimeToNT(struct timespec); @@ -88,7 +89,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, const char *searchName, const struct nls_table *nls_codepage, - __u16 *searchHandle, struct cifs_search_info * psrch_inf); + __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map); extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, __u16 searchHandle, struct cifs_search_info * psrch_inf); @@ -99,42 +100,42 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_ALL_INFO * findData, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap); extern int CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_UNIX_BASIC_INFO * pFindData, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap); extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, const unsigned char *searchName, unsigned char **targetUNCs, unsigned int *number_of_UNC_in_array, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap); extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap); extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, - const char *old_path, const struct nls_table *nls_codepage, - unsigned int *pnum_referrals, unsigned char ** preferrals); + const char *old_path, + const struct nls_table *nls_codepage, + unsigned int *pnum_referrals, + unsigned char ** preferrals, + int remap); extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, - struct kstatfs *FSData, - const struct nls_table *nls_codepage); + struct kstatfs *FSData); extern int CIFSSMBQFSAttributeInfo(const int xid, - struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage); -extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage); -extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage); + struct cifsTconInfo *tcon); +extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); +extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon); extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, - struct kstatfs *FSData, const struct nls_table *nls_codepage); + struct kstatfs *FSData); extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName, const FILE_BASIC_INFO * data, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, __u16 fid); #if 0 @@ -143,36 +144,49 @@ extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, const struct nls_table *nls_codepage); #endif /* possibly unneeded function */ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, - const char *fileName, __u64 size,int setAllocationSizeFlag, - const struct nls_table *nls_codepage); + const char *fileName, __u64 size, + int setAllocationSizeFlag, + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, - __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag); + __u64 size, __u16 fileHandle,__u32 opener_pid, + int AllocSizeFlag); extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, char *full_path, __u64 mode, __u64 uid, - __u64 gid, dev_t dev, const struct nls_table *nls_codepage); + __u64 gid, dev_t dev, + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, const char *newName, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, - const char *name, const struct nls_table *nls_codepage); + const char *name, const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *name, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, - int netfid, char * target_name, const struct nls_table *nls_codepage); + int netfid, char * target_name, + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, @@ -192,7 +206,7 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int disposition, const int access_flags, const int omode, __u16 * netfid, int *pOplock, FILE_ALL_INFO *, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap); extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, const int smb_file_id); @@ -211,10 +225,13 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, const char __user *buf,const int long_op); extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 * inode_number, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); +#endif /* CONFIG_CIFS_EXPERIMENTAL */ extern int cifs_convertUCSpath(char *target, const __u16 *source, int maxlen, const struct nls_table * codepage); -#endif /* CONFIG_CIFS_EXPERIMENTAL */ +extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen, + const struct nls_table * cp, int mapChars); extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, const __u16 netfid, const __u64 len, @@ -243,29 +260,31 @@ extern int CIFSSMBCopy(int xid, const char *fromName, const __u16 target_tid, const char *toName, const int flags, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, - const int notify_subdirs,const __u16 netfid,__u32 filter, - const struct nls_table *nls_codepage); + const int notify_subdirs,const __u16 netfid, + __u32 filter, const struct nls_table *nls_codepage); extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char * EAData, - size_t bufsize, const struct nls_table *nls_codepage); + size_t bufsize, const struct nls_table *nls_codepage, + int remap_special_chars); extern ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon, const unsigned char * searchName,const unsigned char * ea_name, unsigned char * ea_value, size_t buf_size, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap_special_chars); extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, const char * ea_name, const void * ea_value, const __u16 ea_value_len, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap_special_chars); extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char *acl_inf, const int buflen,const int acl_type, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap_special_chars); extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *fileName, const char *local_acl, const int buflen, const int acl_type, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap_special_chars); extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, const int netfid, __u64 * pExtAttrBits, __u64 *pMask); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 237e3bf..f7c4914 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -538,8 +538,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) } int -CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, - const char *fileName, const struct nls_table *nls_codepage) +CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, + const struct nls_table *nls_codepage, int remap) { DELETE_FILE_REQ *pSMB = NULL; DELETE_FILE_RSP *pSMBr = NULL; @@ -555,9 +555,8 @@ DelFileRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->fileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -589,8 +588,8 @@ DelFileRetry: } int -CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, - const char *dirName, const struct nls_table *nls_codepage) +CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, + const struct nls_table *nls_codepage, int remap) { DELETE_DIRECTORY_REQ *pSMB = NULL; DELETE_DIRECTORY_RSP *pSMBr = NULL; @@ -606,9 +605,8 @@ RmDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -639,7 +637,7 @@ RmDirRetry: int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, - const char *name, const struct nls_table *nls_codepage) + const char *name, const struct nls_table *nls_codepage, int remap) { int rc = 0; CREATE_DIRECTORY_REQ *pSMB = NULL; @@ -655,9 +653,8 @@ MkDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + name_len = cifsConvertToUCS((__u16 *) pSMB->DirName, name, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -690,7 +687,7 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int openDisposition, const int access_flags, const int create_options, __u16 * netfid, int *pOplock, FILE_ALL_INFO * pfile_info, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { int rc = -EACCES; OPEN_REQ *pSMB = NULL; @@ -710,10 +707,8 @@ openRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { count = 1; /* account for one byte pad to word boundary */ name_len = - cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1), - fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) (pSMB->fileName + 1), + fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->NameLength = cpu_to_le16(name_len); @@ -1108,7 +1103,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { int rc = 0; RENAME_REQ *pSMB = NULL; @@ -1131,18 +1126,16 @@ renameRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0x04; /* pad */ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = - cifs_strtoUCS((wchar_t *) & pSMB-> - OldFileName[name_len + 2], toName, PATH_MAX, - nls_codepage); + cifsConvertToUCS((__u16 *) &pSMB->OldFileName[name_len + 2], + toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ @@ -1182,7 +1175,8 @@ renameRetry: } int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, - int netfid, char * target_name, const struct nls_table * nls_codepage) + int netfid, char * target_name, + const struct nls_table * nls_codepage, int remap) { struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; @@ -1227,9 +1221,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, /* unicode only call */ if(target_name == NULL) { sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); - len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage); + len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name, + dummy_string, 24, nls_codepage, remap); } else { - len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, PATH_MAX, nls_codepage); + len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name, + target_name, PATH_MAX, nls_codepage, remap); } rename_info->target_name_len = cpu_to_le32(2 * len_of_str); count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; @@ -1263,7 +1259,7 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, int CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, const __u16 target_tid, const char *toName, const int flags, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { int rc = 0; COPY_REQ *pSMB = NULL; @@ -1285,18 +1281,16 @@ copyRetry: pSMB->Flags = cpu_to_le16(flags & COPY_TREE); if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, - fromName, - PATH_MAX /* find define for this maxpathcomponent */, - nls_codepage); + name_len = cifsConvertToUCS((__u16 *) pSMB->OldFileName, + fromName, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0x04; /* pad */ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; - name_len2 = cifs_strtoUCS((wchar_t *) & pSMB-> - OldFileName[name_len + 2], toName, PATH_MAX, - nls_codepage); + name_len2 = cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2], + toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ @@ -1425,7 +1419,7 @@ createSymLinkRetry: int CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -1444,9 +1438,8 @@ createHardLinkRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + name_len = cifsConvertToUCS((__u16 *) pSMB->FileName, toName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -1468,9 +1461,8 @@ createHardLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifs_strtoUCS((wchar_t *) data_offset, fromName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) data_offset, fromName, PATH_MAX, + nls_codepage, remap); name_len_target++; /* trailing null */ name_len_target *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -1512,7 +1504,7 @@ createHardLinkRetry: int CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { int rc = 0; NT_RENAME_REQ *pSMB = NULL; @@ -1539,17 +1531,15 @@ winCreateHardLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0; /* pad */ pSMB->OldFileName[name_len + 1] = 0x04; name_len2 = - cifs_strtoUCS((wchar_t *) & pSMB-> - OldFileName[name_len + 2], toName, PATH_MAX, - nls_codepage); + cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2], + toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ @@ -1659,6 +1649,7 @@ querySymLinkRetry: name_len = UniStrnlen((wchar_t *) ((char *) &pSMBr->hdr.Protocol +data_offset), min_t(const int, buflen,count) / 2); + /* BB FIXME investigate remapping reserved chars here */ cifs_strfromUCS_le(symlinkinfo, (wchar_t *) ((char *)&pSMBr->hdr.Protocol + data_offset), @@ -1793,7 +1784,8 @@ static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace } /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */ -static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,const int acl_type,const int size_of_data_area) +static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen, + const int acl_type,const int size_of_data_area) { int size = 0; int i; @@ -1912,7 +1904,7 @@ int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char *acl_inf, const int buflen, const int acl_type, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { /* SMB_QUERY_POSIX_ACL */ TRANSACTION2_QPI_REQ *pSMB = NULL; @@ -1932,8 +1924,8 @@ queryAclRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->FileName[name_len] = 0; @@ -1997,8 +1989,9 @@ queryAclRetry: int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *fileName, - const char *local_acl, const int buflen, const int acl_type, - const struct nls_table *nls_codepage) + const char *local_acl, const int buflen, + const int acl_type, + const struct nls_table *nls_codepage, int remap) { struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; @@ -2016,8 +2009,8 @@ setAclRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2161,7 +2154,7 @@ int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_ALL_INFO * pFindData, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { /* level 263 SMB_QUERY_FILE_ALL_INFO */ TRANSACTION2_QPI_REQ *pSMB = NULL; @@ -2180,9 +2173,8 @@ QPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2243,7 +2235,7 @@ int CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_UNIX_BASIC_INFO * pFindData, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { /* SMB_QUERY_FILE_UNIX_BASIC */ TRANSACTION2_QPI_REQ *pSMB = NULL; @@ -2262,9 +2254,8 @@ UnixQPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2344,7 +2335,7 @@ findUniqueRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX + cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -2408,7 +2399,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, const char *searchName, const struct nls_table *nls_codepage, __u16 * pnetfid, - struct cifs_search_info * psrch_inf) + struct cifs_search_info * psrch_inf, int remap) { /* level 257 SMB_ */ TRANSACTION2_FFIRST_REQ *pSMB = NULL; @@ -2419,7 +2410,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, int name_len; __u16 params, byte_count; - cFYI(1, ("In FindFirst")); + cFYI(1, ("In FindFirst for %s",searchName)); findFirstRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, @@ -2429,12 +2420,20 @@ findFirstRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName,searchName, - PATH_MAX, nls_codepage); - name_len++; /* trailing null */ + cifsConvertToUCS((__u16 *) pSMB->FileName,searchName, + PATH_MAX, nls_codepage, remap); + /* We can not add the asterik earlier in case + it got remapped to 0xF03A as if it were part of the + directory name instead of a wildcard */ name_len *= 2; + pSMB->FileName[name_len] = '\\'; + pSMB->FileName[name_len+1] = 0; + pSMB->FileName[name_len+2] = '*'; + pSMB->FileName[name_len+3] = 0; + name_len += 4; /* now the trailing null */ pSMB->FileName[name_len] = 0; /* null terminate just in case */ pSMB->FileName[name_len+1] = 0; + name_len += 2; } else { /* BB add check for overrun of SMB buf BB */ name_len = strnlen(searchName, PATH_MAX); name_len++; /* trailing null */ @@ -2691,7 +2690,7 @@ int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 * inode_number, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { int rc = 0; TRANSACTION2_QPI_REQ *pSMB = NULL; @@ -2712,8 +2711,8 @@ GetInodeNumberRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, - PATH_MAX,nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + PATH_MAX,nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2787,7 +2786,7 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, const unsigned char *searchName, unsigned char **targetUNCs, unsigned int *number_of_UNC_in_array, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { /* TRANS2_GET_DFS_REFERRAL */ TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; @@ -2823,10 +2822,8 @@ getDFSRetry: if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; name_len = - cifs_strtoUCS((wchar_t *) pSMB->RequestFileName, - searchName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->RequestFileName, + searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2954,8 +2951,7 @@ GetDFSRefExit: } int -CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, - struct kstatfs *FSData, const struct nls_table *nls_codepage) +CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) { /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -3038,8 +3034,7 @@ QFSInfoRetry: } int -CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage) +CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon) { /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -3107,8 +3102,7 @@ QFSAttributeRetry: } int -CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage) +CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon) { /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -3161,8 +3155,8 @@ QFSDeviceRetry: else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = - (FILE_SYSTEM_DEVICE_INFO - *) (((char *) &pSMBr->hdr.Protocol) + + (FILE_SYSTEM_DEVICE_INFO *) + (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsDevInfo, response_data, sizeof (FILE_SYSTEM_DEVICE_INFO)); @@ -3177,8 +3171,7 @@ QFSDeviceRetry: } int -CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage) +CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon) { /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -3249,7 +3242,7 @@ QFSUnixRetry: int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, - struct kstatfs *FSData, const struct nls_table *nls_codepage) + struct kstatfs *FSData) { /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -3341,7 +3334,8 @@ QFSPosixRetry: int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName, - __u64 size, int SetAllocation, const struct nls_table *nls_codepage) + __u64 size, int SetAllocation, + const struct nls_table *nls_codepage, int remap) { struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; @@ -3360,9 +3354,8 @@ SetEOFRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -3595,7 +3588,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName, const FILE_BASIC_INFO * data, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -3615,9 +3608,8 @@ SetTimesRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -3697,7 +3689,7 @@ SetAttrLgcyRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, + ConvertToUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX, nls_codepage); name_len++; /* trailing null */ name_len *= 2; @@ -3727,8 +3719,9 @@ SetAttrLgcyRetry: int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, - char *fileName, __u64 mode, __u64 uid, __u64 gid, - dev_t device, const struct nls_table *nls_codepage) + char *fileName, __u64 mode, __u64 uid, __u64 gid, + dev_t device, const struct nls_table *nls_codepage, + int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -3747,9 +3740,8 @@ setPermsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -3872,7 +3864,7 @@ ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char * EAData, size_t buf_size, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { /* BB assumes one setup word */ TRANSACTION2_QPI_REQ *pSMB = NULL; @@ -3893,9 +3885,8 @@ QAllEAsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -4017,7 +4008,7 @@ QAllEAsRetry: ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon, const unsigned char * searchName,const unsigned char * ea_name, unsigned char * ea_value, size_t buf_size, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { TRANSACTION2_QPI_REQ *pSMB = NULL; TRANSACTION2_QPI_RSP *pSMBr = NULL; @@ -4037,9 +4028,8 @@ QEARetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -4165,7 +4155,8 @@ QEARetry: int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, const char * ea_name, const void * ea_value, - const __u16 ea_value_len, const struct nls_table *nls_codepage) + const __u16 ea_value_len, const struct nls_table *nls_codepage, + int remap) { struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; @@ -4184,9 +4175,8 @@ SetEARetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3d036bf..1f22b85 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -924,14 +924,15 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, - const char *old_path, const struct nls_table *nls_codepage) + const char *old_path, const struct nls_table *nls_codepage, + int remap) { unsigned char *referrals = NULL; unsigned int num_referrals; int rc = 0; rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, - &num_referrals, &referrals); + &num_referrals, &referrals, remap); /* BB Add in code to: if valid refrl, if not ip address contact the helper that resolves tcp names, mount to it, try to @@ -946,7 +947,8 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage, - unsigned int *pnum_referrals, unsigned char ** preferrals) + unsigned int *pnum_referrals, + unsigned char ** preferrals, int remap) { char *temp_unc; int rc = 0; @@ -971,7 +973,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, } if (rc == 0) rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, - pnum_referrals, nls_codepage); + pnum_referrals, nls_codepage, remap); return rc; } @@ -1456,11 +1458,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if ((strchr(volume_info.UNC + 3, '\\') == NULL) && (strchr(volume_info.UNC + 3, '/') == NULL)) { - rc = connect_to_dfs_path(xid, - pSesInfo, - "", - cifs_sb-> - local_nls); + rc = connect_to_dfs_path(xid, pSesInfo, + "", cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if(volume_info.UNC) kfree(volume_info.UNC); FreeXid(xid); @@ -1523,10 +1524,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, tcon->ses = pSesInfo; /* do not care if following two calls succeed - informational only */ - CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls); - CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls); + CIFSSMBQFSDeviceInfo(xid, tcon); + CIFSSMBQFSAttributeInfo(xid, tcon); if (tcon->ses->capabilities & CAP_UNIX) { - if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) { + if(!CIFSSMBQFSUnixInfo(xid, tcon)) { if(!volume_info.no_psx_acl) { if(CIFS_UNIX_POSIX_ACL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 12ba81d..e3137aa 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -101,68 +101,15 @@ cifs_bp_rename_retry: return full_path; } -/* Note: caller must free return buffer */ -char * -build_wildcard_path_from_dentry(struct dentry *direntry) +/* char * build_wildcard_path_from_dentry(struct dentry *direntry) { - struct dentry *temp; - int namelen = 0; - char *full_path; - - if(direntry == NULL) - return NULL; /* not much we can do if dentry is freed and - we need to reopen the file after it was closed implicitly - when the server crashed */ - -cifs_bwp_rename_retry: - for (temp = direntry; !IS_ROOT(temp);) { - namelen += (1 + temp->d_name.len); - temp = temp->d_parent; - if(temp == NULL) { - cERROR(1,("corrupt dentry")); - return NULL; - } - } - - full_path = kmalloc(namelen+3, GFP_KERNEL); if(full_path == NULL) return full_path; full_path[namelen] = '\\'; full_path[namelen+1] = '*'; - full_path[namelen+2] = 0; /* trailing null */ - - for (temp = direntry; !IS_ROOT(temp);) { - namelen -= 1 + temp->d_name.len; - if (namelen < 0) { - break; - } else { - full_path[namelen] = '\\'; - strncpy(full_path + namelen + 1, temp->d_name.name, - temp->d_name.len); - cFYI(0, (" name: %s ", full_path + namelen)); - } - temp = temp->d_parent; - if(temp == NULL) { - cERROR(1,("corrupt dentry")); - kfree(full_path); - return NULL; - } - } - if (namelen != 0) { - cERROR(1, - ("We did not end path lookup where we expected namelen is %d", - namelen)); - /* presumably this is only possible if we were racing with a rename - of one of the parent directories (we can not lock the dentries - above us to prevent this, but retrying should be harmless) */ - kfree(full_path); - namelen = 0; - goto cifs_bwp_rename_retry; - } - - return full_path; -} + full_path[namelen+2] = 0; +BB remove above eight lines BB */ /* Inode operations in similar order to how they appear in the Linux file fs.h */ @@ -235,7 +182,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, - &fileHandle, &oplock, buf, cifs_sb->local_nls); + &fileHandle, &oplock, buf, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cFYI(1, ("cifs_create returned 0x%x ", rc)); } else { @@ -248,13 +196,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, (__u64)current->euid, (__u64)current->egid, 0 /* dev */, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, 0 /* dev */, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { /* BB implement via Windows security descriptors */ @@ -356,11 +308,15 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,(__u64)current->euid,(__u64)current->egid, - device_number, cifs_sb->local_nls); + device_number, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, - device_number, cifs_sb->local_nls); + device_number, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } if(!rc) { @@ -447,36 +403,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name return ERR_PTR(rc); } -int -cifs_dir_open(struct inode *inode, struct file *file) -{ /* NB: currently unused since searches are opened in readdir */ - int rc = 0; - int xid; - struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; - char *full_path = NULL; - - xid = GetXid(); - - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; - - if(file->f_dentry) { - down(&file->f_dentry->d_sb->s_vfs_rename_sem); - full_path = build_wildcard_path_from_dentry(file->f_dentry); - up(&file->f_dentry->d_sb->s_vfs_rename_sem); - } else { - FreeXid(xid); - return -EIO; - } - - cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path)); - - kfree(full_path); - FreeXid(xid); - return rc; -} - static int cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) { diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 9d24c40..7d2a920 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c @@ -92,7 +92,8 @@ int cifs_dir_notify(struct file * file, unsigned long arg) cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ | SYNCHRONIZE, 0 /* create options */, - &netfid, &oplock,NULL, cifs_sb->local_nls); + &netfid, &oplock,NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); /* BB fixme - add this handle to a notify handle list */ if(rc) { cERROR(1,("Could not open directory for notify")); /* BB remove BB */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 9c77550..1df26dd 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -254,7 +254,8 @@ int cifs_open(struct inode *inode, struct file *file) } rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, - cifs_sb->local_nls); + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags + & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cFYI(1, ("cifs_open returned 0x%x ", rc)); goto out; @@ -287,7 +288,9 @@ int cifs_open(struct inode *inode, struct file *file) CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, (__u64)-1, (__u64)-1, 0 /* dev */, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { /* BB implement via Windows security descriptors eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, @@ -387,7 +390,8 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, } */ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, NULL, - cifs_sb->local_nls); + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { up(&pCifsFile->fh_sem); cFYI(1, ("cifs_open returned 0x%x ", rc)); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index d73b0aa..6709472 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -44,7 +44,8 @@ int cifs_get_inode_info_unix(struct inode **pinode, cFYI(1, (" Getting info on %s ", search_path)); /* could have done a find first instead but this returns more info */ rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, - cifs_sb->local_nls); + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */ if (rc) { @@ -63,7 +64,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, strncat(tmp_path, search_path, MAX_PATHCONF); rc = connect_to_dfs_path(xid, pTcon->ses, /* treename + */ tmp_path, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); kfree(tmp_path); /* BB fix up inode etc. */ @@ -210,7 +213,8 @@ int cifs_get_inode_info(struct inode **pinode, pfindData = (FILE_ALL_INFO *)buf; /* could do find first instead but this returns more info */ rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, - cifs_sb->local_nls); + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ if (rc) { @@ -230,7 +234,9 @@ int cifs_get_inode_info(struct inode **pinode, strncat(tmp_path, search_path, MAX_PATHCONF); rc = connect_to_dfs_path(xid, pTcon->ses, /* treename + */ tmp_path, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); kfree(tmp_path); /* BB fix up inode etc. */ } else if (rc) { @@ -268,7 +274,9 @@ int cifs_get_inode_info(struct inode **pinode, rc1 = CIFSGetSrvInodeNumber(xid, pTcon, search_path, &inode_num, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if(rc1) { cFYI(1,("GetSrvInodeNum rc %d", rc1)); /* BB EOPNOSUPP disable SERVER_INUM? */ @@ -410,7 +418,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) FreeXid(xid); return -ENOMEM; } - rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); + rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { direntry->d_inode->i_nlink--; @@ -422,10 +431,14 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, - &netfid, &oplock, NULL, cifs_sb->local_nls); + &netfid, &oplock, NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); direntry->d_inode->i_nlink--; } @@ -439,7 +452,9 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) if (!(pTcon->ses->flags & CIFS_SES_NT4)) rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); else rc = -EOPNOTSUPP; @@ -461,7 +476,9 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) FILE_OPEN, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, 0, &netfid, &oplock, NULL, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { rc = CIFSSMBSetFileTimes(xid, pTcon, pinfo_buf, @@ -472,8 +489,10 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) kfree(pinfo_buf); } if (rc==0) { - rc = CIFSSMBDelFile(xid, pTcon, full_path, - cifs_sb->local_nls); + rc = CIFSSMBDelFile(xid, pTcon, full_path, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { direntry->d_inode->i_nlink--; } else if (rc == -ETXTBSY) { @@ -485,11 +504,15 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, &netfid, &oplock, NULL, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); direntry->d_inode->i_nlink--; } @@ -534,7 +557,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) return -ENOMEM; } /* BB add setting the equivalent of mode via CreateX w/ACLs */ - rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls); + rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); d_drop(direntry); @@ -558,12 +582,16 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) (__u64)current->euid, (__u64)current->egid, 0 /* dev_t */, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, 0 /* dev_t */, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { /* BB to be implemented via Windows secrty descriptors @@ -600,7 +628,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) return -ENOMEM; } - rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls); + rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { inode->i_nlink--; @@ -653,7 +682,9 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, } rc = CIFSSMBRename(xid, pTcon, fromName, toName, - cifs_sb_source->local_nls); + cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == -EEXIST) { /* check if they are the same file because rename of hardlinked files is a noop */ @@ -665,11 +696,16 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, if (info_buf_source != NULL) { info_buf_target = info_buf_source + 1; rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, - info_buf_source, cifs_sb_source->local_nls); + info_buf_source, cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == 0) { rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName, info_buf_target, - cifs_sb_target->local_nls); + cifs_sb_target->local_nls, + /* remap based on source sb */ + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } if ((rc == 0) && (info_buf_source->UniqueId == @@ -685,7 +721,9 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, cifs_unlink(target_inode, target_direntry); rc = CIFSSMBRename(xid, pTcon, fromName, toName, - cifs_sb_source->local_nls); + cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags + & CIFS_MOUNT_MAP_SPECIAL_CHR); } kfree(info_buf_source); } /* if we can not get memory just leave rc as EEXIST */ @@ -705,10 +743,14 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, might not right be right access to request */ rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, CREATE_NOT_DIR, &netfid, &oplock, NULL, - cifs_sb_source->local_nls); + cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName, - cifs_sb_source->local_nls); + cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); } } @@ -962,7 +1004,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) it by handle */ rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, FALSE, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); } @@ -999,7 +1043,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, - 0 /* dev_t */, cifs_sb->local_nls); + 0 /* dev_t */, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); else if (attrs->ia_valid & ATTR_MODE) { if ((mode & S_IWUGO) == 0) /* not writeable */ { if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) @@ -1048,7 +1094,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) via Handle (SetFileInfo) instead of by path */ if (!(pTcon->ses->flags & CIFS_SES_NT4)) rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); else rc = -EOPNOTSUPP; @@ -1063,7 +1111,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, &netfid, &oplock, - NULL, cifs_sb->local_nls); + NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf, netfid); diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 1455810..bde0fab 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -59,10 +59,14 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, - cifs_sb_target->local_nls); + cifs_sb_target->local_nls, + cifs_sb_target->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); else { rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, - cifs_sb_target->local_nls); + cifs_sb_target->local_nls, + cifs_sb_target->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if(rc == -EIO) rc = -EOPNOTSUPP; } @@ -260,7 +264,10 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) cifs_sb->local_nls); else { rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, - OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls); + OPEN_REPARSE_POINT,&fid, &oplock, NULL, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if(!rc) { rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, tmpbuffer, @@ -279,7 +286,10 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); strncat(tmp_path, full_path, MAX_PATHCONF); rc = get_dfs_path(xid, pTcon->ses, tmp_path, - cifs_sb->local_nls, &num_referrals, &referrals); + cifs_sb->local_nls, + &num_referrals, &referrals, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc)); if((num_referrals == 0) && (rc == 0)) rc = -EACCES; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 4a33add..7ca876b 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -314,7 +314,7 @@ static int initiate_cifs_search(const int xid, struct file *file) return -EINVAL; down(&file->f_dentry->d_sb->s_vfs_rename_sem); - full_path = build_wildcard_path_from_dentry(file->f_dentry); + full_path = build_path_from_dentry(file->f_dentry); up(&file->f_dentry->d_sb->s_vfs_rename_sem); if(full_path == NULL) { @@ -333,8 +333,9 @@ ffirst_retry: cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; } - rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, - &cifsFile->netfid, &cifsFile->srch_inf); + rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, + &cifsFile->netfid, &cifsFile->srch_inf, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if(rc == 0) cifsFile->invalidHandle = FALSE; if((rc == -EOPNOTSUPP) && @@ -600,12 +601,10 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, if(unicode) { /* BB fixme - test with long names */ /* Note converted filename can be longer than in unicode */ -#ifdef CONFIG_CIFS_EXPERIMENTAL if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) pqst->len = cifs_convertUCSpath((char *)pqst->name, (__le16 *)filename, len/2, nlt); else -#endif /* CIFS_EXPERIMENTAL */ pqst->len = cifs_strfromUCS_le((char *)pqst->name, (wchar_t *)filename,len/2,nlt); } else { @@ -849,19 +848,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) break; } - /* BB FIXME - need to enable the below code BB */ - - /* if((!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) || - (cifsFile->srch_inf.info_level != - something that supports server inodes)) { - create dentry - create inode - fill in inode new_inode (getting local i_ino) - } - also create local inode for performance reasons (so we - have a cache of inode metadata) unless this new mount - parm says otherwise */ - rc = cifs_filldir(current_entry, file, filldir, direntry,tmp_buf); file->f_pos++; diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 9a41bee..c1e02ef 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -83,7 +83,8 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name) ea_name+=5; /* skip past user. prefix */ rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,NULL, - (__u16)0, cifs_sb->local_nls); + (__u16)0, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } remove_ea_exit: if (full_path) @@ -147,14 +148,16 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, } ea_name += 5; /* skip past user. prefix */ rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, - (__u16)value_size, cifs_sb->local_nls); + (__u16)value_size, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) goto set_ea_exit; ea_name += 4; /* skip past os2. prefix */ rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, - (__u16)value_size, cifs_sb->local_nls); + (__u16)value_size, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else { int temp; temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS, @@ -164,7 +167,9 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, if(sb->s_flags & MS_POSIXACL) rc = CIFSSMBSetPosixACL(xid, pTcon,full_path, ea_value, (const int)value_size, - ACL_TYPE_ACCESS,cifs_sb->local_nls); + ACL_TYPE_ACCESS,cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); cFYI(1,("set POSIX ACL rc %d",rc)); #else cFYI(1,("set POSIX ACL not supported")); @@ -174,7 +179,9 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, if(sb->s_flags & MS_POSIXACL) rc = CIFSSMBSetPosixACL(xid, pTcon,full_path, ea_value, (const int)value_size, - ACL_TYPE_DEFAULT, cifs_sb->local_nls); + ACL_TYPE_DEFAULT, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); cFYI(1,("set POSIX default ACL rc %d",rc)); #else cFYI(1,("set default POSIX ACL not supported")); @@ -240,20 +247,24 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, } /* BB add else when above is implemented */ ea_name += 5; /* skip past user. prefix */ rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, - buf_size, cifs_sb->local_nls); + buf_size, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) goto get_ea_exit; ea_name += 4; /* skip past os2. prefix */ rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, - buf_size, cifs_sb->local_nls); + buf_size, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { #ifdef CONFIG_CIFS_POSIX if(sb->s_flags & MS_POSIXACL) rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, ea_value, buf_size, ACL_TYPE_ACCESS, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); #else cFYI(1,("query POSIX ACL not supported yet")); #endif /* CONFIG_CIFS_POSIX */ @@ -262,7 +273,9 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, if(sb->s_flags & MS_POSIXACL) rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, ea_value, buf_size, ACL_TYPE_DEFAULT, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); #else cFYI(1,("query POSIX default ACL not supported yet")); #endif @@ -328,7 +341,9 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) search server for EAs or streams to returns as xattrs */ rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (full_path) kfree(full_path); -- cgit v0.10.2 From d0724714fd49aeec1383b94807174de7e96021bf Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:06 -0700 Subject: [PATCH] cifs: Fix PPC64 compile error .. and do not double endian convert the special characters whem mounted with mapchars mount parm. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 6d7bb42..75fd3bd 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -519,13 +519,13 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) /* Windows maps these to the user defined 16 bit Unicode range since they are reserved symbols (along with \ and /), otherwise illegal to store in filenames in NTFS */ -#define UNI_ASTERIK cpu_to_le16('*' + 0xF000) -#define UNI_QUESTION cpu_to_le16('?' + 0xF000) -#define UNI_COLON cpu_to_le16(':' + 0xF000) -#define UNI_GRTRTHAN cpu_to_le16('>' + 0xF000) -#define UNI_LESSTHAN cpu_to_le16('<' + 0xF000) -#define UNI_PIPE cpu_to_le16('|' + 0xF000) -#define UNI_SLASH cpu_to_le16('\\' + 0xF000) +#define UNI_ASTERIK (__u16) ('*' + 0xF000) +#define UNI_QUESTION (__u16) ('?' + 0xF000) +#define UNI_COLON (__u16) (':' + 0xF000) +#define UNI_GRTRTHAN (__u16) ('>' + 0xF000) +#define UNI_LESSTHAN (__u16) ('<' + 0xF000) +#define UNI_PIPE (__u16) ('|' + 0xF000) +#define UNI_SLASH (__u16) ('\\' + 0xF000) /* Convert 16 bit Unicode pathname from wire format to string in current code page. Conversion may involve remapping up the seven characters that are @@ -536,7 +536,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, const struct nls_table * cp) { int i,j,len; - wchar_t src_char; + __u16 src_char; for(i = 0, j = 0; i < maxlen; i++) { src_char = le16_to_cpu(source[i]); -- cgit v0.10.2 From 848f3fce45d2ba93e10b5e9d65bcae0d9269ad0d Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:07 -0700 Subject: [PATCH] cifs: Do not interpret oplock break responses as responses to an unrelated command .. even if the multiplex ids match. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index de88580..de63a0e 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -10,6 +10,8 @@ different users from the same client to the same server. Fix oops in cifs_close. Add mount option for remapping reserved characters in filenames (also allow recognizing files with created by SFU which have any of these seven reserved characters, except backslash, to be recognized). +Fix invalid transact2 message (we were sometimes trying to interpret +oplock breaks as SMB responses). Version 1.31 ------------ diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index e7bd93e..efa0991 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -111,7 +111,12 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, mid_q_entry, qhead); if(mid_entry) { - length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk,mid_entry->mid); + length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n", + mid_entry->midState, + (int)mid_entry->command, + mid_entry->pid, + mid_entry->tsk, + mid_entry->mid); buf += length; } } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1b3082d..fe14097 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -313,12 +313,12 @@ struct mid_q_entry { __u16 mid; /* multiplex id */ __u16 pid; /* process id */ __u32 sequence_number; /* for CIFS signing */ - __u16 command; /* smb command code */ struct timeval when_sent; /* time when smb sent */ struct cifsSesInfo *ses; /* smb was sent to this server */ struct task_struct *tsk; /* task waiting for response */ struct smb_hdr *resp_buf; /* response buffer */ int midState; /* wish this were enum but can not pass to wait_event */ + __u8 command; /* smb command code */ }; struct oplock_q_entry { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1f22b85..383e55f 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -361,9 +361,13 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) mid_q_entry, qhead); - if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) { - cFYI(1, - (" Mid 0x%x matched - waking up ",mid_entry->mid)); + if ((mid_entry->mid == smb_buffer->Mid) + && (mid_entry->midState == + MID_REQUEST_SUBMITTED) + && (mid_entry->command == + smb_buffer->Command)) { + cFYI(1,("Found Mid 0x%x wake up" + ,mid_entry->mid)); task_to_wake = mid_entry->tsk; mid_entry->resp_buf = smb_buffer; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index a9e4f98..aab62ed 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -189,7 +189,6 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, struct msghdr smb_msg; number_of_pages += 1; /* account for SMB header */ struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); - if(i=0;i Date: Thu, 28 Apr 2005 22:41:07 -0700 Subject: [PATCH] cifs: CIFS ioctl needed by umount.cifs utility Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 3d5365b..461a706 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -190,6 +190,7 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) #ifdef CONFIG_CIFS_EXPERIMENTAL /* BB we could add a second check for a QFS Unix capability bit */ +/* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */ if (pTcon->ses->capabilities & CAP_UNIX) rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf); @@ -599,6 +600,9 @@ struct file_operations cifs_dir_ops = { #ifdef CONFIG_CIFS_EXPERIMENTAL .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ }; static void diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 5b35289..e3e9261 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1556,7 +1556,7 @@ typedef struct { #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ - +#define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ typedef struct { /* For undefined recommended transfer size return -1 in that field */ __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index a4f1c34a..711bb7a 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -29,6 +29,8 @@ #include "cifs_debug.h" #include "cifsfs.h" +#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2) + int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg) { @@ -36,8 +38,8 @@ int cifs_ioctl (struct inode * inode, struct file * filep, #ifdef CONFIG_CIFS_POSIX __u64 ExtAttrBits = 0; __u64 ExtAttrMask = 0; - __u64 caps; #endif /* CONFIG_CIFS_POSIX */ + __u64 caps; int xid; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *tcon; @@ -46,12 +48,11 @@ int cifs_ioctl (struct inode * inode, struct file * filep, xid = GetXid(); + cFYI(1,("ioctl file %p cmd %u arg %lu",filep,command,arg)); + cifs_sb = CIFS_SB(inode->i_sb); tcon = cifs_sb->tcon; - if (pSMBFile == NULL) - goto cifs_ioctl_out; -#ifdef CONFIG_CIFS_POSIX if(tcon) caps = le64_to_cpu(tcon->fsUnixInfo.Capability); else { @@ -59,10 +60,22 @@ int cifs_ioctl (struct inode * inode, struct file * filep, goto cifs_ioctl_out; } - cFYI(1,("ioctl file %p cmd %u arg %lu",filep,command,arg)); switch(command) { + case CIFS_IOC_CHECKUMOUNT: + cFYI(1,("User unmount attempted")); + /* BB FIXME - add missing code here FIXME */ + if(cifs_sb->mnt_uid == current->uid) + rc = 0; + else { + rc = -EACCES; + cFYI(1,("uids do not match")); + } + break; +#ifdef CONFIG_CIFS_POSIX case EXT2_IOC_GETFLAGS: if(CIFS_UNIX_EXTATTR_CAP & caps) { + if (pSMBFile == NULL) + goto cifs_ioctl_out; rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, &ExtAttrBits, &ExtAttrMask); if(rc == 0) @@ -78,17 +91,19 @@ int cifs_ioctl (struct inode * inode, struct file * filep, rc = -EFAULT; goto cifs_ioctl_out; } - /* rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, + if (pSMBFile == NULL) + goto cifs_ioctl_out; + /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid, extAttrBits, &ExtAttrMask);*/ } cFYI(1,("set flags not implemented yet")); break; +#endif /* CONFIG_CIFS_POSIX */ default: cFYI(1,("unsupported ioctl")); - return rc; + break; } -#endif /* CONFIG_CIFS_POSIX */ cifs_ioctl_out: FreeXid(xid); -- cgit v0.10.2 From c81156dd217818c143a09b6a744e797a04571e99 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:07 -0700 Subject: [PATCH] cifs: cleanup of ifdefs usage so it is more consistent And fix to not needlessly send new POSIX QFSInfo when server does not explicitly claim support for the new protocol extensions. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 461a706..6322aad 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -169,7 +169,8 @@ cifs_put_super(struct super_block *sb) static int cifs_statfs(struct super_block *sb, struct kstatfs *buf) { - int xid, rc = -EOPNOTSUPP; + int xid; + int rc = -EOPNOTSUPP; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; @@ -181,17 +182,18 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) buf->f_type = CIFS_MAGIC_NUMBER; /* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */ - buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would presumably - be length of total path, note that some servers may be - able to support more than this, but best to be safe - since Win2k and others can not handle very long filenames */ + buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would + presumably be total path, but note + that some servers (includinng Samba 3) + have a shorter maximum path */ buf->f_files = 0; /* undefined */ buf->f_ffree = 0; /* unlimited */ #ifdef CONFIG_CIFS_EXPERIMENTAL /* BB we could add a second check for a QFS Unix capability bit */ /* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */ - if (pTcon->ses->capabilities & CAP_UNIX) + if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS & + le64_to_cpu(pTcon->fsUnixInfo.Capability))) rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf); /* Only need to call the old QFSInfo if failed @@ -204,9 +206,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) int f_type; __fsid_t f_fsid; int f_namelen; */ - /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */ + /* BB get from info in tcon struct at mount time call to QFSAttrInfo */ FreeXid(xid); - return 0; /* always return success? what if volume is no longer available? */ + return 0; /* always return success? what if volume is no + longer available? */ } static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) @@ -600,9 +603,7 @@ struct file_operations cifs_dir_ops = { #ifdef CONFIG_CIFS_EXPERIMENTAL .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ -#ifdef CONFIG_CIFS_POSIX .ioctl = cifs_ioctl, -#endif /* CONFIG_CIFS_POSIX */ }; static void diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index fe14097..322a124 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -318,7 +318,9 @@ struct mid_q_entry { struct task_struct *tsk; /* task waiting for response */ struct smb_hdr *resp_buf; /* response buffer */ int midState; /* wish this were enum but can not pass to wait_event */ - __u8 command; /* smb command code */ + __u8 command; /* smb command code */ + unsigned multiPart:1; /* multiple responses to one SMB request */ + unsigned largeBuf:1; /* if valid response, is pointer to large buf */ }; struct oplock_q_entry { diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 711bb7a..b0ea668 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -35,35 +35,37 @@ int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg) { int rc = -ENOTTY; /* strange error - but the precedent */ + int xid; + struct cifs_sb_info *cifs_sb; #ifdef CONFIG_CIFS_POSIX __u64 ExtAttrBits = 0; __u64 ExtAttrMask = 0; -#endif /* CONFIG_CIFS_POSIX */ __u64 caps; - int xid; - struct cifs_sb_info *cifs_sb; struct cifsTconInfo *tcon; struct cifsFileInfo *pSMBFile = (struct cifsFileInfo *)filep->private_data; +#endif /* CONFIG_CIFS_POSIX */ xid = GetXid(); cFYI(1,("ioctl file %p cmd %u arg %lu",filep,command,arg)); cifs_sb = CIFS_SB(inode->i_sb); - tcon = cifs_sb->tcon; +#ifdef CONFIG_CIFS_POSIX + tcon = cifs_sb->tcon; if(tcon) caps = le64_to_cpu(tcon->fsUnixInfo.Capability); else { rc = -EIO; - goto cifs_ioctl_out; + FreeXid(xid); + return -EIO; } +#endif /* CONFIG_CIFS_POSIX */ switch(command) { case CIFS_IOC_CHECKUMOUNT: cFYI(1,("User unmount attempted")); - /* BB FIXME - add missing code here FIXME */ if(cifs_sb->mnt_uid == current->uid) rc = 0; else { @@ -75,7 +77,7 @@ int cifs_ioctl (struct inode * inode, struct file * filep, case EXT2_IOC_GETFLAGS: if(CIFS_UNIX_EXTATTR_CAP & caps) { if (pSMBFile == NULL) - goto cifs_ioctl_out; + break; rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, &ExtAttrBits, &ExtAttrMask); if(rc == 0) @@ -89,10 +91,10 @@ int cifs_ioctl (struct inode * inode, struct file * filep, if(CIFS_UNIX_EXTATTR_CAP & caps) { if(get_user(ExtAttrBits,(int __user *)arg)) { rc = -EFAULT; - goto cifs_ioctl_out; + break; } if (pSMBFile == NULL) - goto cifs_ioctl_out; + break; /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid, extAttrBits, &ExtAttrMask);*/ @@ -105,7 +107,6 @@ int cifs_ioctl (struct inode * inode, struct file * filep, break; } -cifs_ioctl_out: FreeXid(xid); return rc; } -- cgit v0.10.2 From b8643e1b5253a6a51da5574a55a2f9148e255cfd Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:07 -0700 Subject: [PATCH] cifs: Do not use large smb buffers in response path unless response is larger than 256 bytes. This cuts more than 1/3 of the large memory allocations that cifs does and should be a huge help to memory pressure under stress. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index efa0991..bff2ec6 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -1,7 +1,7 @@ /* * fs/cifs_debug.c * - * Copyright (C) International Business Machines Corp., 2000,2003 + * Copyright (C) International Business Machines Corp., 2000,2005 * * Modified by Steve French (sfrench@us.ibm.com) * @@ -92,8 +92,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, length = sprintf(buf, "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", - i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), - ses->serverOS, ses->serverNOS, ses->capabilities,ses->status); + i, ses->serverName, ses->serverDomain, + atomic_read(&ses->inUse), + ses->serverOS, ses->serverNOS, + ses->capabilities,ses->status); buf += length; if(ses->server) { buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", @@ -207,7 +209,8 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, buf += item_length; item_length = sprintf(buf,"SMB Request/Response Buffer: %d Pool size: %d\n", - bufAllocCount.counter,cifs_min_rcv + tcpSesAllocCount.counter); + bufAllocCount.counter, + cifs_min_rcv + tcpSesAllocCount.counter); length += item_length; buf += item_length; item_length = diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 383e55f..390f22f 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1,7 +1,7 @@ /* * fs/cifs/connect.c * - * Copyright (C) International Business Machines Corp., 2002,2004 + * Copyright (C) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include "cifspdu.h" @@ -198,6 +199,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) int length; unsigned int pdu_length, total_read; struct smb_hdr *smb_buffer = NULL; + struct smb_hdr *bigbuf = NULL; + struct smb_hdr *smallbuf = NULL; struct msghdr smb_msg; struct kvec iov; struct socket *csocket = server->ssocket; @@ -206,6 +209,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) struct task_struct *task_to_wake = NULL; struct mid_q_entry *mid_entry; char *temp; + int isLargeBuf = FALSE; daemonize("cifsd"); allow_signal(SIGKILL); @@ -223,17 +227,33 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } while (server->tcpStatus != CifsExiting) { - if (smb_buffer == NULL) - smb_buffer = cifs_buf_get(); - else - memset(smb_buffer, 0, sizeof (struct smb_hdr)); - - if (smb_buffer == NULL) { - cERROR(1,("Can not get memory for SMB response")); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ * 3); /* give system time to free memory */ - continue; + if (bigbuf == NULL) { + bigbuf = cifs_buf_get(); + if(bigbuf == NULL) { + cERROR(1,("No memory for large SMB response")); + msleep(3000); + /* retry will check if exiting */ + continue; + } + } else if(isLargeBuf) { + /* we are reusing a dirtry large buf, clear its start */ + memset(bigbuf, 0, sizeof (struct smb_hdr)); } + + if (smallbuf == NULL) { + smallbuf = cifs_small_buf_get(); + if(smallbuf == NULL) { + cERROR(1,("No memory for SMB response")); + msleep(1000); + /* retry will check if exiting */ + continue; + } + /* beginning of smb buffer is cleared in our buf_get */ + } else /* if existing small buf clear beginning */ + memset(smallbuf, 0, sizeof (struct smb_hdr)); + + isLargeBuf = FALSE; + smb_buffer = smallbuf; iov.iov_base = smb_buffer; iov.iov_len = 4; smb_msg.msg_control = NULL; @@ -251,8 +271,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) csocket = server->ssocket; continue; } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); /* minimum sleep to prevent looping + msleep(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ continue; @@ -295,8 +314,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } else { /* give server a second to clean up before reconnect attempt */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + msleep(1000); /* always try 445 first on reconnect since we get NACK on some if we ever connected to port 139 (the NACK is @@ -325,6 +343,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) wake_up(&server->response_q); continue; } else { /* length ok */ + if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { + isLargeBuf = TRUE; + memcpy(bigbuf, smallbuf, 4); + smb_buffer = bigbuf; + } length = 0; iov.iov_base = 4 + (char *)smb_buffer; iov.iov_len = pdu_length; @@ -377,6 +400,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } spin_unlock(&GlobalMid_Lock); if (task_to_wake) { + if(isLargeBuf) + bigbuf = NULL; + else + smallbuf = NULL; smb_buffer = NULL; /* will be freed by users thread after he is done */ wake_up_process(task_to_wake); } else if (is_valid_oplock_break(smb_buffer) == FALSE) { @@ -406,15 +433,17 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) and get out of SendReceive. */ wake_up_all(&server->request_q); /* give those requests time to exit */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/8); - + msleep(125); + if(server->ssocket) { sock_release(csocket); server->ssocket = NULL; } - if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ - cifs_buf_release(smb_buffer); + /* buffer usuallly freed in free_mid - need to free it here on exit */ + if (bigbuf != NULL) + cifs_buf_release(bigbuf); + if (smallbuf != NULL) + cifs_small_buf_release(smallbuf); read_lock(&GlobalSMBSeslock); if (list_empty(&server->pending_mid_q)) { @@ -444,17 +473,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } spin_unlock(&GlobalMid_Lock); read_unlock(&GlobalSMBSeslock); - set_current_state(TASK_INTERRUPTIBLE); /* 1/8th of sec is more than enough time for them to exit */ - schedule_timeout(HZ/8); + msleep(125); } if (list_empty(&server->pending_mid_q)) { /* mpx threads have not exited yet give them at least the smb send timeout time for long ops */ cFYI(1, ("Wait for exit from demultiplex thread")); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(46 * HZ); + msleep(46); /* if threads still have not exited they are probably never coming home not much else we can do but free the memory */ } @@ -469,9 +496,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) length + cifs_min_rcv, GFP_KERNEL); } - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); + + msleep(250); return 0; } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index aab62ed..f9e16b3 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -1,7 +1,7 @@ /* * fs/cifs/transport.c * - * Copyright (C) International Business Machines Corp., 2002,2004 + * Copyright (C) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -79,7 +79,10 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) list_del(&midEntry->qhead); atomic_dec(&midCount); spin_unlock(&GlobalMid_Lock); - cifs_buf_release(midEntry->resp_buf); + if(midEntry->largeBuf) + cifs_buf_release(midEntry->resp_buf); + else + cifs_small_buf_release(midEntry->resp_buf); mempool_free(midEntry, cifs_mid_poolp); } -- cgit v0.10.2 From 099a58f681ed951434574ec39bdfe87055bafe73 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:07 -0700 Subject: [PATCH] cifs: Missing initialization for largeBuf flag left out of previous changeset Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index de63a0e..be3a575 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -11,7 +11,11 @@ cifs_close. Add mount option for remapping reserved characters in filenames (also allow recognizing files with created by SFU which have any of these seven reserved characters, except backslash, to be recognized). Fix invalid transact2 message (we were sometimes trying to interpret -oplock breaks as SMB responses). +oplock breaks as SMB responses). Add ioctl for checking that the +current uid matches the uid of the mounter (needed by umount.cifs). +Reduce the number of large buffer allocations in cifs response processing +(significantly reduces memory pressure under heavy stress with multiple +processes accessing the same server at the same time). Version 1.31 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index 93900fc..48c37a6 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -75,7 +75,7 @@ Allowing User Mounts ==================== To permit users to mount and unmount over directories they own is possible with the cifs vfs. A way to enable such mounting is to mark the mount.cifs -utility as suid (e.g. "chmod +s /sbin/mount/cifs). To enable users to +utility as suid (e.g. "chmod +s /sbin/mount.cifs). To enable users to umount shares they mount requires 1) mount.cifs version 1.4 or later 2) an entry for the share in /etc/fstab indicating that a user may @@ -97,6 +97,23 @@ mount.cifs with the following flag: There is a corresponding manual page for cifs mounting in the Samba 3.0 and later source tree in docs/manpages/mount.cifs.8 +Allowing User Unmounts +====================== +To permit users to ummount directories that they have user mounted (see above), +the utility umount.cifs may be used. It may be invoked directly, or if +umount.cifs is placed in /sbin, umount -i can invoke the cifs umount helper +(at least for most versions of the umount utility) for umount of cifs +mounts. As with mount.cifs, to enable user unmounts umount.cifs must be marked +as suid (e.g. "chmod +s /sbin/umount.cifs"). For this utility to succeed +the target path must be a cifs mount, and the uid of the current user must +match the uid of the user who mounted the resource. + +Also note that the customary way of allowing user mounts and unmounts is +(instead of using mount.cifs and unmount.cifs as suid) to add a line +to the file /etc/fstab for each //server/share you wish to mount, but +this can become unwieldy when potential mount targets include many +or unpredictable UNC names. + Samba Considerations ==================== To get the maximum benefit from the CIFS VFS, we recommend using a server that diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 390f22f..c999583 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -396,6 +396,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) smb_buffer; mid_entry->midState = MID_RESPONSE_RECEIVED; + if(isLargeBuf) + mid_entry->largeBuf = 1; + else + mid_entry->largeBuf = 0; } } spin_unlock(&GlobalMid_Lock); -- cgit v0.10.2 From 433dc24f24b409fb130f638aa85470a0eb666206 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:08 -0700 Subject: [PATCH] cifs: remove cifs_kcalloc and check for NULL return on kcalloc in session initialization Suggested by: Adrian Bunk and Dave Miller Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index bff2ec6..4061e43 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -89,14 +89,21 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, list_for_each(tmp, &GlobalSMBSessionList) { i++; ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - length = - sprintf(buf, - "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", + if((ses->serverDomain == NULL) || (ses->serverOS == NULL) || + (ses->serverNOS == NULL)) { + buf += sprintf("\nentry for %s not fully displayed\n\t", + ses->serverName); + + } else { + length = + sprintf(buf, + "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), ses->serverOS, ses->serverNOS, ses->capabilities,ses->status); - buf += length; + buf += length; + } if(ses->server) { buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", ses->server->tcpStatus, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c999583..8a8aa78 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -505,16 +505,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) return 0; } -static void * -cifs_kcalloc(size_t size, unsigned int __nocast type) -{ - void *addr; - addr = kmalloc(size, type); - if (addr) - memset(addr, 0, size); - return addr; -} - static int cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) { @@ -632,7 +622,11 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) /* go from value to value + temp_len condensing double commas to singles. Note that this ends up allocating a few bytes too many, which is ok */ - vol->password = cifs_kcalloc(temp_len, GFP_KERNEL); + vol->password = kcalloc(1, temp_len, GFP_KERNEL); + if(vol->password == NULL) { + printk("CIFS: no memory for pass\n"); + return 1; + } for(i=0,j=0;ipassword[j] = value[i]; if(value[i] == separator[0] && value[i+1] == separator[0]) { @@ -642,7 +636,11 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) } vol->password[j] = 0; } else { - vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL); + vol->password = kcalloc(1, temp_len + 1, GFP_KERNEL); + if(vol->password == NULL) { + printk("CIFS: no memory for pass\n"); + return 1; + } strcpy(vol->password, value); } } else if (strnicmp(data, "ip", 2) == 0) { @@ -1104,7 +1102,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, sessinit is sent but no second negprot */ struct rfc1002_session_packet * ses_init_buf; struct smb_hdr * smb_buf; - ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); + ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL); if(ses_init_buf) { ses_init_buf->trailer.session_req.called_len = 32; rfc1002mangle(ses_init_buf->trailer.session_req.called_name, @@ -1751,7 +1749,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ - ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL); + if(ses->serverOS == NULL) + goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverOS, (wchar_t *)bcc_ptr, len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1761,7 +1761,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (remaining_words > 0) { len = UniStrnlen((wchar_t *)bcc_ptr, remaining_words-1); - ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL); + ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL); + if(ses->serverNOS == NULL) + goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverNOS, (wchar_t *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1774,10 +1776,12 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, } remaining_words -= len + 1; if (remaining_words > 0) { - len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); + len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = - cifs_kcalloc(2*(len+1),GFP_KERNEL); + kcalloc(1, 2*(len+1),GFP_KERNEL); + if(ses->serverDomain == NULL) + goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverDomain, (wchar_t *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1785,21 +1789,25 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ses->serverDomain[1+(2*len)] = 0; } /* else no more room so create dummy domain string */ else - ses->serverDomain = - cifs_kcalloc(2, - GFP_KERNEL); + ses->serverDomain = + kcalloc(1, 2, GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ + /* if these kcallocs fail not much we + can do, but better to not fail the + sesssetup itself */ ses->serverDomain = - cifs_kcalloc(2, GFP_KERNEL); + kcalloc(1, 2, GFP_KERNEL); ses->serverNOS = - cifs_kcalloc(2, GFP_KERNEL); + kcalloc(1, 2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); + ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL); + if(ses->serverOS == NULL) + goto sesssetup_nomem; strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; @@ -1807,14 +1815,18 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); + ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL); + if(ses->serverNOS == NULL) + goto sesssetup_nomem; strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL); + ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL); + if(ses->serverDomain == NULL) + goto sesssetup_nomem; strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -1834,7 +1846,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, smb_buffer_response->WordCount)); rc = -EIO; } - +sesssetup_nomem: /* do not return an error on nomem for the info strings, + since that could make reconnection harder, and + reconnection might be needed to free memory */ if (smb_buffer) cifs_buf_release(smb_buffer); @@ -2011,7 +2025,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -2025,7 +2039,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, remaining_words - 1); ses->serverNOS = - cifs_kcalloc(2 * (len + 1), + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverNOS, (wchar_t *)bcc_ptr, @@ -2038,7 +2052,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ - ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL); + ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, (wchar_t *)bcc_ptr, len, @@ -2049,10 +2063,10 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, } /* else no more room so create dummy domain string */ else ses->serverDomain = - cifs_kcalloc(2,GFP_KERNEL); + kcalloc(1, 2,GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ - ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); - ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); + ses->serverDomain = kcalloc(1, 2, GFP_KERNEL); + ses->serverNOS = kcalloc(1, 2, GFP_KERNEL); } } else { /* ASCII */ @@ -2060,7 +2074,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL); + ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); bcc_ptr += len; @@ -2068,14 +2082,14 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); + ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL); + ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -2325,7 +2339,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -2340,7 +2354,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, remaining_words - 1); ses->serverNOS = - cifs_kcalloc(2 * (len + 1), + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, @@ -2357,7 +2371,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = - cifs_kcalloc(2 * + kcalloc(1, 2 * (len + 1), GFP_KERNEL); @@ -2383,13 +2397,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, } /* else no more room so create dummy domain string */ else ses->serverDomain = - cifs_kcalloc(2, + kcalloc(1, 2, GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ ses->serverDomain = - cifs_kcalloc(2, GFP_KERNEL); + kcalloc(1, 2, GFP_KERNEL); ses->serverNOS = - cifs_kcalloc(2, GFP_KERNEL); + kcalloc(1, 2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); @@ -2397,7 +2411,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { ses->serverOS = - cifs_kcalloc(len + 1, + kcalloc(1, len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); @@ -2408,7 +2422,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, len = strnlen(bcc_ptr, 1024); ses->serverNOS = - cifs_kcalloc(len + 1, + kcalloc(1, len + 1, GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; @@ -2417,7 +2431,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, len = strnlen(bcc_ptr, 1024); ses->serverDomain = - cifs_kcalloc(len + 1, + kcalloc(1, len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; @@ -2719,7 +2733,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -2734,7 +2748,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, remaining_words - 1); ses->serverNOS = - cifs_kcalloc(2 * (len + 1), + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, @@ -2750,7 +2764,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string not always null terminated (e.g. for Windows XP & 2000) */ ses->serverDomain = - cifs_kcalloc(2 * + kcalloc(1, 2 * (len + 1), GFP_KERNEL); @@ -2775,17 +2789,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, = 0; } /* else no more room so create dummy domain string */ else - ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL); + ses->serverDomain = kcalloc(1, 2,GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ - ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); - ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); + ses->serverDomain = kcalloc(1, 2, GFP_KERNEL); + ses->serverNOS = kcalloc(1, 2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); + ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; @@ -2793,14 +2807,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL); + ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL); + ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -2912,7 +2926,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, if(tcon->nativeFileSystem) kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = - cifs_kcalloc(length + 2, GFP_KERNEL); + kcalloc(1, length + 2, GFP_KERNEL); cifs_strfromUCS_le(tcon->nativeFileSystem, (wchar_t *) bcc_ptr, length, nls_codepage); @@ -2930,7 +2944,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, if(tcon->nativeFileSystem) kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = - cifs_kcalloc(length + 1, GFP_KERNEL); + kcalloc(1, length + 1, GFP_KERNEL); strncpy(tcon->nativeFileSystem, bcc_ptr, length); } -- cgit v0.10.2 From 966ca9234754ece58870075972ef103e354de075 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:08 -0700 Subject: [PATCH] cifs: Fix caching problem pointed out by Dave Stahl and Vince Negri in which cifs can update the last modify time on a server modified file without invalidating the local cached data due to an intervening readdir. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS index acce36e..72fdc10 100644 --- a/fs/cifs/AUTHORS +++ b/fs/cifs/AUTHORS @@ -4,13 +4,16 @@ Steve French (sfrench@samba.org) The author wishes to express his appreciation and thanks to: Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS -improvements. Thanks to IBM for allowing me the time and test resources to pursue -this project. Jim McDonough from IBM (and the Samba Team) for his help. -The IBM Linux JFS team for explaining many esoteric Linux filesystem features. +improvements. Thanks to IBM for allowing me time and test resources to pursue +this project, to Jim McDonough from IBM (and the Samba Team) for his help, to +the IBM Linux JFS team for explaining many esoteric Linux filesystem features. +Jeremy Allison of the Samba team has done invaluable work in adding the server +side of the original CIFS Unix extensions and reviewing and implementing +portions of the newer CIFS POSIX extensions into the Samba 3 file server. Thank Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client) -for proving years ago that a very good smb/cifs client could be done on a Unix like -operating system. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin -and others for their work on the Linux smbfs module over the years. Thanks to +for proving years ago that very good smb/cifs clients could be done on Unix-like +operating systems. Volker Lendecke, Andrew Tridgell, Urban Widmark, John +Newbigin and others for their work on the Linux smbfs module. Thanks to the other members of the Storage Network Industry Association CIFS Technical Workgroup for their work specifying this highly complex protocol and finally thanks to the Samba team for their technical advice and encouragement. @@ -24,9 +27,11 @@ Shobhit Dayal Sergey Vlasov Richard Hughes Yury Umanets -Mark Hamzy +Mark Hamzy (for some of the early cifs IPv6 work) Domen Puncer -Jesper Juhl +Jesper Juhl (in particular for lots of whitespace/formatting cleanup) +Vince Negri and Dave Stahl (for finding an important caching bug) +Adrian Bunk (kcalloc cleanups) Test case and Bug Report contributors ------------------------------------- @@ -36,7 +41,8 @@ Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special mention to the Stanford Checker (SWAT) which pointed out many minor -bugs in error paths. +bugs in error paths. Valuable suggestions also have come from Al Viro +and Dave Miller. And thanks to the IBM LTC and Power test teams and SuSE testers for finding multiple bugs during excellent stress test runs. diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index be3a575..0414eb3 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,11 @@ +Version 1.33 +------------ +Fix caching problem, in which readdir of directory containing a file +which was cached could cause the file's time stamp to be updated +without invalidating the readahead data (so we could get stale +file data on the client for that file even as the server copy changed). + + Version 1.32 ------------ Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index e0e46f4..8f74279 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifsfs.h * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) International Business Machines Corp., 2002, 2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -96,5 +96,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg); -#define CIFS_VERSION "1.32" +#define CIFS_VERSION "1.33" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f7c4914..b102ddb 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -464,7 +464,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, &length, 0); if (rc) - cFYI(1, (" Tree disconnect failed %d", rc)); + cFYI(1, ("Tree disconnect failed %d", rc)); if (smb_buffer) cifs_small_buf_release(smb_buffer); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 7ca876b..39170cf 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -3,7 +3,7 @@ * * Directory search handling * - * Copyright (C) International Business Machines Corp., 2004 + * Copyright (C) International Business Machines Corp., 2004, 2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -65,14 +65,14 @@ static int construct_dentry(struct qstr *qstring, struct file *file, struct cifsTconInfo *pTcon; int rc = 0; - cFYI(1, ("For %s ", qstring->name)); + cFYI(1, ("For %s", qstring->name)); cifs_sb = CIFS_SB(file->f_dentry->d_sb); pTcon = cifs_sb->tcon; qstring->hash = full_name_hash(qstring->name, qstring->len); tmp_dentry = d_lookup(file->f_dentry, qstring); if (tmp_dentry) { - cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode)); + cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode)); *ptmp_inode = tmp_dentry->d_inode; /* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ if(*ptmp_inode == NULL) { @@ -105,8 +105,11 @@ static int construct_dentry(struct qstr *qstring, struct file *file, } static void fill_in_inode(struct inode *tmp_inode, - FILE_DIRECTORY_INFO *pfindData, int *pobject_type) + FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode) { + loff_t local_size; + struct timespec local_mtime; + struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); @@ -116,6 +119,10 @@ static void fill_in_inode(struct inode *tmp_inode, cifsInfo->cifsAttrs = attr; cifsInfo->time = jiffies; + /* save mtime and size */ + local_mtime = tmp_inode->i_mtime; + local_size = tmp_inode->i_size; + /* Linux can not store file creation time unfortunately so ignore it */ tmp_inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); @@ -134,7 +141,6 @@ static void fill_in_inode(struct inode *tmp_inode, tmp_inode->i_mode = cifs_sb->mnt_file_mode; } - cFYI(0,("CIFS FFIRST: Attributes came in as 0x%x",attr)); if (attr & ATTR_DIRECTORY) { *pobject_type = DT_DIR; /* override default perms since we do not lock dirs */ @@ -175,30 +181,46 @@ static void fill_in_inode(struct inode *tmp_inode, (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks, tmp_inode->i_blksize)); if (S_ISREG(tmp_inode->i_mode)) { - cFYI(1, (" File inode ")); + cFYI(1, ("File inode")); tmp_inode->i_op = &cifs_file_inode_ops; if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) tmp_inode->i_fop = &cifs_file_direct_ops; else tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops; + + if(isNewInode) + return; /* No sense invalidating pages for new inode since we + have not started caching readahead file data yet */ + + if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && + (local_size == tmp_inode->i_size)) { + cFYI(1, ("inode exists but unchanged")); + } else { + /* file may have changed on server */ + cFYI(1, ("invalidate inode, readdir detected change")); + invalidate_remote_inode(tmp_inode); + } } else if (S_ISDIR(tmp_inode->i_mode)) { - cFYI(1, (" Directory inode")); + cFYI(1, ("Directory inode")); tmp_inode->i_op = &cifs_dir_inode_ops; tmp_inode->i_fop = &cifs_dir_ops; } else if (S_ISLNK(tmp_inode->i_mode)) { - cFYI(1, (" Symbolic Link inode ")); + cFYI(1, ("Symbolic Link inode")); tmp_inode->i_op = &cifs_symlink_inode_ops; } else { - cFYI(1, (" Init special inode ")); + cFYI(1, ("Init special inode")); init_special_inode(tmp_inode, tmp_inode->i_mode, tmp_inode->i_rdev); } } static void unix_fill_in_inode(struct inode *tmp_inode, - FILE_UNIX_INFO *pfindData, int *pobject_type) + FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode) { + loff_t local_size; + struct timespec local_mtime; + struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); @@ -208,6 +230,10 @@ static void unix_fill_in_inode(struct inode *tmp_inode, cifsInfo->time = jiffies; atomic_inc(&cifsInfo->inUse); + /* save mtime and size */ + local_mtime = tmp_inode->i_mtime; + local_size = tmp_inode->i_size; + tmp_inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); tmp_inode->i_mtime = @@ -265,6 +291,19 @@ static void unix_fill_in_inode(struct inode *tmp_inode, else tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops; + + if(isNewInode) + return; /* No sense invalidating pages for new inode since we + have not started caching readahead file data yet */ + + if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && + (local_size == tmp_inode->i_size)) { + cFYI(1, ("inode exists but unchanged")); + } else { + /* file may have changed on server */ + cFYI(1, ("invalidate inode, readdir detected change")); + invalidate_remote_inode(tmp_inode); + } } else if (S_ISDIR(tmp_inode->i_mode)) { cFYI(1, ("Directory inode")); tmp_inode->i_op = &cifs_dir_inode_ops; @@ -321,7 +360,7 @@ static int initiate_cifs_search(const int xid, struct file *file) return -ENOMEM; } - cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); + cFYI(1, ("Full path: %s start at: %lld", full_path, file->f_pos)); ffirst_retry: /* test for Unix extensions */ @@ -666,10 +705,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file, insert_inode_hash(tmp_inode); } + /* we pass in rc below, indicating whether it is a new inode, + so we can figure out whether to invalidate the inode cached + data if the file has changed */ if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { - unix_fill_in_inode(tmp_inode,(FILE_UNIX_INFO *)pfindEntry,&obj_type); + unix_fill_in_inode(tmp_inode, + (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc); } else { - fill_in_inode(tmp_inode,(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type); + fill_in_inode(tmp_inode, + (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); } rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); -- cgit v0.10.2 From 09d1db5c6131232f764046160c29118cd4e5e646 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:08 -0700 Subject: [PATCH] cifs: improve check for search entry going beyond end of SMB transact Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/README b/fs/cifs/README index 48c37a6..bec7b3f 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -420,7 +420,7 @@ Misc /proc/fs/cifs Flags and Debug Info ======================================= Informational pseudo-files: DebugData Displays information about active CIFS sessions - and shares. + and shares, as well as the cifs.ko version. Stats Lists summary resource usage information as well as per share statistics, if CONFIG_CIFS_STATS in enabled in the kernel configuration. @@ -477,7 +477,7 @@ and for more extensive tracing including the start of smb requests and responses Two other experimental features are under development and to test require enabling CONFIG_CIFS_EXPERIMENTAL - More efficient write operations and SMB buffer handling + More efficient write operations DNOTIFY fcntl: needed for support of directory change notification and perhaps later for file leases) @@ -495,8 +495,8 @@ returned success. Also note that "cat /proc/fs/cifs/DebugData" will display information about the active sessions and the shares that are mounted. Note: NTLMv2 enablement -will not work since they its implementation is not quite complete yet. -Do not alter these configuration values unless you are doing specific testing. +will not work since its implementation is not quite complete yet. Do not alter +the ExtendedSecurity configuration value unless you are doing specific testing. Enabling extended security works to Windows 2000 Workstations and XP but not to Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" (instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b102ddb..834297f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -75,7 +75,8 @@ static void mark_open_files_invalid(struct cifsTconInfo * pTcon) } } write_unlock(&GlobalSMBSeslock); - /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */ + /* BB Add call to invalidate_inodes(sb) for all superblocks mounted + to this tcon */ } /* If the return code is zero, this function must fill in request_buf pointer */ @@ -92,8 +93,8 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, if((tcon->ses) && (tcon->ses->server)){ struct nls_table *nls_codepage; /* Give Demultiplex thread up to 10 seconds to - reconnect, should be greater than cifs socket - timeout which is 7 seconds */ + reconnect, should be greater than cifs socket + timeout which is 7 seconds */ while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { wait_event_interruptible_timeout(tcon->ses->server->response_q, (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); @@ -103,8 +104,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, (tcon->ses->status == CifsExiting)) { cFYI(1,("gave up waiting on reconnect in smb_init")); return -EHOSTDOWN; - } /* else "hard" mount - keep retrying until - process is killed or server comes back up */ + } /* else "hard" mount - keep retrying + until process is killed or server + comes back on-line */ } else /* TCP session is reestablished now */ break; @@ -115,23 +117,24 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, simultaneously reconnect the same SMB session */ down(&tcon->ses->sesSem); if(tcon->ses->status == CifsNeedReconnect) - rc = cifs_setup_session(0, tcon->ses, nls_codepage); + rc = cifs_setup_session(0, tcon->ses, + nls_codepage); if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { mark_open_files_invalid(tcon); - rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, - nls_codepage); + rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon + , nls_codepage); up(&tcon->ses->sesSem); if(rc == 0) atomic_inc(&tconInfoReconnectCount); cFYI(1, ("reconnect tcon rc = %d", rc)); /* Removed call to reopen open files here - - it is safer (and faster) to reopen files - one at a time as needed in read and write */ + it is safer (and faster) to reopen files + one at a time as needed in read and write */ /* Check if handle based operation so we - know whether we can continue or not without - returning to caller to reset file handle */ + know whether we can continue or not without + returning to caller to reset file handle */ switch(smb_command) { case SMB_COM_READ_ANDX: case SMB_COM_WRITE_ANDX: @@ -184,20 +187,22 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, if(tcon) { if((tcon->ses) && (tcon->ses->server)){ struct nls_table *nls_codepage; - /* Give Demultiplex thread up to 10 seconds to - reconnect, should be greater than cifs socket - timeout which is 7 seconds */ + /* Give Demultiplex thread up to 10 seconds to + reconnect, should be greater than cifs socket + timeout which is 7 seconds */ while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { wait_event_interruptible_timeout(tcon->ses->server->response_q, (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); - if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + if(tcon->ses->server->tcpStatus == + CifsNeedReconnect) { /* on "soft" mounts we wait once */ if((tcon->retry == FALSE) || (tcon->ses->status == CifsExiting)) { cFYI(1,("gave up waiting on reconnect in smb_init")); return -EHOSTDOWN; - } /* else "hard" mount - keep retrying until - process is killed or server comes back up */ + } /* else "hard" mount - keep retrying + until process is killed or server + comes on-line */ } else /* TCP session is reestablished now */ break; @@ -208,23 +213,24 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, simultaneously reconnect the same SMB session */ down(&tcon->ses->sesSem); if(tcon->ses->status == CifsNeedReconnect) - rc = cifs_setup_session(0, tcon->ses, nls_codepage); + rc = cifs_setup_session(0, tcon->ses, + nls_codepage); if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { mark_open_files_invalid(tcon); - rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, - nls_codepage); + rc = CIFSTCon(0, tcon->ses, tcon->treeName, + tcon, nls_codepage); up(&tcon->ses->sesSem); if(rc == 0) atomic_inc(&tconInfoReconnectCount); cFYI(1, ("reconnect tcon rc = %d", rc)); /* Removed call to reopen open files here - - it is safer (and faster) to reopen files - one at a time as needed in read and write */ + it is safer (and faster) to reopen files + one at a time as needed in read and write */ /* Check if handle based operation so we - know whether we can continue or not without - returning to caller to reset file handle */ + know whether we can continue or not without + returning to caller to reset file handle */ switch(smb_command) { case SMB_COM_READ_ANDX: case SMB_COM_WRITE_ANDX: @@ -286,7 +292,8 @@ static int validate_t2(struct smb_t2_rsp * pSMB) if(total_size < 512) { total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount); /* BCC le converted in SendReceive */ - pBCC = (pSMB->hdr.WordCount * 2) + sizeof(struct smb_hdr) + + pBCC = (pSMB->hdr.WordCount * 2) + + sizeof(struct smb_hdr) + (char *)pSMB; if((total_size <= (*(u16 *)pBCC)) && (total_size < @@ -337,8 +344,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc == 0) { server->secMode = pSMBr->SecurityMode; - server->secType = NTLM; /* BB override default for NTLMv2 or krb*/ - /* one byte - no need to convert this or EncryptionKeyLen from le,*/ + server->secType = NTLM; /* BB override default for + NTLMv2 or kerberos v5 */ + /* one byte - no need to convert this or EncryptionKeyLen + from little endian */ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); /* probably no need to store and check maxvcs */ server->maxBuf = @@ -374,7 +383,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) pSMBr->u.extended_response. GUID, 16) != 0) { cFYI(1, - ("UID of server does not match previous connection to same ip address")); + ("UID of server does not match previous connection to same ip address")); memcpy(server-> server_GUID, pSMBr->u. @@ -454,7 +463,8 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) up(&tcon->tconSem); return -EIO; } - rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer); + rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, + (void **)&smb_buffer); if (rc) { up(&tcon->tconSem); return rc; @@ -559,7 +569,7 @@ DelFileRetry: PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; - } else { /* BB improve the check for buffer overruns BB */ + } else { /* BB improve check for buffer overruns BB */ name_len = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->fileName, fileName, name_len); @@ -609,7 +619,7 @@ RmDirRetry: PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; - } else { /* BB improve the check for buffer overruns BB */ + } else { /* BB improve check for buffer overruns BB */ name_len = strnlen(dirName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->DirName, dirName, name_len); @@ -657,7 +667,7 @@ MkDirRetry: PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; - } else { /* BB improve the check for buffer overruns BB */ + } else { /* BB improve check for buffer overruns BB */ name_len = strnlen(name, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->DirName, name, name_len); @@ -712,7 +722,7 @@ openRetry: name_len++; /* trailing null */ name_len *= 2; pSMB->NameLength = cpu_to_le16(name_len); - } else { /* BB improve the check for buffer overruns BB */ + } else { /* BB improve check for buffer overruns BB */ count = 0; /* no pad */ name_len = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ @@ -741,7 +751,8 @@ openRetry: pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); pSMB->CreateDisposition = cpu_to_le32(openDisposition); pSMB->CreateOptions = cpu_to_le32(create_options); - pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/ + /* BB Expirement with various impersonation levels and verify */ + pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); pSMB->SecurityFlags = SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY; @@ -755,7 +766,7 @@ openRetry: if (rc) { cFYI(1, ("Error in Open = %d", rc)); } else { - *pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */ + *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */ *netfid = pSMBr->Fid; /* cifs fid stays in le */ /* Let caller know file was created so we can set the mode. */ /* Do we care about the CreateAction in any other cases? */ @@ -2504,7 +2515,9 @@ findFirstRetry: psrch_inf->srch_entries_start = (char *) &pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->t2.DataOffset); - +/* if(le16_to_cpu(pSMBr->t2.DataCount) != le16_to_cpu(pSMBr->t2.TotalDataCount)) { + cERROR(1,("DC: %d TDC: %d",pSMBr->t2.DataCount,pSMBr->t2.TotalDataCount)); +} */ /* BB removeme BB */ parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->t2.ParameterOffset)); @@ -2516,7 +2529,7 @@ findFirstRetry: psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); psrch_inf->index_of_last_entry = psrch_inf->entries_in_buffer; -/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ +/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ /* BB removeme BB */ *pnetfid = parms->SearchHandle; } else { cifs_buf_release(pSMB); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8a8aa78..d5d49b5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -157,9 +157,10 @@ cifs_reconnect(struct TCP_Server_Info *server) qhead); if(mid_entry) { if(mid_entry->midState == MID_REQUEST_SUBMITTED) { - /* Mark other intransit requests as needing retry so - we do not immediately mark the session bad again - (ie after we reconnect below) as they timeout too */ + /* Mark other intransit requests as needing + retry so we do not immediately mark the + session bad again (ie after we reconnect + below) as they timeout too */ mid_entry->midState = MID_RETRY_NEEDED; } } @@ -278,9 +279,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } else if (length <= 0) { if(server->tcpStatus == CifsNew) { cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); - /* some servers kill tcp session rather than returning - smb negprot error in which case reconnecting here is - not going to help - return error to mount */ + /* some servers kill the TCP session rather than + returning an SMB negprot error, in which + case reconnecting here is not going to help, + and so simply return error to mount */ break; } if(length == -EINTR) { @@ -296,15 +298,19 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) pdu_length = ntohl(smb_buffer->smb_buf_length); /* Only read pdu_length after below checks for too short (due to e.g. int overflow) and too long ie beyond end of buf */ - cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); + cFYI(1,("rfc1002 length(big endian)0x%x)", + pdu_length+4)); temp = (char *) smb_buffer; if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { cFYI(0,("Received 4 byte keep alive packet")); - } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { + } else if (temp[0] == + (char) RFC1002_POSITIVE_SESSION_RESPONSE) { cFYI(1,("Good RFC 1002 session rsp")); - } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { - /* we get this from Windows 98 instead of error on SMB negprot response */ + } else if (temp[0] == + (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { + /* we get this from Windows 98 instead of + an error on SMB negprot response */ cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); if(server->tcpStatus == CifsNew) { /* if nack on negprot (rather than @@ -320,7 +326,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) connected to port 139 (the NACK is since we do not begin with RFC1001 session initialize frame) */ - server->addr.sockAddr.sin_port = htons(CIFS_PORT); + server->addr.sockAddr.sin_port = + htons(CIFS_PORT); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); @@ -333,8 +340,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) csocket = server->ssocket; continue; } else { - if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) - || (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { + if((pdu_length > CIFSMaxBufSize + + MAX_CIFS_HDR_SIZE - 4) || + (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { cERROR(1, ("Invalid size SMB length %d and pdu_length %d", length, pdu_length+4)); @@ -377,6 +385,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) continue; } + /* BB FIXME - add checkTrans2SMBSecondary() */ + task_to_wake = NULL; spin_lock(&GlobalMid_Lock); list_for_each(tmp, &server->pending_mid_q) { @@ -408,7 +418,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) bigbuf = NULL; else smallbuf = NULL; - smb_buffer = NULL; /* will be freed by users thread after he is done */ + smb_buffer = NULL; /* will be freed by users thread after he is done */ wake_up_process(task_to_wake); } else if (is_valid_oplock_break(smb_buffer) == FALSE) { cERROR(1, ("No task to wake, unknown frame rcvd!")); @@ -432,7 +442,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) spin_unlock(&GlobalMid_Lock); /* Although there should not be any requests blocked on this queue it can not hurt to be paranoid and try to wake up requests - that may haven been blocked when more than 50 at time were on the wire + that may haven been blocked when more than 50 at time were on the wire to the same server - they now will see the session is in exit state and get out of SendReceive. */ wake_up_all(&server->request_q); @@ -451,7 +461,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) read_lock(&GlobalSMBSeslock); if (list_empty(&server->pending_mid_q)) { - /* loop through server session structures attached to this and mark them dead */ + /* loop through server session structures attached to this and + mark them dead */ list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, @@ -468,7 +479,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) mid_entry = list_entry(tmp, struct mid_q_entry, qhead); if (mid_entry->midState == MID_REQUEST_SUBMITTED) { cFYI(1, - (" Clearing Mid 0x%x - waking up ",mid_entry->mid)); + ("Clearing Mid 0x%x - waking up ",mid_entry->mid)); task_to_wake = mid_entry->tsk; if(task_to_wake) { wake_up_process(task_to_wake); @@ -521,7 +532,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) /* does not have to be a perfect mapping since the field is informational, only used for servers that do not support port 445 and it can be overridden at mount time */ - vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]); + vol->source_rfc1001_name[i] = + toupper(system_utsname.nodename[i]); } vol->source_rfc1001_name[15] = 0; @@ -596,14 +608,17 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) /* NB: password legally can have multiple commas and the only illegal character in a password is null */ - if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) { + if ((value[temp_len] == 0) && + (value[temp_len+1] == separator[0])) { /* reinsert comma */ value[temp_len] = separator[0]; temp_len+=2; /* move after the second comma */ while(value[temp_len] != 0) { if (value[temp_len] == separator[0]) { - if (value[temp_len+1] == separator[0]) { - temp_len++; /* skip second comma */ + if (value[temp_len+1] == + separator[0]) { + /* skip second comma */ + temp_len++; } else { /* single comma indicating start of next parm */ @@ -629,14 +644,15 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) } for(i=0,j=0;ipassword[j] = value[i]; - if(value[i] == separator[0] && value[i+1] == separator[0]) { + if(value[i] == separator[0] + && value[i+1] == separator[0]) { /* skip second comma */ i++; } } vol->password[j] = 0; } else { - vol->password = kcalloc(1, temp_len + 1, GFP_KERNEL); + vol->password = kcalloc(1, temp_len+1, GFP_KERNEL); if(vol->password == NULL) { printk("CIFS: no memory for pass\n"); return 1; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 39170cf..2255771 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -409,10 +409,15 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb) cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); /* validate that new_entry is not past end of SMB */ if(new_entry >= end_of_smb) { - cFYI(1,("search entry %p began after end of SMB %p old entry %p", - new_entry,end_of_smb,old_entry)); + cERROR(1, + ("search entry %p began after end of SMB %p old entry %p", + new_entry, end_of_smb, old_entry)); return NULL; - } else + } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) { + cERROR(1,("search entry %p extends after end of SMB %p", + new_entry, end_of_smb)); + return NULL; + } else return new_entry; } -- cgit v0.10.2 From 67010fbc6ff889aaf86592bc148d705c5b9e1a27 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:09 -0700 Subject: [PATCH] cifs: Better handle errors on second socket recv message call Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 322a124..8fc0801 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifsglob.h * - * Copyright (C) International Business Machines Corp., 2002,2003 + * Copyright (C) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -321,6 +321,7 @@ struct mid_q_entry { __u8 command; /* smb command code */ unsigned multiPart:1; /* multiple responses to one SMB request */ unsigned largeBuf:1; /* if valid response, is pointer to large buf */ + unsigned multiResp:1 /* multiple trans2 responses for one request */ }; struct oplock_q_entry { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d5d49b5..8c5d310 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -359,20 +359,36 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) length = 0; iov.iov_base = 4 + (char *)smb_buffer; iov.iov_len = pdu_length; - for (total_read = 0; + for (total_read = 0; total_read < pdu_length; total_read += length) { - length = kernel_recvmsg(csocket, &smb_msg, + length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0); - if (length == 0) { + if((server->tcpStatus == CifsExiting) || + (length == -EINTR)) { + /* then will exit */ + goto dmx_loop_end; + } else if (server->tcpStatus == + CifsNeedReconnect) { + cifs_reconnect(server); + csocket = server->ssocket; + /* Reconnect wakes up rspns q */ + /* Now we will reread sock */ + goto dmx_loop_end; + } else if ((length == -ERESTARTSYS) || + (length == -EAGAIN)) { + msleep(1); /* minimum sleep to prevent looping + allowing socket to clear and app threads to set + tcpStatus CifsNeedReconnect if server hung */ + continue; + } else if (length <= 0) { cERROR(1, - ("Zero length receive when expecting %d ", + ("Received no data, expecting %d", pdu_length - total_read)); cifs_reconnect(server); csocket = server->ssocket; - wake_up(&server->response_q); - continue; + goto dmx_loop_end; } } length += 4; /* account for rfc1002 hdr */ @@ -434,6 +450,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) wake_up(&server->response_q); continue; } +dmx_loop_end: + cFYI(1,("Exiting cifsd loop")); + } spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; -- cgit v0.10.2 From 79944bf71352f33f984ac3973b159b5c2cee139d Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:09 -0700 Subject: [PATCH] cifs: missing semicolon from previous fix Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 8fc0801..81babab 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -321,7 +321,7 @@ struct mid_q_entry { __u8 command; /* smb command code */ unsigned multiPart:1; /* multiple responses to one SMB request */ unsigned largeBuf:1; /* if valid response, is pointer to large buf */ - unsigned multiResp:1 /* multiple trans2 responses for one request */ + unsigned multiResp:1; /* multiple trans2 responses for one request */ }; struct oplock_q_entry { -- cgit v0.10.2 From 46810cbf3d951c1ce8ce3311639996ad43ca4ed1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:09 -0700 Subject: [PATCH] cifs: Ease memory pressure, do not use large buffers in byte range lock requests. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 834297f..a6e6697 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1023,11 +1023,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, __u16 count; cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock)); - rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); + if (rc) return rc; + pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */ + if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) { timeout = -1; /* no response expected */ pSMB->Timeout = 0; @@ -1065,7 +1067,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, if (rc) { cFYI(1, ("Send error in Lock = %d", rc)); } - cifs_buf_release(pSMB); + cifs_small_buf_release(pSMB); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8c5d310..419f145 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -294,165 +294,168 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) csocket = server->ssocket; wake_up(&server->response_q); continue; - } else if (length > 3) { - pdu_length = ntohl(smb_buffer->smb_buf_length); - /* Only read pdu_length after below checks for too short (due - to e.g. int overflow) and too long ie beyond end of buf */ - cFYI(1,("rfc1002 length(big endian)0x%x)", - pdu_length+4)); - - temp = (char *) smb_buffer; - if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { - cFYI(0,("Received 4 byte keep alive packet")); - } else if (temp[0] == - (char) RFC1002_POSITIVE_SESSION_RESPONSE) { - cFYI(1,("Good RFC 1002 session rsp")); - } else if (temp[0] == - (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { - /* we get this from Windows 98 instead of - an error on SMB negprot response */ - cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); - if(server->tcpStatus == CifsNew) { - /* if nack on negprot (rather than - ret of smb negprot error) reconnecting - not going to help, ret error to mount */ - break; - } else { - /* give server a second to - clean up before reconnect attempt */ - msleep(1000); - /* always try 445 first on reconnect - since we get NACK on some if we ever - connected to port 139 (the NACK is - since we do not begin with RFC1001 - session initialize frame) */ - server->addr.sockAddr.sin_port = - htons(CIFS_PORT); - cifs_reconnect(server); - csocket = server->ssocket; - wake_up(&server->response_q); - continue; - } - } else if (temp[0] != (char) 0) { - cERROR(1,("Unknown RFC 1002 frame")); - cifs_dump_mem(" Received Data: ", temp, length); + } else if (length < 4) { + cFYI(1, + ("Frame less than four bytes received %d bytes long.", + length)); + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } + + /* the right amount was read from socket - 4 bytes */ + + pdu_length = ntohl(smb_buffer->smb_buf_length); + cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); + + temp = (char *) smb_buffer; + if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { + cFYI(0,("Received 4 byte keep alive packet")); + } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { + cFYI(1,("Good RFC 1002 session rsp")); + } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { + /* we get this from Windows 98 instead of + an error on SMB negprot response */ + cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); + if(server->tcpStatus == CifsNew) { + /* if nack on negprot (rather than + ret of smb negprot error) reconnecting + not going to help, ret error to mount */ + break; + } else { + /* give server a second to + clean up before reconnect attempt */ + msleep(1000); + /* always try 445 first on reconnect + since we get NACK on some if we ever + connected to port 139 (the NACK is + since we do not begin with RFC1001 + session initialize frame) */ + server->addr.sockAddr.sin_port = + htons(CIFS_PORT); cifs_reconnect(server); csocket = server->ssocket; + wake_up(&server->response_q); continue; - } else { - if((pdu_length > CIFSMaxBufSize + - MAX_CIFS_HDR_SIZE - 4) || - (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { - cERROR(1, - ("Invalid size SMB length %d and pdu_length %d", - length, pdu_length+4)); - cifs_reconnect(server); - csocket = server->ssocket; - wake_up(&server->response_q); - continue; - } else { /* length ok */ - if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { - isLargeBuf = TRUE; - memcpy(bigbuf, smallbuf, 4); - smb_buffer = bigbuf; - } - length = 0; - iov.iov_base = 4 + (char *)smb_buffer; - iov.iov_len = pdu_length; - for (total_read = 0; - total_read < pdu_length; - total_read += length) { - length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, - pdu_length - total_read, 0); - if((server->tcpStatus == CifsExiting) || - (length == -EINTR)) { - /* then will exit */ - goto dmx_loop_end; - } else if (server->tcpStatus == - CifsNeedReconnect) { - cifs_reconnect(server); - csocket = server->ssocket; - /* Reconnect wakes up rspns q */ + } + } else if (temp[0] != (char) 0) { + cERROR(1,("Unknown RFC 1002 frame")); + cifs_dump_mem(" Received Data: ", temp, length); + cifs_reconnect(server); + csocket = server->ssocket; + continue; + } else { /* we have an SMB response */ + if((pdu_length > CIFSMaxBufSize + + MAX_CIFS_HDR_SIZE - 4) || + (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { + cERROR(1, + ("Invalid size SMB length %d and pdu_length %d", + length, pdu_length+4)); + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } else { /* length ok */ + int reconnect = 0; + + if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { + isLargeBuf = TRUE; + memcpy(bigbuf, smallbuf, 4); + smb_buffer = bigbuf; + } + length = 0; + iov.iov_base = 4 + (char *)smb_buffer; + iov.iov_len = pdu_length; + for (total_read = 0; + total_read < pdu_length; + total_read += length) { + length = kernel_recvmsg(csocket, &smb_msg, + &iov, 1, + pdu_length - total_read, 0); + if((server->tcpStatus == CifsExiting) || + (length == -EINTR)) { + /* then will exit */ + reconnect = 2; + break; + } else if (server->tcpStatus == + CifsNeedReconnect) { + cifs_reconnect(server); + csocket = server->ssocket; + /* Reconnect wakes up rspns q */ /* Now we will reread sock */ - goto dmx_loop_end; - } else if ((length == -ERESTARTSYS) || - (length == -EAGAIN)) { - msleep(1); /* minimum sleep to prevent looping - allowing socket to clear and app threads to set - tcpStatus CifsNeedReconnect if server hung */ - continue; - } else if (length <= 0) { - cERROR(1, - ("Received no data, expecting %d", - pdu_length - total_read)); - cifs_reconnect(server); - csocket = server->ssocket; - goto dmx_loop_end; - } + reconnect = 1; + break; + } else if ((length == -ERESTARTSYS) || + (length == -EAGAIN)) { + msleep(1); /* minimum sleep to prevent looping + allowing socket to clear and app threads to set + tcpStatus CifsNeedReconnect if server hung */ + continue; + } else if (length <= 0) { + cERROR(1,("Received no data, expecting %d", + pdu_length - total_read)); + cifs_reconnect(server); + csocket = server->ssocket; + reconnect = 1; + break; } - length += 4; /* account for rfc1002 hdr */ } + if(reconnect == 2) + break; + else if(reconnect == 1) + continue; - dump_smb(smb_buffer, length); - if (checkSMB - (smb_buffer, smb_buffer->Mid, total_read+4)) { - cERROR(1, ("Bad SMB Received ")); - continue; - } + length += 4; /* account for rfc1002 hdr */ + } - /* BB FIXME - add checkTrans2SMBSecondary() */ - - task_to_wake = NULL; - spin_lock(&GlobalMid_Lock); - list_for_each(tmp, &server->pending_mid_q) { - mid_entry = list_entry(tmp, struct - mid_q_entry, - qhead); - - if ((mid_entry->mid == smb_buffer->Mid) - && (mid_entry->midState == - MID_REQUEST_SUBMITTED) - && (mid_entry->command == - smb_buffer->Command)) { - cFYI(1,("Found Mid 0x%x wake up" - ,mid_entry->mid)); - task_to_wake = mid_entry->tsk; - mid_entry->resp_buf = - smb_buffer; - mid_entry->midState = - MID_RESPONSE_RECEIVED; - if(isLargeBuf) - mid_entry->largeBuf = 1; - else - mid_entry->largeBuf = 0; - } - } - spin_unlock(&GlobalMid_Lock); - if (task_to_wake) { + dump_smb(smb_buffer, length); + if (checkSMB + (smb_buffer, smb_buffer->Mid, total_read+4)) { + cERROR(1, ("Bad SMB Received ")); + continue; + } + + + task_to_wake = NULL; + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct mid_q_entry, + qhead); + + if ((mid_entry->mid == smb_buffer->Mid) + && (mid_entry->midState == + MID_REQUEST_SUBMITTED) + && (mid_entry->command == + smb_buffer->Command)) { + cFYI(1,("Found Mid 0x%x wake up" + ,mid_entry->mid)); + /* BB FIXME - missing code here BB */ + /* check_2nd_t2(smb_buffer); */ + task_to_wake = mid_entry->tsk; + mid_entry->resp_buf = + smb_buffer; + mid_entry->midState = + MID_RESPONSE_RECEIVED; if(isLargeBuf) - bigbuf = NULL; + mid_entry->largeBuf = 1; else - smallbuf = NULL; - smb_buffer = NULL; /* will be freed by users thread after he is done */ - wake_up_process(task_to_wake); - } else if (is_valid_oplock_break(smb_buffer) == FALSE) { - cERROR(1, ("No task to wake, unknown frame rcvd!")); - cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + mid_entry->largeBuf = 0; } } - } else { - cFYI(1, - ("Frame less than four bytes received %d bytes long.", - length)); - cifs_reconnect(server); - csocket = server->ssocket; - wake_up(&server->response_q); - continue; + spin_unlock(&GlobalMid_Lock); + if (task_to_wake) { + if(isLargeBuf) + bigbuf = NULL; + else + smallbuf = NULL; + smb_buffer = NULL; /* will be freed by users thread after he is done */ + wake_up_process(task_to_wake); + } else if (is_valid_oplock_break(smb_buffer) == FALSE) { + cERROR(1, ("No task to wake, unknown frame rcvd!")); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + } } -dmx_loop_end: - cFYI(1,("Exiting cifsd loop")); - } spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; -- cgit v0.10.2 From e4eb295d38b57f4d4b956942a48887eb252d97c6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:09 -0700 Subject: [PATCH] cifs: Handle multiple response transact2 part 1 of 2 Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e3e9261..aede6a8 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -330,7 +330,7 @@ struct smb_hdr { }; /* given a pointer to an smb_hdr retrieve the value of byte count */ #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) - +#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 419f145..a8d592b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -116,7 +116,7 @@ cifs_reconnect(struct TCP_Server_Info *server) spin_unlock(&GlobalMid_Lock); server->maxBuf = 0; - cFYI(1, ("Reconnecting tcp session ")); + cFYI(1, ("Reconnecting tcp session")); /* before reconnecting the tcp session, mark the smb session (uid) and the tid bad so they are not used until reconnected */ @@ -194,6 +194,121 @@ cifs_reconnect(struct TCP_Server_Info *server) return rc; } +/* + return codes: + 0 not a transact2, or all data present + >0 transact2 with that much data missing + -EINVAL = invalid transact2 + + */ +static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize) +{ + struct smb_t2_rsp * pSMBt; + int total_data_size; + int data_in_this_rsp; + int remaining; + + if(pSMB->Command != SMB_COM_TRANSACTION2) + return 0; + + /* check for plausible wct, bcc and t2 data and parm sizes */ + /* check for parm and data offset going beyond end of smb */ + if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */ + cFYI(1,("invalid transact2 word count")); + return -EINVAL; + } + + pSMBt = (struct smb_t2_rsp *)pSMB; + + total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); + data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount); + + remaining = total_data_size - data_in_this_rsp; + + if(remaining == 0) + return 0; + else if(remaining < 0) { + cFYI(1,("total data %d smaller than data in frame %d", + total_data_size, data_in_this_rsp)); + return -EINVAL; + } else { + cFYI(1,("missing %d bytes from transact2, check next response", + remaining)); + if(total_data_size > maxBufSize) { + cERROR(1,("TotalDataSize %d is over maximum buffer %d", + total_data_size,maxBufSize)); + return -EINVAL; + } + return remaining; + } +} + +static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) +{ + struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; + struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; + int total_data_size; + int total_in_buf; + int remaining; + int total_in_buf2; + char * data_area_of_target; + char * data_area_of_buf2; + __u16 byte_count; + + total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); + + if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) { + cFYI(1,("total data sizes of primary and secondary t2 differ")); + } + + total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount); + + remaining = total_data_size - total_in_buf; + + if(remaining < 0) + return -EINVAL; + + if(remaining == 0) /* nothing to do, ignore */ + return 0; + + total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount); + if(remaining < total_in_buf2) { + cFYI(1,("transact2 2nd response contains too much data")); + } + + /* find end of first SMB data area */ + data_area_of_target = (char *)&pSMBt->hdr.Protocol + + le16_to_cpu(pSMBt->t2_rsp.DataOffset); + /* validate target area */ + + data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol + + le16_to_cpu(pSMB2->t2_rsp.DataOffset); + + data_area_of_target += total_in_buf; + + /* copy second buffer into end of first buffer */ + memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2); + total_in_buf += total_in_buf2; + pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf); + byte_count = le16_to_cpu(BCC_LE(pTargetSMB)); + byte_count += total_in_buf2; + BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); + + byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); + byte_count += total_in_buf2; + + /* BB also add check that we are not beyond maximum buffer size */ + + pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); + + if(remaining == total_in_buf2) { + cFYI(1,("found the last secondary response")); + return 0; /* we are done */ + } else /* more responses to go */ + return 1; + +} + static int cifs_demultiplex_thread(struct TCP_Server_Info *server) { @@ -211,6 +326,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) struct mid_q_entry *mid_entry; char *temp; int isLargeBuf = FALSE; + int isMultiRsp; + int reconnect; daemonize("cifsd"); allow_signal(SIGKILL); @@ -254,6 +371,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) memset(smallbuf, 0, sizeof (struct smb_hdr)); isLargeBuf = FALSE; + isMultiRsp = FALSE; smb_buffer = smallbuf; iov.iov_base = smb_buffer; iov.iov_len = 4; @@ -311,13 +429,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) temp = (char *) smb_buffer; if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { - cFYI(0,("Received 4 byte keep alive packet")); + continue; } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { - cFYI(1,("Good RFC 1002 session rsp")); + cFYI(1,("Good RFC 1002 session rsp")); + continue; } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { /* we get this from Windows 98 instead of an error on SMB negprot response */ - cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); + cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", + temp[4])); if(server->tcpStatus == CifsNew) { /* if nack on negprot (rather than ret of smb negprot error) reconnecting @@ -345,118 +465,140 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) cifs_reconnect(server); csocket = server->ssocket; continue; - } else { /* we have an SMB response */ - if((pdu_length > CIFSMaxBufSize + - MAX_CIFS_HDR_SIZE - 4) || + } + + /* else we have an SMB response */ + if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { - cERROR(1, - ("Invalid size SMB length %d and pdu_length %d", + cERROR(1, ("Invalid size SMB length %d pdu_length %d", length, pdu_length+4)); + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } + + /* else length ok */ + reconnect = 0; + + if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { + isLargeBuf = TRUE; + memcpy(bigbuf, smallbuf, 4); + smb_buffer = bigbuf; + } + length = 0; + iov.iov_base = 4 + (char *)smb_buffer; + iov.iov_len = pdu_length; + for (total_read = 0; total_read < pdu_length; + total_read += length) { + length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, + pdu_length - total_read, 0); + if((server->tcpStatus == CifsExiting) || + (length == -EINTR)) { + /* then will exit */ + reconnect = 2; + break; + } else if (server->tcpStatus == CifsNeedReconnect) { cifs_reconnect(server); csocket = server->ssocket; - wake_up(&server->response_q); + /* Reconnect wakes up rspns q */ + /* Now we will reread sock */ + reconnect = 1; + break; + } else if ((length == -ERESTARTSYS) || + (length == -EAGAIN)) { + msleep(1); /* minimum sleep to prevent looping, + allowing socket to clear and app + threads to set tcpStatus + CifsNeedReconnect if server hung*/ continue; - } else { /* length ok */ - int reconnect = 0; - - if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { - isLargeBuf = TRUE; - memcpy(bigbuf, smallbuf, 4); - smb_buffer = bigbuf; - } - length = 0; - iov.iov_base = 4 + (char *)smb_buffer; - iov.iov_len = pdu_length; - for (total_read = 0; - total_read < pdu_length; - total_read += length) { - length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, - pdu_length - total_read, 0); - if((server->tcpStatus == CifsExiting) || - (length == -EINTR)) { - /* then will exit */ - reconnect = 2; - break; - } else if (server->tcpStatus == - CifsNeedReconnect) { - cifs_reconnect(server); - csocket = server->ssocket; - /* Reconnect wakes up rspns q */ - /* Now we will reread sock */ - reconnect = 1; - break; - } else if ((length == -ERESTARTSYS) || - (length == -EAGAIN)) { - msleep(1); /* minimum sleep to prevent looping - allowing socket to clear and app threads to set - tcpStatus CifsNeedReconnect if server hung */ - continue; - } else if (length <= 0) { - cERROR(1,("Received no data, expecting %d", - pdu_length - total_read)); - cifs_reconnect(server); - csocket = server->ssocket; - reconnect = 1; - break; - } - } - if(reconnect == 2) - break; - else if(reconnect == 1) - continue; - - length += 4; /* account for rfc1002 hdr */ + } else if (length <= 0) { + cERROR(1,("Received no data, expecting %d", + pdu_length - total_read)); + cifs_reconnect(server); + csocket = server->ssocket; + reconnect = 1; + break; } + } + if(reconnect == 2) + break; + else if(reconnect == 1) + continue; - dump_smb(smb_buffer, length); - if (checkSMB - (smb_buffer, smb_buffer->Mid, total_read+4)) { - cERROR(1, ("Bad SMB Received ")); - continue; - } + length += 4; /* account for rfc1002 hdr */ + + dump_smb(smb_buffer, length); + if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { + cERROR(1, ("Bad SMB Received ")); + continue; + } - task_to_wake = NULL; - spin_lock(&GlobalMid_Lock); - list_for_each(tmp, &server->pending_mid_q) { - mid_entry = list_entry(tmp, struct mid_q_entry, - qhead); - - if ((mid_entry->mid == smb_buffer->Mid) - && (mid_entry->midState == - MID_REQUEST_SUBMITTED) - && (mid_entry->command == - smb_buffer->Command)) { - cFYI(1,("Found Mid 0x%x wake up" - ,mid_entry->mid)); - /* BB FIXME - missing code here BB */ - /* check_2nd_t2(smb_buffer); */ - task_to_wake = mid_entry->tsk; - mid_entry->resp_buf = - smb_buffer; - mid_entry->midState = - MID_RESPONSE_RECEIVED; - if(isLargeBuf) - mid_entry->largeBuf = 1; - else - mid_entry->largeBuf = 0; - } - } - spin_unlock(&GlobalMid_Lock); - if (task_to_wake) { + + task_to_wake = NULL; + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + + if ((mid_entry->mid == smb_buffer->Mid) && + (mid_entry->midState == MID_REQUEST_SUBMITTED) && + (mid_entry->command == smb_buffer->Command)) { + cFYI(1,("Found Mid 0x%x wake", mid_entry->mid)); + + if(check2ndT2(smb_buffer,server->maxBuf) > 0) { + /* We have a multipart transact2 resp */ + if(mid_entry->resp_buf) { + /* merge response - fix up 1st*/ + if(coalesce_t2(smb_buffer, + mid_entry->resp_buf)) { + isMultiRsp = TRUE; + break; + } else { + /* all parts received */ + goto multi_t2_fnd; + } + } else { + if(!isLargeBuf) { + cERROR(1,("1st trans2 resp needs bigbuf")); + /* BB maybe we can fix this up, switch + to already allocated large buffer? */ + } else { + mid_entry->resp_buf = + smb_buffer; + mid_entry->largeBuf = 1; + isMultiRsp = TRUE; + bigbuf = NULL; + } + } + break; + } + mid_entry->resp_buf = smb_buffer; if(isLargeBuf) - bigbuf = NULL; + mid_entry->largeBuf = 1; else - smallbuf = NULL; - smb_buffer = NULL; /* will be freed by users thread after he is done */ - wake_up_process(task_to_wake); - } else if (is_valid_oplock_break(smb_buffer) == FALSE) { - cERROR(1, ("No task to wake, unknown frame rcvd!")); - cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + mid_entry->largeBuf = 0; +multi_t2_fnd: + task_to_wake = mid_entry->tsk; + mid_entry->midState = MID_RESPONSE_RECEIVED; + break; } } - } + spin_unlock(&GlobalMid_Lock); + if (task_to_wake) { + if(isLargeBuf) + bigbuf = NULL; + else + smallbuf = NULL; + /* smb buffer freed by user thread when done */ + wake_up_process(task_to_wake); + } else if ((is_valid_oplock_break(smb_buffer) == FALSE) + && (isMultiRsp == FALSE)) { + cERROR(1, ("No task to wake, unknown frame rcvd!")); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + } + } /* end while !EXITING */ + spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; server->tsk = NULL; -- cgit v0.10.2 From 275cde1a1f3880601509c851d72c82bb8d3ee67c Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:10 -0700 Subject: [PATCH] cifs: cleanup various long lines Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index f9e16b3..79bf686 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -41,7 +41,7 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) struct mid_q_entry *temp; if (ses == NULL) { - cERROR(1, ("Null session passed in to AllocMidQEntry ")); + cERROR(1, ("Null session passed in to AllocMidQEntry")); return NULL; } if (ses->server == NULL) { @@ -185,7 +185,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, int smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, - unsigned int smb_buf_length, struct kvec * write_vector /* page list */, struct sockaddr *sin) + unsigned int smb_buf_length, struct kvec * write_vector + /* page list */, struct sockaddr *sin) { int rc = 0; int i = 0; @@ -215,7 +216,8 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, dump_smb(smb_buffer, len); while (len > 0) { - rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, len?); + rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, + len); if ((rc == -ENOSPC) || (rc == -EAGAIN)) { i++; if(i > 60) { @@ -351,8 +353,9 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; -/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec, - (struct sockaddr *) &(ses->server->addr.sockAddr));*/ +/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, + piovec, + (struct sockaddr *) &(ses->server->addr.sockAddr));*/ if(rc < 0) { DeleteMidQEntry(midQ); up(&ses->server->tcpSem); @@ -407,7 +410,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, } else { spin_lock(&GlobalMid_Lock); while(1) { - if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ + if(atomic_read(&ses->server->inFlight) >= + cifs_max_pending){ spin_unlock(&GlobalMid_Lock); wait_event(ses->server->request_q, atomic_read(&ses->server->inFlight) @@ -495,7 +499,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, up(&ses->server->tcpSem); if (long_op == -1) goto cifs_no_response_exit; - else if (long_op == 2) /* writes past end of file can take looooong time */ + else if (long_op == 2) /* writes past end of file can take loong time */ timeout = 300 * HZ; else if (long_op == 1) timeout = 45 * HZ; /* should be greater than @@ -582,8 +586,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ses->server->mac_signing_key, midQ->sequence_number+1); if(rc) { - cERROR(1,("Unexpected packet signature received from server")); - /* BB FIXME - add code to kill session here */ + cERROR(1,("Unexpected SMB signature")); + /* BB FIXME add code to kill session */ } } -- cgit v0.10.2 From cd63499cbe37e53e6cc084c8a35d911a4613c797 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:10 -0700 Subject: [PATCH] cifs: Handle case of multiple trans2 responses for one SMB request (part 2 of 2) Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 0414eb3..3d61d96 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -4,6 +4,8 @@ Fix caching problem, in which readdir of directory containing a file which was cached could cause the file's time stamp to be updated without invalidating the readahead data (so we could get stale file data on the client for that file even as the server copy changed). +Cleanup response processing so cifsd can not loop when abnormally +terminated. Version 1.32 diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a6e6697..f8edf81 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -470,7 +470,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) return rc; } else { smb_buffer_response = smb_buffer; /* BB removeme BB */ - } + } rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, &length, 0); if (rc) @@ -2517,9 +2517,6 @@ findFirstRetry: psrch_inf->srch_entries_start = (char *) &pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->t2.DataOffset); -/* if(le16_to_cpu(pSMBr->t2.DataCount) != le16_to_cpu(pSMBr->t2.TotalDataCount)) { - cERROR(1,("DC: %d TDC: %d",pSMBr->t2.DataCount,pSMBr->t2.TotalDataCount)); -} */ /* BB removeme BB */ parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->t2.ParameterOffset)); @@ -2531,7 +2528,6 @@ findFirstRetry: psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); psrch_inf->index_of_last_entry = psrch_inf->entries_in_buffer; -/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ /* BB removeme BB */ *pnetfid = parms->SearchHandle; } else { cifs_buf_release(pSMB); @@ -3451,11 +3447,13 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, cFYI(1, ("SetFileSize (via SetFileInfo) %lld", (long long)size)); - rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); + if (rc) return rc; + pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; + pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); @@ -3515,7 +3513,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, } if (pSMB) - cifs_buf_release(pSMB); + cifs_small_buf_release(pSMB); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ @@ -3541,11 +3539,13 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I __u16 params, param_offset, offset, byte_count, count; cFYI(1, ("Set Times (via SetFileInfo)")); - rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); + if (rc) return rc; + pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; + /* At this point there is no need to override the current pid with the pid of the opener, but that could change if we someday use an existing handle (rather than opening one on the fly) */ @@ -3591,7 +3591,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc)); } - cifs_buf_release(pSMB); + cifs_small_buf_release(pSMB); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index a8d592b..e3b177a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -544,15 +544,13 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED) && (mid_entry->command == smb_buffer->Command)) { - cFYI(1,("Found Mid 0x%x wake", mid_entry->mid)); - if(check2ndT2(smb_buffer,server->maxBuf) > 0) { /* We have a multipart transact2 resp */ + isMultiRsp = TRUE; if(mid_entry->resp_buf) { /* merge response - fix up 1st*/ if(coalesce_t2(smb_buffer, mid_entry->resp_buf)) { - isMultiRsp = TRUE; break; } else { /* all parts received */ @@ -564,10 +562,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) /* BB maybe we can fix this up, switch to already allocated large buffer? */ } else { + /* Have first buffer */ mid_entry->resp_buf = smb_buffer; mid_entry->largeBuf = 1; - isMultiRsp = TRUE; bigbuf = NULL; } } @@ -586,11 +584,14 @@ multi_t2_fnd: } spin_unlock(&GlobalMid_Lock); if (task_to_wake) { - if(isLargeBuf) - bigbuf = NULL; - else - smallbuf = NULL; - /* smb buffer freed by user thread when done */ + /* Was previous buf put in mpx struct for multi-rsp? */ + if(!isMultiRsp) { + /* smb buffer will be freed by user thread */ + if(isLargeBuf) { + bigbuf = NULL; + } else + smallbuf = NULL; + } wake_up_process(task_to_wake); } else if ((is_valid_oplock_break(smb_buffer) == FALSE) && (isMultiRsp == FALSE)) { -- cgit v0.10.2 From 11aa0149d0e49ee1791735ec4ae3079b27b9a68e Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:10 -0700 Subject: [PATCH] cifs: Fix mapping of EMLINK case Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 3d61d96..21a2464 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,7 @@ +Version 1.34 +------------ +Fix error mapping of the TOO_MANY_LINKS (hardlinks) case. + Version 1.33 ------------ Fix caching problem, in which readdir of directory containing a file diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 8f74279..d00b3bf 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -96,5 +96,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg); -#define CIFS_VERSION "1.33" +#define CIFS_VERSION "1.34" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index dfaabc8..a92af41 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -78,6 +78,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { {ErrQuota, -EDQUOT}, {ErrNotALink, -ENOLINK}, {ERRnetlogonNotStarted,-ENOPROTOOPT}, + {ErrTooManyLinks,-EMLINK}, {0, 0} }; @@ -742,7 +743,7 @@ static const struct { ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, { ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, { ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, { - ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, { + ERRDOS, ErrTooManyLinks, NT_STATUS_TOO_MANY_LINKS}, { ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, { ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, { ERRDOS, 21, 0xc000026e}, { diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index 1b53dcd..cd41c67 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h @@ -107,6 +107,10 @@ #define ErrNotALink 0x201 /* A link operation was performed on a pathname that was not a link. */ +/* Below errors are used internally (do not come over the wire) for passthrough + from STATUS codes to POSIX only */ +#define ErrTooManyLinks 0xFFFE + /* Following error codes may be generated with the ERRSRV error class.*/ #define ERRerror 1 /* Non-specific error code. It is -- cgit v0.10.2 From 57337e42f1393941d59d5154eed27a63988ff2be Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:10 -0700 Subject: [PATCH] cifs: handle termination of cifs oplockd kernel thread Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 21a2464..bd3b55e 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,6 +1,7 @@ Version 1.34 ------------ Fix error mapping of the TOO_MANY_LINKS (hardlinks) case. +Do not oops if user kills cifs oplock kernel thread. Version 1.33 ------------ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 6322aad..8cc23e7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -835,6 +835,7 @@ static int cifs_oplock_thread(void * dummyarg) } } while(!signal_pending(current)); complete_and_exit (&cifs_oplock_exited, 0); + oplockThread = NULL; } static int __init diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e3b177a..437be1e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -384,7 +384,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) if(server->tcpStatus == CifsExiting) { break; } else if (server->tcpStatus == CifsNeedReconnect) { - cFYI(1,("Reconnecting after server stopped responding")); + cFYI(1,("Reconnect after server stopped responding")); cifs_reconnect(server); cFYI(1,("call to reconnect done")); csocket = server->ssocket; @@ -396,7 +396,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) continue; } else if (length <= 0) { if(server->tcpStatus == CifsNew) { - cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); + cFYI(1,("tcp session abend after SMBnegprot")); /* some servers kill the TCP session rather than returning an SMB negprot error, in which case reconnecting here is not going to help, @@ -407,14 +407,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) cFYI(1,("cifsd thread killed")); break; } - cFYI(1,("Reconnecting after unexpected peek error %d",length)); + cFYI(1,("Reconnect after unexpected peek error %d", + length)); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); continue; } else if (length < 4) { cFYI(1, - ("Frame less than four bytes received %d bytes long.", + ("Frame under four bytes received (%d bytes long)", length)); cifs_reconnect(server); csocket = server->ssocket; @@ -593,7 +594,7 @@ multi_t2_fnd: smallbuf = NULL; } wake_up_process(task_to_wake); - } else if ((is_valid_oplock_break(smb_buffer) == FALSE) + } else if ((is_valid_oplock_break(smb_buffer) == FALSE) && (isMultiRsp == FALSE)) { cERROR(1, ("No task to wake, unknown frame rcvd!")); cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 75fd3bd..db14b50 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -452,25 +452,30 @@ is_valid_oplock_break(struct smb_hdr *buf) atomic_inc(&tcon->num_oplock_brks); #endif list_for_each(tmp1,&tcon->openFileList){ - netfile = list_entry(tmp1,struct cifsFileInfo,tlist); + netfile = list_entry(tmp1,struct cifsFileInfo, + tlist); if(pSMB->Fid == netfile->netfid) { struct cifsInodeInfo *pCifsInode; read_unlock(&GlobalSMBSeslock); - cFYI(1,("Matching file id, processing oplock break")); + cFYI(1,("file id match, oplock break")); pCifsInode = CIFS_I(netfile->pInode); pCifsInode->clientCanCacheAll = FALSE; if(pSMB->OplockLevel == 0) - pCifsInode->clientCanCacheRead = FALSE; + pCifsInode->clientCanCacheRead + = FALSE; pCifsInode->oplockPending = TRUE; - AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon); + AllocOplockQEntry(netfile->pInode, + netfile->netfid, + tcon); cFYI(1,("about to wake up oplock thd")); - wake_up_process(oplockThread); + if(oplockThread) + wake_up_process(oplockThread); return TRUE; } } read_unlock(&GlobalSMBSeslock); - cFYI(1,("No matching file for oplock break on connection")); + cFYI(1,("No matching file for oplock break")); return TRUE; } } @@ -491,7 +496,7 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) buffer = (unsigned char *) smb_buf; for (i = 0, j = 0; i < smb_buf_length; i++, j++) { - if (i % 8 == 0) { /* we have reached the beginning of line */ + if (i % 8 == 0) { /* have reached the beginning of line */ printk(KERN_DEBUG "| "); j = 0; } @@ -502,7 +507,7 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) else debug_line[1 + (2 * j)] = '_'; - if (i % 8 == 7) { /* we have reached end of line, time to print ascii */ + if (i % 8 == 7) { /* reached end of line, time to print ascii */ debug_line[16] = 0; printk(" | %s\n", debug_line); } @@ -577,7 +582,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, } } j++; - /* check to make sure we do not overrun callers allocated temp buffer */ + /* make sure we do not overrun callers allocated temp buffer */ if(j >= (2 * NAME_MAX)) break; } @@ -599,7 +604,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, char src_char; if(!mapChars) - return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); + return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); for(i = 0, j = 0; i < maxlen; j++) { src_char = source[i]; -- cgit v0.10.2 From 31ca3bc3c569f9fe02aae6974ac3a9126f14902f Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:11 -0700 Subject: [PATCH] cifs: Do not init smb requests or block when sending requests if cifsd thread is no longer running to demultixplex responses. Do not send FindClose request when FindFirst failed without reaching end of search. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index bd3b55e..4d24043 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,7 +1,10 @@ Version 1.34 ------------ Fix error mapping of the TOO_MANY_LINKS (hardlinks) case. -Do not oops if user kills cifs oplock kernel thread. +Do not oops if root user kills cifs oplock kernel thread or +kills the cifsd thread (NB: killing the cifs kernel threads is not +recommended, unmount and rmmod cifs will kill them when they are +no longer needed). Version 1.33 ------------ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f8edf81..b004fef 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -90,7 +90,8 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, check for tcp and smb session status done differently for those three - in the calling routine */ if(tcon) { - if((tcon->ses) && (tcon->ses->server)){ + if((tcon->ses) && (tcon->ses->status != CifsExiting) && + (tcon->ses->server)){ struct nls_table *nls_codepage; /* Give Demultiplex thread up to 10 seconds to reconnect, should be greater than cifs socket @@ -185,7 +186,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, check for tcp and smb session status done differently for those three - in the calling routine */ if(tcon) { - if((tcon->ses) && (tcon->ses->server)){ + if((tcon->ses) && (tcon->ses->status != CifsExiting) && + (tcon->ses->server)){ struct nls_table *nls_codepage; /* Give Demultiplex thread up to 10 seconds to reconnect, should be greater than cifs socket diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 437be1e..ac1f970 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -604,7 +604,13 @@ multi_t2_fnd: spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; server->tsk = NULL; - atomic_set(&server->inFlight, 0); + /* check if we have blocked requests that need to free */ + /* Note that cifs_max_pending is normally 50, but + can be set at module install time to as little as two */ + if(atomic_read(&server->inFlight) >= cifs_max_pending) + atomic_set(&server->inFlight, cifs_max_pending - 1); + /* We do not want to set the max_pending too low or we + could end up with the counter going negative */ spin_unlock(&GlobalMid_Lock); /* Although there should not be any requests blocked on this queue it can not hurt to be paranoid and try to wake up requests @@ -640,6 +646,17 @@ multi_t2_fnd: } read_unlock(&GlobalSMBSeslock); } else { + /* although we can not zero the server struct pointer yet, + since there are active requests which may depnd on them, + mark the corresponding SMB sessions as exiting too */ + list_for_each(tmp, &GlobalSMBSessionList) { + ses = list_entry(tmp, struct cifsSesInfo, + cifsSessionList); + if (ses->server == server) { + ses->status = CifsExiting; + } + } + spin_lock(&GlobalMid_Lock); list_for_each(tmp, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); @@ -661,17 +678,34 @@ multi_t2_fnd: if (list_empty(&server->pending_mid_q)) { /* mpx threads have not exited yet give them at least the smb send timeout time for long ops */ + /* due to delays on oplock break requests, we need + to wait at least 45 seconds before giving up + on a request getting a response and going ahead + and killing cifsd */ cFYI(1, ("Wait for exit from demultiplex thread")); - msleep(46); + msleep(46000); /* if threads still have not exited they are probably never coming home not much else we can do but free the memory */ } - kfree(server); write_lock(&GlobalSMBSeslock); atomic_dec(&tcpSesAllocCount); length = tcpSesAllocCount.counter; + + /* last chance to mark ses pointers invalid + if there are any pointing to this (e.g + if a crazy root user tried to kill cifsd + kernel thread explicitly this might happen) */ + list_for_each(tmp, &GlobalSMBSessionList) { + ses = list_entry(tmp, struct cifsSesInfo, + cifsSessionList); + if (ses->server == server) { + ses->server = NULL; + } + } write_unlock(&GlobalSMBSeslock); + + kfree(server); if(length > 0) { mempool_resize(cifs_req_poolp, length + cifs_min_rcv, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 1df26dd..dde2d25 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -512,7 +512,8 @@ int cifs_closedir(struct inode *inode, struct file *file) pTcon = cifs_sb->tcon; cFYI(1, ("Freeing private data in close dir")); - if (pCFileStruct->srch_inf.endOfSearch == FALSE) { + if ((pCFileStruct->srch_inf.endOfSearch == FALSE) && + (pCFileStruct->invalidHandle == FALSE)) { pCFileStruct->invalidHandle = TRUE; rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); cFYI(1, ("Closing uncompleted readdir with rc %d", diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 79bf686..0046c21 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -270,6 +270,9 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, + if(ses->server->tcpStatus == CIFS_EXITING) + return -ENOENT; + /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ @@ -401,6 +404,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, return -EIO; } + if(ses->server->tcpStatus == CifsExiting) + return -ENOENT; + /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ -- cgit v0.10.2 From 0cb766ae629c70d53040f85de73db0583eadb233 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:11 -0700 Subject: [PATCH] cifs: Do not sleep interruptible after socket connect failure .. since it can be due to pending kill. Update readme information to better describe cifs umount Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/README b/fs/cifs/README index bec7b3f..7b4ac09 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -101,12 +101,15 @@ Allowing User Unmounts ====================== To permit users to ummount directories that they have user mounted (see above), the utility umount.cifs may be used. It may be invoked directly, or if -umount.cifs is placed in /sbin, umount -i can invoke the cifs umount helper +umount.cifs is placed in /sbin, umount can invoke the cifs umount helper (at least for most versions of the umount utility) for umount of cifs -mounts. As with mount.cifs, to enable user unmounts umount.cifs must be marked -as suid (e.g. "chmod +s /sbin/umount.cifs"). For this utility to succeed -the target path must be a cifs mount, and the uid of the current user must -match the uid of the user who mounted the resource. +mounts, unless umount is invoked with -i (which will avoid invoking a umount +helper). As with mount.cifs, to enable user unmounts umount.cifs must be marked +as suid (e.g. "chmod +s /sbin/umount.cifs") or equivalent (some distributions +allow adding entries to a file to the /etc/permissions file to achieve the +equivalent suid effect). For this utility to succeed the target path +must be a cifs mount, and the uid of the current user must match the uid +of the user who mounted the resource. Also note that the customary way of allowing user mounts and unmounts is (instead of using mount.cifs and unmount.cifs as suid) to add a line @@ -404,6 +407,8 @@ A partial list of the supported mount options follows: This has no effect if the server does not support Unicode on the wire. nomapchars Do not translate any of these seven characters (default). + remount remount the share (often used to change from ro to rw mounts + or vice versa) The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ac1f970..e568cc4 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -178,8 +178,7 @@ cifs_reconnect(struct TCP_Server_Info *server) server->workstation_RFC1001_name); } if(rc) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(3 * HZ); + msleep(3000); } else { atomic_inc(&tcpSesReconnectCount); spin_lock(&GlobalMid_Lock); -- cgit v0.10.2 From c60c390620e0abb60d4ae8c43583714bda27763f Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 28 Apr 2005 22:47:29 -0700 Subject: [PATCH] x86_64: fix PT_NOTE addition to IA32 vDSO The addition of the PT_NOTE didn't take in the x86_64 version of the i386 vDSO, because I forgot the linker script bit in that copy. Signed-off-by: Roland McGrath Signed-off-by: Linus Torvalds diff --git a/arch/x86_64/ia32/vsyscall.lds b/arch/x86_64/ia32/vsyscall.lds index fa4b4dd..f2e75ed 100644 --- a/arch/x86_64/ia32/vsyscall.lds +++ b/arch/x86_64/ia32/vsyscall.lds @@ -36,6 +36,7 @@ SECTIONS .text.rtsigreturn : { *(.text.rtsigreturn) } :text =0x90909090 + .note : { *(.note.*) } :text :note .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr .eh_frame : { KEEP (*(.eh_frame)) } :text .dynamic : { *(.dynamic) } :text :dynamic @@ -55,6 +56,7 @@ PHDRS { text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + note PT_NOTE FLAGS(4); /* PF_R */ eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ } -- cgit v0.10.2 From 42d4dc3f4e1ec1396371aac89d0dccfdd977191b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 29 Apr 2005 07:40:12 -0700 Subject: [PATCH] Add suspend method to cpufreq core In order to properly fix some issues with cpufreq vs. sleep on PowerBooks, I had to add a suspend callback to the pmac_cpufreq driver. I must force a switch to full speed before sleep and I switch back to previous speed on resume. I also added a driver flag to disable the warnings in suspend/resume since it is expected in this case to have different speed (and I want it to fixup the jiffies properly). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b30001f..4fc0cb7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -223,7 +223,7 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) } if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || - (val == CPUFREQ_RESUMECHANGE)) { + (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); dprintk("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new); } @@ -866,11 +866,90 @@ EXPORT_SYMBOL(cpufreq_get); /** + * cpufreq_suspend - let the low level driver prepare for suspend + */ + +static int cpufreq_suspend(struct sys_device * sysdev, u32 state) +{ + int cpu = sysdev->id; + unsigned int ret = 0; + unsigned int cur_freq = 0; + struct cpufreq_policy *cpu_policy; + + dprintk("resuming cpu %u\n", cpu); + + if (!cpu_online(cpu)) + return 0; + + /* we may be lax here as interrupts are off. Nonetheless + * we need to grab the correct cpu policy, as to check + * whether we really run on this CPU. + */ + + cpu_policy = cpufreq_cpu_get(cpu); + if (!cpu_policy) + return -EINVAL; + + /* only handle each CPU group once */ + if (unlikely(cpu_policy->cpu != cpu)) { + cpufreq_cpu_put(cpu_policy); + return 0; + } + + if (cpufreq_driver->suspend) { + ret = cpufreq_driver->suspend(cpu_policy, state); + if (ret) { + printk(KERN_ERR "cpufreq: suspend failed in ->suspend " + "step on CPU %u\n", cpu_policy->cpu); + cpufreq_cpu_put(cpu_policy); + return ret; + } + } + + + if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS) + goto out; + + if (cpufreq_driver->get) + cur_freq = cpufreq_driver->get(cpu_policy->cpu); + + if (!cur_freq || !cpu_policy->cur) { + printk(KERN_ERR "cpufreq: suspend failed to assert current " + "frequency is what timing core thinks it is.\n"); + goto out; + } + + if (unlikely(cur_freq != cpu_policy->cur)) { + struct cpufreq_freqs freqs; + + if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) + printk(KERN_DEBUG "Warning: CPU frequency is %u, " + "cpufreq assumed %u kHz.\n", + cur_freq, cpu_policy->cur); + + freqs.cpu = cpu; + freqs.old = cpu_policy->cur; + freqs.new = cur_freq; + + notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_SUSPENDCHANGE, &freqs); + adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs); + + cpu_policy->cur = cur_freq; + } + + out: + cpufreq_cpu_put(cpu_policy); + return 0; +} + +/** * cpufreq_resume - restore proper CPU frequency handling after resume * * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) * 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync - * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are restored. + * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are + * restored. */ static int cpufreq_resume(struct sys_device * sysdev) { @@ -915,7 +994,9 @@ static int cpufreq_resume(struct sys_device * sysdev) cur_freq = cpufreq_driver->get(cpu_policy->cpu); if (!cur_freq || !cpu_policy->cur) { - printk(KERN_ERR "cpufreq: resume failed to assert current frequency is what timing core thinks it is.\n"); + printk(KERN_ERR "cpufreq: resume failed to assert " + "current frequency is what timing core " + "thinks it is.\n"); goto out; } @@ -923,13 +1004,15 @@ static int cpufreq_resume(struct sys_device * sysdev) struct cpufreq_freqs freqs; printk(KERN_WARNING "Warning: CPU frequency is %u, " - "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur); + "cpufreq assumed %u kHz.\n", + cur_freq, cpu_policy->cur); freqs.cpu = cpu; freqs.old = cpu_policy->cur; freqs.new = cur_freq; - notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs); + notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_RESUMECHANGE, &freqs); adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); cpu_policy->cur = cur_freq; @@ -945,6 +1028,7 @@ out: static struct sysdev_driver cpufreq_sysdev_driver = { .add = cpufreq_add_dev, .remove = cpufreq_remove_dev, + .suspend = cpufreq_suspend, .resume = cpufreq_resume, }; diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 910eca3..f21af06 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -103,6 +103,7 @@ struct cpufreq_policy { #define CPUFREQ_PRECHANGE (0) #define CPUFREQ_POSTCHANGE (1) #define CPUFREQ_RESUMECHANGE (8) +#define CPUFREQ_SUSPENDCHANGE (9) struct cpufreq_freqs { unsigned int cpu; /* cpu nr */ @@ -200,6 +201,7 @@ struct cpufreq_driver { /* optional */ int (*exit) (struct cpufreq_policy *policy); + int (*suspend) (struct cpufreq_policy *policy, u32 state); int (*resume) (struct cpufreq_policy *policy); struct freq_attr **attr; }; @@ -211,7 +213,8 @@ struct cpufreq_driver { #define CPUFREQ_CONST_LOOPS 0x02 /* loops_per_jiffy or other kernel * "constants" aren't affected by * frequency transitions */ - +#define CPUFREQ_PM_NO_WARN 0x04 /* don't warn on suspend/resume speed + * mismatches */ int cpufreq_register_driver(struct cpufreq_driver *driver_data); int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); -- cgit v0.10.2 From 83c7d09173fdb6b06b109e65895392db3e49ac9c Mon Sep 17 00:00:00 2001 From: Date: Fri, 29 Apr 2005 15:54:44 +0100 Subject: AUDIT: Avoid log pollution by untrusted strings. We log strings from userspace, such as arguments to open(). These could be formatted to contain \n followed by fake audit log entries. Provide a function for logging such strings, which gives a hex dump when the string contains anything but basic printable ASCII characters. Use it for logging filenames. Signed-off-by: David Woodhouse diff --git a/include/linux/audit.h b/include/linux/audit.h index 3628f7c..9b77992 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -174,11 +174,15 @@ extern void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) __attribute__((format(printf,2,3))); extern void audit_log_end(struct audit_buffer *ab); +extern void audit_log_hex(struct audit_buffer *ab, + const unsigned char *buf, + size_t len); +extern void audit_log_untrustedstring(struct audit_buffer *ab, + const char *string); extern void audit_log_d_path(struct audit_buffer *ab, const char *prefix, struct dentry *dentry, struct vfsmount *vfsmnt); - /* Private API (for auditsc.c only) */ extern void audit_send_reply(int pid, int seq, int type, int done, int multi, @@ -190,6 +194,8 @@ extern void audit_log_lost(const char *message); #define audit_log_vformat(b,f,a) do { ; } while (0) #define audit_log_format(b,f,...) do { ; } while (0) #define audit_log_end(b) do { ; } while (0) +#define audit_log_hex(a,b,l) do { ; } while (0) +#define audit_log_untrustedstring(a,s) do { ; } while (0) #define audit_log_d_path(b,p,d,v) do { ; } while (0) #endif #endif diff --git a/kernel/audit.c b/kernel/audit.c index 0f84dd7..dca7b99 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -720,6 +720,29 @@ void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) va_end(args); } +void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, size_t len) +{ + int i; + + for (i=0; i 0x7f) { + audit_log_hex(ab, string, strlen(string)); + return; + } + p++; + } + audit_log_format(ab, "\"%s\"", string); +} + + /* This is a helper-function to print the d_path without using a static * buffer or allocating another buffer in addition to the one in * audit_buffer. */ diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 6f19313..00e87ff 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -696,9 +696,10 @@ static void audit_log_exit(struct audit_context *context) if (!ab) continue; /* audit_panic has been called */ audit_log_format(ab, "item=%d", i); - if (context->names[i].name) - audit_log_format(ab, " name=%s", - context->names[i].name); + if (context->names[i].name) { + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, context->names[i].name); + } if (context->names[i].ino != (unsigned long)-1) audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o" " uid=%d gid=%d rdev=%02x:%02x", -- cgit v0.10.2 From 81b7854d52d35ed2353dd47033ae630d18322a2d Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 29 Apr 2005 15:59:11 +0100 Subject: audit_log_untrustedstring() warning fix kernel/audit.c: In function `audit_log_untrustedstring': kernel/audit.c:736: warning: comparison is always false due to limited range of data type Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse diff --git a/kernel/audit.c b/kernel/audit.c index dca7b99..e7bff80 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -730,7 +730,7 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, size_t len void audit_log_untrustedstring(struct audit_buffer *ab, const char *string) { - const char *p = string; + const unsigned char *p = string; while (*p) { if (*p == '"' || *p == ' ' || *p < 0x20 || *p > 0x7f) { -- cgit v0.10.2 From ea3834d9fb348fb1144ad3affea22df933eaf62e Mon Sep 17 00:00:00 2001 From: Prasanna Meda Date: Fri, 29 Apr 2005 16:00:17 +0100 Subject: namei: add audit_inode to all branches in path_lookup Main change is in path_lookup: added a goto to do audit_inode instead of return statement, when emul_lookup_dentry for root is successful.The existing code does audit_inode only when lookup is done in normal root or cwd. Other changes: Some lookup routines are returning zero on success, and some are returning zero on failure. I documented the related function signatures in this code path, so that one can glance over abstract functions without understanding the entire code. Signed-off-by: Prasanna Meda Signed-off-by: David Woodhouse diff --git a/fs/namei.c b/fs/namei.c index 9e4aef2..0f76fd7 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -686,11 +686,11 @@ fail: /* * Name resolution. + * This is the basic name resolution function, turning a pathname into + * the final dentry. We expect 'base' to be positive and a directory. * - * This is the basic name resolution function, turning a pathname - * into the final dentry. - * - * We expect 'base' to be positive and a directory. + * Returns 0 and nd will have valid dentry and mnt on success. + * Returns error and drops reference to input namei data on failure. */ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) { @@ -929,8 +929,10 @@ int fastcall path_walk(const char * name, struct nameidata *nd) return link_path_walk(name, nd); } -/* SMP-safe */ -/* returns 1 if everything is done */ +/* + * SMP-safe: Returns 1 and nd will have valid dentry and mnt, if + * everything is done. Returns 0 and drops input nd, if lookup failed; + */ static int __emul_lookup_dentry(const char *name, struct nameidata *nd) { if (path_walk(name, nd)) @@ -994,9 +996,10 @@ set_it: } } +/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) { - int retval; + int retval = 0; nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags; @@ -1009,7 +1012,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata nd->dentry = dget(current->fs->altroot); read_unlock(¤t->fs->lock); if (__emul_lookup_dentry(name,nd)) - return 0; + goto out; /* found in altroot */ read_lock(¤t->fs->lock); } nd->mnt = mntget(current->fs->rootmnt); @@ -1021,6 +1024,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata read_unlock(¤t->fs->lock); current->total_link_count = 0; retval = link_path_walk(name, nd); +out: if (unlikely(current->audit_context && nd && nd->dentry && nd->dentry->d_inode)) audit_inode(name, nd->dentry->d_inode); -- cgit v0.10.2 From 2fd6f58ba6efc82ea2c9c2630f7ff5ed9eeaf34a Mon Sep 17 00:00:00 2001 From: Date: Fri, 29 Apr 2005 16:08:28 +0100 Subject: [AUDIT] Don't allow ptrace to fool auditing, log arch of audited syscalls. We were calling ptrace_notify() after auditing the syscall and arguments, but the debugger could have _changed_ them before the syscall was actually invoked. Reorder the calls to fix that. While we're touching ever call to audit_syscall_entry(), we also make it take an extra argument: the architecture of the syscall which was made, because some architectures allow more than one type of syscall. Also add an explicit success/failure flag to audit_syscall_exit(), for the benefit of architectures which return that in a condition register rather than only returning a single register. Change type of syscall return value to 'long' not 'int'. Signed-off-by: David Woodhouse diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index b2f1764..5606ec7 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -682,24 +682,18 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit) /* do the secure computing check first */ secure_computing(regs->orig_eax); - if (unlikely(current->audit_context)) { - if (!entryexit) - audit_syscall_entry(current, regs->orig_eax, - regs->ebx, regs->ecx, - regs->edx, regs->esi); - else - audit_syscall_exit(current, regs->eax); - } + if (unlikely(current->audit_context) && entryexit) + audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax); if (!(current->ptrace & PT_PTRACED)) - return; + goto out; /* Fake a debug trap */ if (test_thread_flag(TIF_SINGLESTEP)) send_sigtrap(current, regs, 0); if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; + goto out; /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ @@ -714,4 +708,9 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit) send_sig(current->exit_code, current, 1); current->exit_code = 0; } + out: + if (unlikely(current->audit_context) && !entryexit) + audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax, + regs->ebx, regs->ecx, regs->edx, regs->esi); + } diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 55789fc..8dde0b1 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1595,20 +1595,25 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, struct pt_regs regs) { - long syscall; + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + syscall_trace(); if (unlikely(current->audit_context)) { - if (IS_IA32_PROCESS(®s)) + long syscall; + int arch; + + if (IS_IA32_PROCESS(®s)) { syscall = regs.r1; - else + arch = AUDIT_ARCH_I386; + } else { syscall = regs.r15; + arch = AUDIT_ARCH_IA64; + } - audit_syscall_entry(current, syscall, arg0, arg1, arg2, arg3); + audit_syscall_entry(current, arch, syscall, arg0, arg1, arg2, arg3); } - if (test_thread_flag(TIF_SYSCALL_TRACE) - && (current->ptrace & PT_PTRACED)) - syscall_trace(); } /* "asmlinkage" so the input arguments are preserved... */ @@ -1619,7 +1624,7 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3, struct pt_regs regs) { if (unlikely(current->audit_context)) - audit_syscall_exit(current, regs.r8); + audit_syscall_exit(current, AUDITSC_RESULT(regs.r10), regs.r8); if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED)) diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 92f2c39..eaf7be9 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -300,25 +300,38 @@ out: return ret; } +static inline int audit_arch() +{ +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#ifdef CONFIG_MIPS64 + if (!(current->thread.mflags & MF_32BIT_REGS)) + return AUDIT_ARCH_MIPSEL64; +#endif /* MIPS64 */ + return AUDIT_ARCH_MIPSEL; + +#else /* big endian... */ +#ifdef CONFIG_MIPS64 + if (!(current->thread.mflags & MF_32BIT_REGS)) + return AUDIT_ARCH_MIPS64; +#endif /* MIPS64 */ + return AUDIT_ARCH_MIPS; + +#endif /* endian */ +} + /* * Notification of system call entry/exit * - triggered by current->work.syscall_trace */ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) { - if (unlikely(current->audit_context)) { - if (!entryexit) - audit_syscall_entry(current, regs->regs[2], - regs->regs[4], regs->regs[5], - regs->regs[6], regs->regs[7]); - else - audit_syscall_exit(current, regs->regs[2]); - } + if (unlikely(current->audit_context) && entryexit) + audit_syscall_exit(current, AUDITSC_RESULT(regs->regs[2]), regs->regs[2]); if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; + goto out; if (!(current->ptrace & PT_PTRACED)) - return; + goto out; /* The 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ @@ -334,4 +347,9 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) send_sig(current->exit_code, current, 1); current->exit_code = 0; } + out: + if (unlikely(current->audit_context) && !entryexit) + audit_syscall_entry(current, audit_arch(), regs->regs[2], + regs->regs[4], regs->regs[5], + regs->regs[6], regs->regs[7]); } diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index 354a287..3c76333 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c @@ -304,14 +304,17 @@ static void do_syscall_trace(void) void do_syscall_trace_enter(struct pt_regs *regs) { + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + do_syscall_trace(); + if (unlikely(current->audit_context)) - audit_syscall_entry(current, regs->gpr[0], + audit_syscall_entry(current, + test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64, + regs->gpr[0], regs->gpr[3], regs->gpr[4], regs->gpr[5], regs->gpr[6]); - if (test_thread_flag(TIF_SYSCALL_TRACE) - && (current->ptrace & PT_PTRACED)) - do_syscall_trace(); } void do_syscall_trace_leave(struct pt_regs *regs) @@ -319,7 +322,9 @@ void do_syscall_trace_leave(struct pt_regs *regs) secure_computing(regs->gpr[0]); if (unlikely(current->audit_context)) - audit_syscall_exit(current, regs->result); + audit_syscall_exit(current, + (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, + regs->result); if ((test_thread_flag(TIF_SYSCALL_TRACE) || test_thread_flag(TIF_SINGLESTEP)) diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 647233c..2d546c6 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -711,18 +711,13 @@ out: asmlinkage void syscall_trace(struct pt_regs *regs, int entryexit) { - if (unlikely(current->audit_context)) { - if (!entryexit) - audit_syscall_entry(current, regs->gprs[2], - regs->orig_gpr2, regs->gprs[3], - regs->gprs[4], regs->gprs[5]); - else - audit_syscall_exit(current, regs->gprs[2]); - } + if (unlikely(current->audit_context) && entryexit) + audit_syscall_exit(current, AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); + if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; + goto out; if (!(current->ptrace & PT_PTRACED)) - return; + goto out; ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); @@ -735,4 +730,10 @@ syscall_trace(struct pt_regs *regs, int entryexit) send_sig(current->exit_code, current, 1); current->exit_code = 0; } + out: + if (unlikely(current->audit_context) && !entryexit) + audit_syscall_entry(current, + test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X, + regs->gprs[2], regs->orig_gpr2, regs->gprs[3], + regs->gprs[4], regs->gprs[5]); } diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index c701167..ecbccbb 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -629,25 +629,28 @@ static void syscall_trace(struct pt_regs *regs) } } +#define audit_arch() (test_thread_flag(TIF_IA32) ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64) + asmlinkage void syscall_trace_enter(struct pt_regs *regs) { /* do the secure computing check first */ secure_computing(regs->orig_rax); + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + syscall_trace(regs); + if (unlikely(current->audit_context)) - audit_syscall_entry(current, regs->orig_rax, + audit_syscall_entry(current, audit_arch(), regs->orig_rax, regs->rdi, regs->rsi, regs->rdx, regs->r10); - if (test_thread_flag(TIF_SYSCALL_TRACE) - && (current->ptrace & PT_PTRACED)) - syscall_trace(regs); } asmlinkage void syscall_trace_leave(struct pt_regs *regs) { if (unlikely(current->audit_context)) - audit_syscall_exit(current, regs->rax); + audit_syscall_exit(current, AUDITSC_RESULT(regs->rax), regs->rax); if ((test_thread_flag(TIF_SYSCALL_TRACE) || test_thread_flag(TIF_SINGLESTEP)) diff --git a/include/linux/audit.h b/include/linux/audit.h index 9b77992..fad0c1d 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -24,6 +24,9 @@ #ifndef _LINUX_AUDIT_H_ #define _LINUX_AUDIT_H_ +#include +#include + /* Request and reply types */ #define AUDIT_GET 1000 /* Get status */ #define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */ @@ -67,6 +70,7 @@ #define AUDIT_FSGID 8 #define AUDIT_LOGINUID 9 #define AUDIT_PERS 10 +#define AUDIT_ARCH 11 /* These are ONLY useful when checking * at syscall exit time (AUDIT_AT_EXIT). */ @@ -96,6 +100,38 @@ #define AUDIT_FAIL_PRINTK 1 #define AUDIT_FAIL_PANIC 2 +/* distinguish syscall tables */ +#define __AUDIT_ARCH_64BIT 0x80000000 +#define __AUDIT_ARCH_LE 0x40000000 +#define AUDIT_ARCH_ALPHA (EM_ALPHA|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_ARM (EM_ARM|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_ARMEB (EM_ARM) +#define AUDIT_ARCH_CRIS (EM_CRIS|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_FRV (EM_FRV) +#define AUDIT_ARCH_H8300 (EM_H8_300) +#define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_IA64 (EM_IA_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_M32R (EM_M32R) +#define AUDIT_ARCH_M68K (EM_68K) +#define AUDIT_ARCH_MIPS (EM_MIPS) +#define AUDIT_ARCH_MIPSEL (EM_MIPS|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_MIPS64 (EM_MIPS|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_MIPSEL64 (EM_MIPS|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_PARISC (EM_PARISC) +#define AUDIT_ARCH_PARISC64 (EM_PARISC|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_PPC (EM_PPC) +#define AUDIT_ARCH_PPC64 (EM_PPC64|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_S390 (EM_S390) +#define AUDIT_ARCH_S390X (EM_S390|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_SH (EM_SH) +#define AUDIT_ARCH_SHEL (EM_SH|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_SH64 (EM_SH|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_SHEL64 (EM_SH|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_SPARC (EM_SPARC) +#define AUDIT_ARCH_SPARC64 (EM_SPARC64|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_V850 (EM_V850|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) + #ifndef __KERNEL__ struct audit_message { struct nlmsghdr nlh; @@ -129,15 +165,19 @@ struct audit_buffer; struct audit_context; struct inode; +#define AUDITSC_INVALID 0 +#define AUDITSC_SUCCESS 1 +#define AUDITSC_FAILURE 2 +#define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS ) #ifdef CONFIG_AUDITSYSCALL /* These are defined in auditsc.c */ /* Public API */ extern int audit_alloc(struct task_struct *task); extern void audit_free(struct task_struct *task); -extern void audit_syscall_entry(struct task_struct *task, +extern void audit_syscall_entry(struct task_struct *task, int arch, int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3); -extern void audit_syscall_exit(struct task_struct *task, int return_code); +extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code); extern void audit_getname(const char *name); extern void audit_putname(const char *name); extern void audit_inode(const char *name, const struct inode *inode); @@ -153,8 +193,8 @@ extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mo #else #define audit_alloc(t) ({ 0; }) #define audit_free(t) do { ; } while (0) -#define audit_syscall_entry(t,a,b,c,d,e) do { ; } while (0) -#define audit_syscall_exit(t,r) do { ; } while (0) +#define audit_syscall_entry(t,ta,a,b,c,d,e) do { ; } while (0) +#define audit_syscall_exit(t,f,r) do { ; } while (0) #define audit_getname(n) do { ; } while (0) #define audit_putname(n) do { ; } while (0) #define audit_inode(n,i) do { ; } while (0) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 00e87ff..77e9259 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -123,7 +123,7 @@ struct audit_context { int major; /* syscall number */ unsigned long argv[4]; /* syscall arguments */ int return_valid; /* return code is valid */ - int return_code;/* syscall return code */ + long return_code;/* syscall return code */ int auditable; /* 1 if record should be written */ int name_count; struct audit_names names[AUDIT_NAMES]; @@ -135,6 +135,7 @@ struct audit_context { uid_t uid, euid, suid, fsuid; gid_t gid, egid, sgid, fsgid; unsigned long personality; + int arch; #if AUDIT_DEBUG int put_count; @@ -348,6 +349,10 @@ static int audit_filter_rules(struct task_struct *tsk, case AUDIT_PERS: result = (tsk->personality == value); break; + case AUDIT_ARCH: + if (ctx) + result = (ctx->arch == value); + break; case AUDIT_EXIT: if (ctx && ctx->return_valid) @@ -355,7 +360,7 @@ static int audit_filter_rules(struct task_struct *tsk, break; case AUDIT_SUCCESS: if (ctx && ctx->return_valid) - result = (ctx->return_code >= 0); + result = (ctx->return_valid == AUDITSC_SUCCESS); break; case AUDIT_DEVMAJOR: if (ctx) { @@ -648,8 +653,11 @@ static void audit_log_exit(struct audit_context *context) audit_log_format(ab, "syscall=%d", context->major); if (context->personality != PER_LINUX) audit_log_format(ab, " per=%lx", context->personality); + audit_log_format(ab, " arch=%x", context->arch); if (context->return_valid) - audit_log_format(ab, " exit=%d", context->return_code); + audit_log_format(ab, " success=%s exit=%ld", + (context->return_valid==AUDITSC_SUCCESS)?"yes":"no", + context->return_code); audit_log_format(ab, " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" " pid=%d loginuid=%d uid=%d gid=%d" @@ -773,7 +781,7 @@ static inline unsigned int audit_serial(void) * then the record will be written at syscall exit time (otherwise, it * will only be written if another part of the kernel requests that it * be written). */ -void audit_syscall_entry(struct task_struct *tsk, int major, +void audit_syscall_entry(struct task_struct *tsk, int arch, int major, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4) { @@ -827,6 +835,7 @@ void audit_syscall_entry(struct task_struct *tsk, int major, if (!audit_enabled) return; + context->arch = arch; context->major = major; context->argv[0] = a1; context->argv[1] = a2; @@ -850,13 +859,13 @@ void audit_syscall_entry(struct task_struct *tsk, int major, * filtering, or because some other part of the kernel write an audit * message), then write out the syscall information. In call cases, * free the names stored from getname(). */ -void audit_syscall_exit(struct task_struct *tsk, int return_code) +void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code) { struct audit_context *context; get_task_struct(tsk); task_lock(tsk); - context = audit_get_context(tsk, 1, return_code); + context = audit_get_context(tsk, valid, return_code); task_unlock(tsk); /* Not having a context here is ok, since the parent may have @@ -869,6 +878,7 @@ void audit_syscall_exit(struct task_struct *tsk, int return_code) context->in_syscall = 0; context->auditable = 0; + if (context->previous) { struct audit_context *new_context = context->previous; context->previous = NULL; -- cgit v0.10.2 From d812ddbb89e323d054a7d073466225966c8350c8 Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Fri, 29 Apr 2005 16:09:52 +0100 Subject: [AUDIT] Fix signedness of 'serial' in various routines. Attached is a patch that corrects a signed/unsigned warning. I also noticed that we needlessly init serial to 0. That only needs to occur if the kernel was compiled without the audit system. -Steve Grubb Signed-off-by: David Woodhouse diff --git a/include/linux/audit.h b/include/linux/audit.h index fad0c1d..0467f24 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -186,7 +186,7 @@ extern void audit_inode(const char *name, const struct inode *inode); extern int audit_receive_filter(int type, int pid, int uid, int seq, void *data); extern void audit_get_stamp(struct audit_context *ctx, - struct timespec *t, int *serial); + struct timespec *t, unsigned int *serial); extern int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid); extern uid_t audit_get_loginuid(struct audit_context *ctx); extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); diff --git a/kernel/audit.c b/kernel/audit.c index e7bff80..aa35422 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -620,7 +620,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx) struct audit_buffer *ab = NULL; unsigned long flags; struct timespec t; - int serial = 0; + unsigned int serial; if (!audit_initialized) return NULL; @@ -669,8 +669,10 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx) audit_get_stamp(ab->ctx, &t, &serial); else #endif + { t = CURRENT_TIME; - + serial = 0; + } audit_log_format(ab, "audit(%lu.%03lu:%u): ", t.tv_sec, t.tv_nsec/1000000, serial); return ab; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 77e9259..49ecd70 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -992,7 +992,7 @@ void audit_inode(const char *name, const struct inode *inode) } void audit_get_stamp(struct audit_context *ctx, - struct timespec *t, int *serial) + struct timespec *t, unsigned int *serial) { if (ctx) { t->tv_sec = ctx->ctime.tv_sec; -- cgit v0.10.2 From c7fcb0ee74ef4cfdea02befacb55945c93641e44 Mon Sep 17 00:00:00 2001 From: Peter Martuccelli Date: Fri, 29 Apr 2005 16:10:24 +0100 Subject: [AUDIT] Avoid using %*.*s format strings. They don't seem to work correctly (investigation ongoing), but we don't actually need to do it anyway. Patch from Peter Martuccelli Signed-off-by: David Woodhouse diff --git a/kernel/audit.c b/kernel/audit.c index aa35422..42ce282 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -540,8 +540,8 @@ static inline int audit_log_drain(struct audit_buffer *ab) if (!audit_pid) { /* No daemon */ int offset = ab->nlh ? NLMSG_SPACE(0) : 0; int len = skb->len - offset; - printk(KERN_ERR "%*.*s\n", - len, len, skb->data + offset); + skb->data[offset + len] = '\0'; + printk(KERN_ERR "%s\n", skb->data + offset); } kfree_skb(skb); ab->nlh = NULL; -- cgit v0.10.2 From 3ac3ed555bec5b1f92bb22cb94823a0e99d0f320 Mon Sep 17 00:00:00 2001 From: Amy Griffis Date: Fri, 29 Apr 2005 16:12:55 +0100 Subject: [PATCH] fix ia64 syscall auditing Attached is a patch against David's audit.17 kernel that adds checks for the TIF_SYSCALL_AUDIT thread flag to the ia64 system call and signal handling code paths.The patch enables auditing of system calls set up via fsys_bubble_down, as well as ensuring that audit_syscall_exit() is called on return from sigreturn. Neglecting to check for TIF_SYSCALL_AUDIT at these points results in incorrect information in audit_context, causing frequent system panics when system call auditing is enabled on an ia64 system. Signed-off-by: Amy Griffis Signed-off-by: David Woodhouse diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S index 0d8650f..4f3cdef 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S @@ -611,8 +611,10 @@ GLOBAL_ENTRY(fsys_bubble_down) movl r2=ia64_ret_from_syscall ;; mov rp=r2 // set the real return addr - tbit.z p8,p0=r3,TIF_SYSCALL_TRACE + and r3=_TIF_SYSCALL_TRACEAUDIT,r3 ;; + cmp.eq p8,p0=r3,r0 + (p10) br.cond.spnt.many ia64_ret_from_syscall // p10==true means out registers are more than 8 (p8) br.call.sptk.many b6=b6 // ignore this return addr br.cond.sptk ia64_trace_syscall diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 6891d86..6455574 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -224,7 +224,8 @@ ia64_rt_sigreturn (struct sigscratch *scr) * could be corrupted. */ retval = (long) &ia64_leave_kernel; - if (test_thread_flag(TIF_SYSCALL_TRACE)) + if (test_thread_flag(TIF_SYSCALL_TRACE) + || test_thread_flag(TIF_SYSCALL_AUDIT)) /* * strace expects to be notified after sigreturn returns even though the * context to which we return may not be in the middle of a syscall. -- cgit v0.10.2 From 67eb81e1686f44bcf8f005b296213fd2c21b4719 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Fri, 29 Apr 2005 16:13:35 +0100 Subject: mips: warning fix audit_arch() arch/mips/kernel/ptrace.c:305: warning: function declaration isn't a prototype Signed-off-by: Yoichi Yuasa Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index eaf7be9..4abc2ee5 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -300,7 +300,7 @@ out: return ret; } -static inline int audit_arch() +static inline int audit_arch(void) { #ifdef CONFIG_CPU_LITTLE_ENDIAN #ifdef CONFIG_MIPS64 -- cgit v0.10.2 From 85c8721ff3bc96b702427a440616079e8daf8a2f Mon Sep 17 00:00:00 2001 From: Date: Fri, 29 Apr 2005 16:23:29 +0100 Subject: audit: update pointer to userspace tools, remove emacs mode tags diff --git a/include/linux/audit.h b/include/linux/audit.h index 0467f24..5fabe84 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -1,4 +1,4 @@ -/* audit.h -- Auditing support -*- linux-c -*- +/* audit.h -- Auditing support * * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. diff --git a/kernel/audit.c b/kernel/audit.c index 42ce282..58c7d7e 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1,4 +1,4 @@ -/* audit.c -- Auditing support -*- linux-c -*- +/* audit.c -- Auditing support * Gateway between the kernel (e.g., selinux) and the user-space audit daemon. * System-call specific features have moved to auditsc.c * @@ -38,7 +38,7 @@ * 6) Support low-overhead kernel-based filtering to minimize the * information that must be passed to user-space. * - * Example user-space utilities: http://people.redhat.com/faith/audit/ + * Example user-space utilities: http://people.redhat.com/sgrubb/audit/ */ #include diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 49ecd70..9ff2c1b 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1,4 +1,4 @@ -/* auditsc.c -- System-call auditing support -*- linux-c -*- +/* auditsc.c -- System-call auditing support * Handles all system-call specific auditing features. * * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. -- cgit v0.10.2 From c94c257c88c517f251da273a15c654224c7b6e21 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Fri, 29 Apr 2005 16:27:17 +0100 Subject: Add audit uid to netlink credentials Most audit control messages are sent over netlink.In order to properly log the identity of the sender of audit control messages, we would like to add the loginuid to the netlink_creds structure, as per the attached patch. Signed-off-by: Serge Hallyn Signed-off-by: David Woodhouse diff --git a/include/linux/audit.h b/include/linux/audit.h index 5fabe84..19f2142 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -184,7 +184,7 @@ extern void audit_inode(const char *name, const struct inode *inode); /* Private API (for audit.c only) */ extern int audit_receive_filter(int type, int pid, int uid, int seq, - void *data); + void *data, uid_t loginuid); extern void audit_get_stamp(struct audit_context *ctx, struct timespec *t, unsigned int *serial); extern int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid); diff --git a/include/linux/netlink.h b/include/linux/netlink.h index f731abd..b2738ac 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -110,6 +110,7 @@ struct netlink_skb_parms __u32 dst_pid; __u32 dst_groups; kernel_cap_t eff_cap; + __u32 loginuid; /* Login (audit) uid */ }; #define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) diff --git a/kernel/audit.c b/kernel/audit.c index 58c7d7e..587d3b2 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -239,36 +239,36 @@ void audit_log_lost(const char *message) } -static int audit_set_rate_limit(int limit) +static int audit_set_rate_limit(int limit, uid_t loginuid) { int old = audit_rate_limit; audit_rate_limit = limit; - audit_log(current->audit_context, "audit_rate_limit=%d old=%d", - audit_rate_limit, old); + audit_log(NULL, "audit_rate_limit=%d old=%d by auid %u", + audit_rate_limit, old, loginuid); return old; } -static int audit_set_backlog_limit(int limit) +static int audit_set_backlog_limit(int limit, uid_t loginuid) { int old = audit_backlog_limit; audit_backlog_limit = limit; - audit_log(current->audit_context, "audit_backlog_limit=%d old=%d", - audit_backlog_limit, old); + audit_log(NULL, "audit_backlog_limit=%d old=%d by auid %u", + audit_backlog_limit, old, loginuid); return old; } -static int audit_set_enabled(int state) +static int audit_set_enabled(int state, uid_t loginuid) { int old = audit_enabled; if (state != 0 && state != 1) return -EINVAL; audit_enabled = state; - audit_log(current->audit_context, "audit_enabled=%d old=%d", - audit_enabled, old); + audit_log(NULL, "audit_enabled=%d old=%d by auid %u", + audit_enabled, old, loginuid); return old; } -static int audit_set_failure(int state) +static int audit_set_failure(int state, uid_t loginuid) { int old = audit_failure; if (state != AUDIT_FAIL_SILENT @@ -276,8 +276,8 @@ static int audit_set_failure(int state) && state != AUDIT_FAIL_PANIC) return -EINVAL; audit_failure = state; - audit_log(current->audit_context, "audit_failure=%d old=%d", - audit_failure, old); + audit_log(NULL, "audit_failure=%d old=%d by auid %u", + audit_failure, old, loginuid); return old; } @@ -344,6 +344,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) int err; struct audit_buffer *ab; u16 msg_type = nlh->nlmsg_type; + uid_t loginuid; /* loginuid of sender */ err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); if (err) @@ -351,6 +352,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) pid = NETLINK_CREDS(skb)->pid; uid = NETLINK_CREDS(skb)->uid; + loginuid = NETLINK_CB(skb).loginuid; seq = nlh->nlmsg_seq; data = NLMSG_DATA(nlh); @@ -371,34 +373,36 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return -EINVAL; status_get = (struct audit_status *)data; if (status_get->mask & AUDIT_STATUS_ENABLED) { - err = audit_set_enabled(status_get->enabled); + err = audit_set_enabled(status_get->enabled, loginuid); if (err < 0) return err; } if (status_get->mask & AUDIT_STATUS_FAILURE) { - err = audit_set_failure(status_get->failure); + err = audit_set_failure(status_get->failure, loginuid); if (err < 0) return err; } if (status_get->mask & AUDIT_STATUS_PID) { int old = audit_pid; audit_pid = status_get->pid; - audit_log(current->audit_context, - "audit_pid=%d old=%d", audit_pid, old); + audit_log(NULL, "audit_pid=%d old=%d by auid %u", + audit_pid, old, loginuid); } if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) - audit_set_rate_limit(status_get->rate_limit); + audit_set_rate_limit(status_get->rate_limit, loginuid); if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT) - audit_set_backlog_limit(status_get->backlog_limit); + audit_set_backlog_limit(status_get->backlog_limit, + loginuid); break; case AUDIT_USER: ab = audit_log_start(NULL); if (!ab) break; /* audit_panic has been called */ audit_log_format(ab, - "user pid=%d uid=%d length=%d msg='%.1024s'", + "user pid=%d uid=%d length=%d loginuid=%u" + " msg='%.1024s'", pid, uid, (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh)), - (char *)data); + loginuid, (char *)data); ab->type = AUDIT_USER; ab->pid = pid; audit_log_end(ab); @@ -411,7 +415,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case AUDIT_LIST: #ifdef CONFIG_AUDITSYSCALL err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, - uid, seq, data); + uid, seq, data, loginuid); #else err = -EOPNOTSUPP; #endif diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 9ff2c1b..66148f8 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -251,7 +251,8 @@ static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) return 0; } -int audit_receive_filter(int type, int pid, int uid, int seq, void *data) +int audit_receive_filter(int type, int pid, int uid, int seq, void *data, + uid_t loginuid) { u32 flags; struct audit_entry *entry; @@ -286,6 +287,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data) err = audit_add_rule(entry, &audit_entlist); if (!err && (flags & AUDIT_AT_EXIT)) err = audit_add_rule(entry, &audit_extlist); + audit_log(NULL, "auid %u added an audit rule\n", loginuid); break; case AUDIT_DEL: flags =((struct audit_rule *)data)->flags; @@ -295,6 +297,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data) err = audit_del_rule(data, &audit_entlist); if (!err && (flags & AUDIT_AT_EXIT)) err = audit_del_rule(data, &audit_extlist); + audit_log(NULL, "auid %u removed an audit rule\n", loginuid); break; default: return -EINVAL; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 29a5fd2..cb64cff 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -905,6 +905,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, NETLINK_CB(skb).groups = nlk->groups; NETLINK_CB(skb).dst_pid = dst_pid; NETLINK_CB(skb).dst_groups = dst_groups; + NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context); memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); /* What can I do? Netlink is asynchronous, so that -- cgit v0.10.2 From 37509e749dc2072e667db806ef24b9e897f61b8a Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Fri, 29 Apr 2005 17:19:14 +0100 Subject: [AUDIT] Requeue messages at head of queue, up to audit_backlog If netlink_unicast() fails, requeue the skb back at the head of the queue it just came from, instead of the tail. And do so unless we've exceeded the audit_backlog limit; not according to some other arbitrary limit. From: Chris Wright Signed-off-by: David Woodhouse diff --git a/kernel/audit.c b/kernel/audit.c index 587d3b2..4a697c7 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -142,7 +142,6 @@ struct audit_buffer { int total; int type; int pid; - int count; /* Times requeued */ }; void audit_set_type(struct audit_buffer *ab, int type) @@ -526,9 +525,9 @@ static inline int audit_log_drain(struct audit_buffer *ab) retval = netlink_unicast(audit_sock, skb, audit_pid, MSG_DONTWAIT); } - if (retval == -EAGAIN && ab->count < 5) { - ++ab->count; - skb_queue_tail(&ab->sklist, skb); + if (retval == -EAGAIN && + (atomic_read(&audit_backlog)) < audit_backlog_limit) { + skb_queue_head(&ab->sklist, skb); audit_log_end_irq(ab); return 1; } @@ -666,7 +665,6 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx) ab->total = 0; ab->type = AUDIT_KERNEL; ab->pid = 0; - ab->count = 0; #ifdef CONFIG_AUDITSYSCALL if (ab->ctx) -- cgit v0.10.2 From 456be6cd90dbbb9b0ea01d56932d56d110d51cf7 Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Fri, 29 Apr 2005 17:30:07 +0100 Subject: [AUDIT] LOGIN message credentials Attached is a new patch that solves the issue of getting valid credentials into the LOGIN message. The current code was assuming that the audit context had already been copied. This is not always the case for LOGIN messages. To solve the problem, the patch passes the task struct to the function that emits the message where it can get valid credentials. Signed-off-by: Steve Grubb Signed-off-by: David Woodhouse diff --git a/fs/proc/base.c b/fs/proc/base.c index 39fd336..57554bf 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -820,7 +820,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, goto out_free_page; } - length = audit_set_loginuid(task->audit_context, loginuid); + length = audit_set_loginuid(task, loginuid); if (likely(length == 0)) length = count; diff --git a/include/linux/audit.h b/include/linux/audit.h index 19f2142..19f04b0 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -187,7 +187,7 @@ extern int audit_receive_filter(int type, int pid, int uid, int seq, void *data, uid_t loginuid); extern void audit_get_stamp(struct audit_context *ctx, struct timespec *t, unsigned int *serial); -extern int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid); +extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); extern uid_t audit_get_loginuid(struct audit_context *ctx); extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); #else diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 66148f8..37b3ac9 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1010,20 +1010,21 @@ void audit_get_stamp(struct audit_context *ctx, extern int audit_set_type(struct audit_buffer *ab, int type); -int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid) +int audit_set_loginuid(struct task_struct *task, uid_t loginuid) { - if (ctx) { + if (task->audit_context) { struct audit_buffer *ab; ab = audit_log_start(NULL); if (ab) { audit_log_format(ab, "login pid=%d uid=%u " "old loginuid=%u new loginuid=%u", - ctx->pid, ctx->uid, ctx->loginuid, loginuid); + task->pid, task->uid, + task->audit_context->loginuid, loginuid); audit_set_type(ab, AUDIT_LOGIN); audit_log_end(ab); } - ctx->loginuid = loginuid; + task->audit_context->loginuid = loginuid; } return 0; } -- cgit v0.10.2 From c06fec5022ebe014af876da2df4a0eee836e97c8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 29 Apr 2005 09:37:07 -0700 Subject: Remove bogus BUG() in kernel/exit.c It's old sanity checking that may have been useful for debugging, but is just bogus these days. Noticed by Mattia Belletti. diff --git a/kernel/exit.c b/kernel/exit.c index 39d35935..93851bc 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -517,8 +517,6 @@ static inline void choose_new_parent(task_t *p, task_t *reaper, task_t *child_re */ BUG_ON(p == reaper || reaper->exit_state >= EXIT_ZOMBIE); p->real_parent = reaper; - if (p->parent == p->real_parent) - BUG(); } static inline void reparent_thread(task_t *p, task_t *father, int traced) -- cgit v0.10.2 From a879cbbb34cbecfa9707fbb6e5a00c503ac1ecb9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 29 Apr 2005 09:38:44 -0700 Subject: x86: make traps on 'iret' be debuggable in user space This makes a trap on the 'iret' that returns us to user space cause a nice clean SIGSEGV, instead of just a hard (and silent) exit. That way a debugger can actually try to see what happened, and we also properly notify everybody who might be interested about us being gone. This loses the error code, but tells the debugger what happened with ILL_BADSTK in the siginfo. diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 3c73dc8..fe1918c 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -260,11 +260,9 @@ restore_nocheck: .section .fixup,"ax" iret_exc: sti - movl $__USER_DS, %edx - movl %edx, %ds - movl %edx, %es - movl $11,%eax - call do_exit + pushl $0 # no error code + pushl $do_iret_error + jmp error_code .previous .section __ex_table,"a" .align 4 diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 6c0e383..d708194 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -451,6 +451,7 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) DO_ERROR(12, SIGBUS, "stack segment", stack_segment) DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) +DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0) fastcall void do_general_protection(struct pt_regs * regs, long error_code) { -- cgit v0.10.2 From 8443b165f13d21214e5d5495eee7c3bf7f2456bf Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 29 Apr 2005 21:58:15 +0100 Subject: [PATCH] ARM: 2657/1: export ixp2000_pci_config_addr Patch from Lennert Buytenhek Export ixp2000_pci_config_addr, to be used by the IXDP2800 platform setup code to coordinate booting the master and slave NPU. Signed-off-by: Lennert Buytenhek Signed-off-by: Deepak Saxena Signed-off-by: Russell King diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c index 831f8ff..36c9a94 100644 --- a/arch/arm/mach-ixp2000/pci.c +++ b/arch/arm/mach-ixp2000/pci.c @@ -37,7 +37,7 @@ static int pci_master_aborts = 0; static int clear_master_aborts(void); -static u32 * +u32 * ixp2000_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where) { u32 *paddress; diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h index 509e44d..901bba6 100644 --- a/include/asm-arm/arch-ixp2000/platform.h +++ b/include/asm-arm/arch-ixp2000/platform.h @@ -121,6 +121,7 @@ unsigned long ixp2000_gettimeoffset(void); struct pci_sys_data; +u32 *ixp2000_pci_config_addr(unsigned int bus, unsigned int devfn, int where); void ixp2000_pci_preinit(void); int ixp2000_pci_setup(int, struct pci_sys_data*); struct pci_bus* ixp2000_pci_scan_bus(int, struct pci_sys_data*); -- cgit v0.10.2 From ae36bf5861e1091dd337f0b475e043ab07d4a937 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 29 Apr 2005 21:58:15 +0100 Subject: [PATCH] ARM: 2658/1: start ixp2000 pci memory resource at 0xe0000000 Patch from Lennert Buytenhek On the IXDP2800, the bootloader does an awful job of configuring the PCI bus, so we make linux reconfigure everything. Having a 1:1 pci:phys address mapping generally simplifies everything, so try to allocate PCI addresses from the [e0000000..ffffffff] range, which is the physical address range of the outbound PCI window on the IXP2000. This does not affect any of the other IXP2000 platforms since they all use their bootloader's PCI resource assignment. Signed-off-by: Lennert Buytenhek Signed-off-by: Deepak Saxena Signed-off-by: Russell King diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c index 36c9a94..3844d5c 100644 --- a/arch/arm/mach-ixp2000/pci.c +++ b/arch/arm/mach-ixp2000/pci.c @@ -208,7 +208,7 @@ ixp2000_pci_preinit(void) * use our own resource space. */ static struct resource ixp2000_pci_mem_space = { - .start = 0x00000000, + .start = 0xe0000000, .end = 0xffffffff, .flags = IORESOURCE_MEM, .name = "PCI Mem Space" -- cgit v0.10.2 From 458a83fa43e83505f9401783ce9ed41b5a8b5591 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 29 Apr 2005 21:58:16 +0100 Subject: [PATCH] ARM: 2659/1: do not assign PCI I/O address zero on IXP2000 Patch from Lennert Buytenhek Assigning the address zero to a PCI device BAR causes some part of the PCI subsystem to believe that resource allocation for that BAR failed due to resource conflicts, which will make attempts to enable the device fail. Work around this by assigning I/O addresses starting from 00010000. While we're at it, make the PCI I/O resource end at 0001ffff, since we only have 64k of outbound I/O window on the IXP2000, and we don't do bank switching. Signed-off-by: Lennert Buytenhek Signed-off-by: Deepak Saxena Signed-off-by: Russell King diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c index 3844d5c..5ff2f27 100644 --- a/arch/arm/mach-ixp2000/pci.c +++ b/arch/arm/mach-ixp2000/pci.c @@ -215,8 +215,8 @@ static struct resource ixp2000_pci_mem_space = { }; static struct resource ixp2000_pci_io_space = { - .start = 0x00000000, - .end = 0xffffffff, + .start = 0x00010000, + .end = 0x0001ffff, .flags = IORESOURCE_IO, .name = "PCI I/O Space" }; -- cgit v0.10.2 From 3a1e501511a1e2c665c566939047794dcf86466b Mon Sep 17 00:00:00 2001 From: "George G. Davis" Date: Fri, 29 Apr 2005 22:08:33 +0100 Subject: [PATCH] ARM: 2655/1: ARM1136 SWP instruction abort handler fix Patch from George G. Davis As noted in http://www.arm.com/linux/patch-2.6.9-arm1.gz, the "Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR." So the v6_early_abort handler does not report the correct rd/wr direction for the SWP instruction which may result in SEGVS or hangs. In order to work around this problem, this patch merely updates the fix contained in the ARM Ltd. patch to use the macroised abort handler fixups. Signed-off-by: George G. Davis Signed-off-by: Russell King diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S index 38b2cbb..8f76f3d 100644 --- a/arch/arm/mm/abort-ev6.S +++ b/arch/arm/mm/abort-ev6.S @@ -1,5 +1,6 @@ #include #include +#include "abort-macro.S" /* * Function: v6_early_abort * @@ -13,11 +14,26 @@ * : sp = pointer to registers * * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. */ .align 5 ENTRY(v6_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR +/* + * Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR. + * The test below covers all the write situations, including Java bytecodes + */ + bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR + tst r3, #PSR_J_BIT @ Java? + movne pc, lr + do_thumb_abort + ldreq r3, [r2] @ read aborted ARM instruction + do_ldrd_abort + tst r3, #1 << 20 @ L = 0 -> write + orreq r1, r1, #1 << 11 @ yes. mov pc, lr -- cgit v0.10.2 From 2d2669b62984b8d76b05a6a045390a3250317d21 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 29 Apr 2005 22:08:33 +0100 Subject: [PATCH] ARM: 2651/3: kernel helpers for NPTL support Patch from Nicolas Pitre This patch entirely reworks the kernel assistance for NPTL on ARM. In particular this provides an efficient way to retrieve the TLS value and perform atomic operations without any instruction emulation nor special system call. This even allows for pre ARMv6 binaries to be forward compatible with SMP systems without any penalty. The problematic and performance critical operations are performed through segment of kernel provided user code reachable from user space at a fixed address in kernel memory. Those fixed entry points are within the vector page so we basically get it for free as no extra memory page is required and nothing else may be mapped at that location anyway. This is different from (but doesn't preclude) a full blown VDSO implementation, however a VDSO would prevent some assembly tricks with constants that allows for efficient branching to those code segments. And since those code segments only use a few cycles before returning to user code, the overhead of a VDSO far call would add a significant overhead to such minimalistic operations. The ARM_NR_set_tls syscall also changed number. This is done for two reasons: 1) this patch changes the way the TLS value was previously meant to be retrieved, therefore we ensure whatever library using the old way gets fixed (they only exist in private tree at the moment since the NPTL work is still progressing). 2) the previous number was allocated in a range causing an undefined instruction trap on kernels not supporting that syscall and it was determined that allocating it in a range returning -ENOSYS would be much nicer for libraries trying to determine if the feature is present or not. Signed-off-by: Nicolas Pitre Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 2a5c3fe..080df90 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -269,6 +269,12 @@ __pabt_svc: add r5, sp, #S_PC ldmia r7, {r2 - r4} @ Get USR pc, cpsr +#if __LINUX_ARM_ARCH__ < 6 + @ make sure our user space atomic helper is aborted + cmp r2, #VIRT_OFFSET + bichs r3, r3, #PSR_Z_BIT +#endif + @ @ We are now ready to fill in the remaining blanks on the stack: @ @@ -499,8 +505,12 @@ ENTRY(__switch_to) mra r4, r5, acc0 stmia ip, {r4, r5} #endif +#ifdef CONFIG_HAS_TLS_REG + mcr p15, 0, r3, c13, c0, 3 @ set TLS register +#else mov r4, #0xffff0fff - str r3, [r4, #-3] @ Set TLS ptr + str r3, [r4, #-15] @ TLS val at 0xffff0ff0 +#endif mcr p15, 0, r6, c3, c0, 0 @ Set domain register #ifdef CONFIG_VFP @ Always disable VFP so we can lazily save/restore the old @@ -519,6 +529,207 @@ ENTRY(__switch_to) ldmib r2, {r4 - sl, fp, sp, pc} @ Load all regs saved previously __INIT + +/* + * User helpers. + * + * These are segment of kernel provided user code reachable from user space + * at a fixed address in kernel memory. This is used to provide user space + * with some operations which require kernel help because of unimplemented + * native feature and/or instructions in many ARM CPUs. The idea is for + * this code to be executed directly in user mode for best efficiency but + * which is too intimate with the kernel counter part to be left to user + * libraries. In fact this code might even differ from one CPU to another + * depending on the available instruction set and restrictions like on + * SMP systems. In other words, the kernel reserves the right to change + * this code as needed without warning. Only the entry points and their + * results are guaranteed to be stable. + * + * Each segment is 32-byte aligned and will be moved to the top of the high + * vector page. New segments (if ever needed) must be added in front of + * existing ones. This mechanism should be used only for things that are + * really small and justified, and not be abused freely. + * + * User space is expected to implement those things inline when optimizing + * for a processor that has the necessary native support, but only if such + * resulting binaries are already to be incompatible with earlier ARM + * processors due to the use of unsupported instructions other than what + * is provided here. In other words don't make binaries unable to run on + * earlier processors just for the sake of not using these kernel helpers + * if your compiled code is not going to use the new instructions for other + * purpose. + */ + + .align 5 + .globl __kuser_helper_start +__kuser_helper_start: + +/* + * Reference prototype: + * + * int __kernel_cmpxchg(int oldval, int newval, int *ptr) + * + * Input: + * + * r0 = oldval + * r1 = newval + * r2 = ptr + * lr = return address + * + * Output: + * + * r0 = returned value (zero or non-zero) + * C flag = set if r0 == 0, clear if r0 != 0 + * + * Clobbered: + * + * r3, ip, flags + * + * Definition and user space usage example: + * + * typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr); + * #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) + * + * Atomically store newval in *ptr if *ptr is equal to oldval for user space. + * Return zero if *ptr was changed or non-zero if no exchange happened. + * The C flag is also set if *ptr was changed to allow for assembly + * optimization in the calling code. + * + * For example, a user space atomic_add implementation could look like this: + * + * #define atomic_add(ptr, val) \ + * ({ register unsigned int *__ptr asm("r2") = (ptr); \ + * register unsigned int __result asm("r1"); \ + * asm volatile ( \ + * "1: @ atomic_add\n\t" \ + * "ldr r0, [r2]\n\t" \ + * "mov r3, #0xffff0fff\n\t" \ + * "add lr, pc, #4\n\t" \ + * "add r1, r0, %2\n\t" \ + * "add pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \ + * "bcc 1b" \ + * : "=&r" (__result) \ + * : "r" (__ptr), "rIL" (val) \ + * : "r0","r3","ip","lr","cc","memory" ); \ + * __result; }) + */ + +__kuser_cmpxchg: @ 0xffff0fc0 + +#if __LINUX_ARM_ARCH__ < 6 + +#ifdef CONFIG_SMP /* sanity check */ +#error "CONFIG_SMP on a machine supporting pre-ARMv6 processors?" +#endif + + /* + * Theory of operation: + * + * We set the Z flag before loading oldval. If ever an exception + * occurs we can not be sure the loaded value will still be the same + * when the exception returns, therefore the user exception handler + * will clear the Z flag whenever the interrupted user code was + * actually from the kernel address space (see the usr_entry macro). + * + * The post-increment on the str is used to prevent a race with an + * exception happening just after the str instruction which would + * clear the Z flag although the exchange was done. + */ + teq ip, ip @ set Z flag + ldr ip, [r2] @ load current val + add r3, r2, #1 @ prepare store ptr + teqeq ip, r0 @ compare with oldval if still allowed + streq r1, [r3, #-1]! @ store newval if still allowed + subs r0, r2, r3 @ if r2 == r3 the str occured + mov pc, lr + +#else + + ldrex r3, [r2] + subs r3, r3, r0 + strexeq r3, r1, [r2] + rsbs r0, r3, #0 + mov pc, lr + +#endif + + .align 5 + +/* + * Reference prototype: + * + * int __kernel_get_tls(void) + * + * Input: + * + * lr = return address + * + * Output: + * + * r0 = TLS value + * + * Clobbered: + * + * the Z flag might be lost + * + * Definition and user space usage example: + * + * typedef int (__kernel_get_tls_t)(void); + * #define __kernel_get_tls (*(__kernel_get_tls_t *)0xffff0fe0) + * + * Get the TLS value as previously set via the __ARM_NR_set_tls syscall. + * + * This could be used as follows: + * + * #define __kernel_get_tls() \ + * ({ register unsigned int __val asm("r0"); \ + * asm( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #31" \ + * : "=r" (__val) : : "lr","cc" ); \ + * __val; }) + */ + +__kuser_get_tls: @ 0xffff0fe0 + +#ifndef CONFIG_HAS_TLS_REG + +#ifdef CONFIG_SMP /* sanity check */ +#error "CONFIG_SMP without CONFIG_HAS_TLS_REG is wrong" +#endif + + ldr r0, [pc, #(16 - 8)] @ TLS stored at 0xffff0ff0 + mov pc, lr + +#else + + mrc p15, 0, r0, c13, c0, 3 @ read TLS register + mov pc, lr + +#endif + + .rep 5 + .word 0 @ pad up to __kuser_helper_version + .endr + +/* + * Reference declaration: + * + * extern unsigned int __kernel_helper_version; + * + * Definition and user space usage example: + * + * #define __kernel_helper_version (*(unsigned int *)0xffff0ffc) + * + * User space may read this to determine the curent number of helpers + * available. + */ + +__kuser_helper_version: @ 0xffff0ffc + .word ((__kuser_helper_end - __kuser_helper_start) >> 5) + + .globl __kuser_helper_end +__kuser_helper_end: + + /* * Vector stubs. * diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 0078aeb..3a001fe 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -450,13 +450,17 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) case NR(set_tls): thread->tp_value = regs->ARM_r0; +#ifdef CONFIG_HAS_TLS_REG + asm ("mcr p15, 0, %0, c13, c0, 3" : : "r" (regs->ARM_r0) ); +#else /* - * Our user accessible TLS ptr is located at 0xffff0ffc. - * On SMP read access to this address must raise a fault - * and be emulated from the data abort handler. - * m + * User space must never try to access this directly. + * Expect your app to break eventually if you do so. + * The user helper at 0xffff0fe0 must be used instead. + * (see entry-armv.S for details) */ - *((unsigned long *)0xffff0ffc) = thread->tp_value; + *((unsigned int *)0xffff0ff0) = regs->ARM_r0; +#endif return 0; default: @@ -493,6 +497,41 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) return 0; } +#if defined(CONFIG_CPU_32v6) && !defined(CONFIG_HAS_TLS_REG) + +/* + * We might be running on an ARMv6+ processor which should have the TLS + * register, but for some reason we can't use it and have to emulate it. + */ + +static int get_tp_trap(struct pt_regs *regs, unsigned int instr) +{ + int reg = (instr >> 12) & 15; + if (reg == 15) + return 1; + regs->uregs[reg] = current_thread_info()->tp_value; + regs->ARM_pc += 4; + return 0; +} + +static struct undef_hook arm_mrc_hook = { + .instr_mask = 0x0fff0fff, + .instr_val = 0x0e1d0f70, + .cpsr_mask = PSR_T_BIT, + .cpsr_val = 0, + .fn = get_tp_trap, +}; + +static int __init arm_mrc_hook_init(void) +{ + register_undef_hook(&arm_mrc_hook); + return 0; +} + +late_initcall(arm_mrc_hook_init); + +#endif + void __bad_xchg(volatile void *ptr, int size) { printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n", @@ -580,14 +619,17 @@ void __init trap_init(void) { extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; + extern char __kuser_helper_start[], __kuser_helper_end[]; + int kuser_sz = __kuser_helper_end - __kuser_helper_start; /* - * Copy the vectors and stubs (in entry-armv.S) into the - * vector page, mapped at 0xffff0000, and ensure these are - * visible to the instruction stream. + * Copy the vectors, stubs and kuser helpers (in entry-armv.S) + * into the vector page, mapped at 0xffff0000, and ensure these + * are visible to the instruction stream. */ memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start); memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start); + memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz); flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); } diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 5b670c9..007766a 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -409,3 +409,17 @@ config CPU_BPREDICT_DISABLE depends on CPU_ARM1020 help Say Y here to disable branch prediction. If unsure, say N. + +config HAS_TLS_REG + bool + depends on CPU_32v6 && !CPU_32v5 && !CPU_32v4 && !CPU_32v3 + help + This selects support for the CP15 thread register. + It is defined to be available on ARMv6 or later. However + if the kernel is configured to support multiple CPUs including + a pre-ARMv6 processors, or if a given ARMv6 processor doesn't + implement the thread register for some reason, then access to + this register from user space must be trapped and emulated. + If user space is relying on the __kuser_get_tls code then + there should not be any impact. + diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index a19ec09..ace2748 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -359,8 +359,7 @@ #define __ARM_NR_cacheflush (__ARM_NR_BASE+2) #define __ARM_NR_usr26 (__ARM_NR_BASE+3) #define __ARM_NR_usr32 (__ARM_NR_BASE+4) - -#define __ARM_NR_set_tls (__ARM_NR_BASE+0x800) +#define __ARM_NR_set_tls (__ARM_NR_BASE+5) #define __sys2(x) #x #define __sys1(x) __sys2(x) -- cgit v0.10.2 From 05f9869bf20e11bcb9b64b9ebd6a9cf89d6b71ba Mon Sep 17 00:00:00 2001 From: Olav Kongas Date: Fri, 29 Apr 2005 22:08:34 +0100 Subject: [PATCH] ARM: 2649/1: Fix 'sparse -Wbitwise' warnings from MMIO macros Patch from Olav Kongas On ARM, the outX() and writeX() families of macros take the result of cpu_to_leYY(), which is of restricted type __leYY, and feed it to __raw_writeX(), which expect an argument of unrestricted type. This results in 'sparse -Wbitwise' warnings about incorrect types in assignments. Analogous type mismatch warnings are issued for inX() and readX() counterparts. The below patch resolves these warnings by adding forced typecasts. Signed-off-by: Olav Kongas Signed-off-by: Russell King diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h index 69bc7a3..658ffa3 100644 --- a/include/asm-arm/io.h +++ b/include/asm-arm/io.h @@ -99,12 +99,16 @@ extern void __readwrite_bug(const char *fn); */ #ifdef __io #define outb(v,p) __raw_writeb(v,__io(p)) -#define outw(v,p) __raw_writew(cpu_to_le16(v),__io(p)) -#define outl(v,p) __raw_writel(cpu_to_le32(v),__io(p)) +#define outw(v,p) __raw_writew((__force __u16) \ + cpu_to_le16(v),__io(p)) +#define outl(v,p) __raw_writel((__force __u32) \ + cpu_to_le32(v),__io(p)) -#define inb(p) ({ unsigned int __v = __raw_readb(__io(p)); __v; }) -#define inw(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; }) -#define inl(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; }) +#define inb(p) ({ __u8 __v = __raw_readb(__io(p)); __v; }) +#define inw(p) ({ __u16 __v = le16_to_cpu((__force __le16) \ + __raw_readw(__io(p))); __v; }) +#define inl(p) ({ __u32 __v = le32_to_cpu((__force __le32) \ + __raw_readl(__io(p))); __v; }) #define outsb(p,d,l) __raw_writesb(__io(p),d,l) #define outsw(p,d,l) __raw_writesw(__io(p),d,l) @@ -149,9 +153,11 @@ extern void _memset_io(void __iomem *, int, size_t); * IO port primitives for more information. */ #ifdef __mem_pci -#define readb(c) ({ unsigned int __v = __raw_readb(__mem_pci(c)); __v; }) -#define readw(c) ({ unsigned int __v = le16_to_cpu(__raw_readw(__mem_pci(c))); __v; }) -#define readl(c) ({ unsigned int __v = le32_to_cpu(__raw_readl(__mem_pci(c))); __v; }) +#define readb(c) ({ __u8 __v = __raw_readb(__mem_pci(c)); __v; }) +#define readw(c) ({ __u16 __v = le16_to_cpu((__force __le16) \ + __raw_readw(__mem_pci(c))); __v; }) +#define readl(c) ({ __u32 __v = le32_to_cpu((__force __le32) \ + __raw_readl(__mem_pci(c))); __v; }) #define readb_relaxed(addr) readb(addr) #define readw_relaxed(addr) readw(addr) #define readl_relaxed(addr) readl(addr) @@ -161,8 +167,10 @@ extern void _memset_io(void __iomem *, int, size_t); #define readsl(p,d,l) __raw_readsl(__mem_pci(p),d,l) #define writeb(v,c) __raw_writeb(v,__mem_pci(c)) -#define writew(v,c) __raw_writew(cpu_to_le16(v),__mem_pci(c)) -#define writel(v,c) __raw_writel(cpu_to_le32(v),__mem_pci(c)) +#define writew(v,c) __raw_writew((__force __u16) \ + cpu_to_le16(v),__mem_pci(c)) +#define writel(v,c) __raw_writel((__force __u32) \ + cpu_to_le32(v),__mem_pci(c)) #define writesb(p,d,l) __raw_writesb(__mem_pci(p),d,l) #define writesw(p,d,l) __raw_writesw(__mem_pci(p),d,l) -- cgit v0.10.2 From ca315159dfa80a2bfc7d917a717a7ee8d771bdf9 Mon Sep 17 00:00:00 2001 From: "George G. Davis" Date: Fri, 29 Apr 2005 22:08:35 +0100 Subject: [PATCH] ARM: 2656/1: Access permission bits are wrong for kernel XIP sections on ARMv6 Patch from George G. Davis This patch is required for kernel XIP support on ARMv6 machines. It ensures that the access permission bits for kernel XIP section descriptors are APX=1 and AP[1:0]=01, which is Kernel read-only/User no access permissions. Prior to this change, kernel XIP section descriptor access permissions were set to Kernel no access/User no access on ARMv6 machines and the kernel would therefore hang upon entry to userspace when set_fs(USER_DS) was executed. Signed-off-by: Steve Longerbeam Signed-off-by: George G. Davis Signed-off-by: Russell King diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index f5a87db8..585dfb8 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -411,9 +411,10 @@ static void __init build_mem_type_table(void) mem_types[MT_MEMORY].prot_sect &= ~PMD_BIT4; mem_types[MT_ROM].prot_sect &= ~PMD_BIT4; /* - * Mark cache clean areas read only from SVC mode - * and no access from userspace. + * Mark cache clean areas and XIP ROM read only + * from SVC mode and no access from userspace. */ + mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; } -- cgit v0.10.2 From 53e173f62c318e65e6ae13524b04c5cf38c1bc3c Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 29 Apr 2005 22:13:57 +0100 Subject: [PATCH] ARM: 2660/2: fix ixdp2800 boot and pci init Patch from Lennert Buytenhek The IXDP2800 is an evalution platform for the IXP2800 processor that has two IXP2800s connected to the same PCI bus. This is problematic as both CPUs will try to configure the PCI bus as they boot linux. Contrary to on the other IXP2000 platforms, the boot loader on the IXDP2800 doesn't configure the PCI bus properly, so we do want the linux instance on one of the CPUs to do that. Making one of the CPUs ignore the PCI bus (and thus act like a pure PCI slave device) is not an option because there is a 82559 NIC on the PCI bus for each of the CPUs. The chosen solution is to have the master CPU configure the PCI bus while the slave is kept in a quiescent state, and then to have the slave CPU scan the PCI bus (without assigning resources) while the master is kept in a quiescent state. After this ritual, the master deletes the slave NIC from its PCI device list, the slave deletes the master NIC from its device list, and (almost) all is well. There's still one little problem: each of the CPUs has a 1G SDRAM BAR, but the IXP2000 only has 512M of outbound PCI memory window. We solve this by hand-assigning the master and slave SDRAM BARs to a location outside each of the IXP's outbound PCI windows, and by having the rest of the BARs autoconfigured in the outbound PCI windows, in the range [e0000000..ffffffff], so that there is a 1:1 pci:phys mapping between them. Even with this patch, a number of issues still remain -- just imagine what happens if one of the CPUs is rebooted, by watchdog or by hand, but the other one isn't. But those issues are not easily fixable given the strange PCI layout of this board and the behavior of the boot loader shipped with the platform. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig index d36f991..7be3521 100644 --- a/arch/arm/configs/ixdp2800_defconfig +++ b/arch/arm/configs/ixdp2800_defconfig @@ -133,7 +133,7 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware" +CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/nfs ip=bootp mem=64M@0x0" # CONFIG_XIP_KERNEL is not set # diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c index c4683aa..aec13c7 100644 --- a/arch/arm/mach-ixp2000/ixdp2800.c +++ b/arch/arm/mach-ixp2000/ixdp2800.c @@ -65,19 +65,102 @@ static struct sys_timer ixdp2800_timer = { /************************************************************************* * IXDP2800 PCI *************************************************************************/ +static void __init ixdp2800_slave_disable_pci_master(void) +{ + *IXP2000_PCI_CMDSTAT &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); +} + +static void __init ixdp2800_master_wait_for_slave(void) +{ + volatile u32 *addr; + + printk(KERN_INFO "IXDP2800: waiting for slave NPU to configure " + "its BAR sizes\n"); + + addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN, + PCI_BASE_ADDRESS_1); + do { + *addr = 0xffffffff; + cpu_relax(); + } while (*addr != 0xfe000008); + + addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN, + PCI_BASE_ADDRESS_2); + do { + *addr = 0xffffffff; + cpu_relax(); + } while (*addr != 0xc0000008); + + /* + * Configure the slave's SDRAM BAR by hand. + */ + *addr = 0x40000008; +} + +static void __init ixdp2800_slave_wait_for_master_enable(void) +{ + printk(KERN_INFO "IXDP2800: waiting for master NPU to enable us\n"); + + while ((*IXP2000_PCI_CMDSTAT & PCI_COMMAND_MASTER) == 0) + cpu_relax(); +} + void __init ixdp2800_pci_preinit(void) { printk("ixdp2x00_pci_preinit called\n"); - *IXP2000_PCI_ADDR_EXT = 0x0000e000; + *IXP2000_PCI_ADDR_EXT = 0x0001e000; + + if (!ixdp2x00_master_npu()) + ixdp2800_slave_disable_pci_master(); - *IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff; *IXP2000_PCI_SRAM_BASE_ADDR_MASK = (0x2000000 - 1) & ~0x3ffff; + *IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff; ixp2000_pci_preinit(); + + if (ixdp2x00_master_npu()) { + /* + * Wait until the slave set its SRAM/SDRAM BAR sizes + * correctly before we proceed to scan and enumerate + * the bus. + */ + ixdp2800_master_wait_for_slave(); + + /* + * We configure the SDRAM BARs by hand because they + * are 1G and fall outside of the regular allocated + * PCI address space. + */ + *IXP2000_PCI_SDRAM_BAR = 0x00000008; + } else { + /* + * Wait for the master to complete scanning the bus + * and assigning resources before we proceed to scan + * the bus ourselves. Set pci=firmware to honor the + * master's resource assignment. + */ + ixdp2800_slave_wait_for_master_enable(); + pcibios_setup("firmware"); + } } -int ixdp2800_pci_setup(int nr, struct pci_sys_data *sys) +/* + * We assign the SDRAM BARs for the two IXP2800 CPUs by hand, outside + * of the regular PCI window, because there's only 512M of outbound PCI + * memory window on each IXP, while we need 1G for each of the BARs. + */ +static void __devinit ixp2800_pci_fixup(struct pci_dev *dev) +{ + if (machine_is_ixdp2800()) { + dev->resource[2].start = 0; + dev->resource[2].end = 0; + dev->resource[2].flags = 0; + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IXP2800, ixp2800_pci_fixup); + +static int __init ixdp2800_pci_setup(int nr, struct pci_sys_data *sys) { sys->mem_offset = 0x00000000; @@ -129,22 +212,47 @@ static int __init ixdp2800_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */ } -static void ixdp2800_pci_postinit(void) +static void __init ixdp2800_master_enable_slave(void) { - struct pci_dev *dev; + volatile u32 *addr; - if (ixdp2x00_master_npu()) { - dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN); - pci_remove_bus_device(dev); - } else { - dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN); - pci_remove_bus_device(dev); + printk(KERN_INFO "IXDP2800: enabling slave NPU\n"); + + addr = (volatile u32 *)ixp2000_pci_config_addr(0, + IXDP2X00_SLAVE_NPU_DEVFN, + PCI_COMMAND); + + *addr |= PCI_COMMAND_MASTER; +} +static void __init ixdp2800_master_wait_for_slave_bus_scan(void) +{ + volatile u32 *addr; + + printk(KERN_INFO "IXDP2800: waiting for slave to finish bus scan\n"); + + addr = (volatile u32 *)ixp2000_pci_config_addr(0, + IXDP2X00_SLAVE_NPU_DEVFN, + PCI_COMMAND); + while ((*addr & PCI_COMMAND_MEMORY) == 0) + cpu_relax(); +} + +static void __init ixdp2800_slave_signal_bus_scan_completion(void) +{ + printk(KERN_INFO "IXDP2800: bus scan done, signaling master\n"); + *IXP2000_PCI_CMDSTAT |= PCI_COMMAND_MEMORY; +} + +static void __init ixdp2800_pci_postinit(void) +{ + if (!ixdp2x00_master_npu()) { ixdp2x00_slave_pci_postinit(); + ixdp2800_slave_signal_bus_scan_completion(); } } -struct hw_pci ixdp2800_pci __initdata = { +struct __initdata hw_pci ixdp2800_pci __initdata = { .nr_controllers = 1, .setup = ixdp2800_pci_setup, .preinit = ixdp2800_pci_preinit, @@ -155,8 +263,21 @@ struct hw_pci ixdp2800_pci __initdata = { int __init ixdp2800_pci_init(void) { - if (machine_is_ixdp2800()) + if (machine_is_ixdp2800()) { + struct pci_dev *dev; + pci_common_init(&ixdp2800_pci); + if (ixdp2x00_master_npu()) { + dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN); + pci_remove_bus_device(dev); + + ixdp2800_master_enable_slave(); + ixdp2800_master_wait_for_slave_bus_scan(); + } else { + dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN); + pci_remove_bus_device(dev); + } + } return 0; } -- cgit v0.10.2 From 587897f51fac04988de497a553215fdf41e6d5f6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 29 Apr 2005 22:46:40 +0100 Subject: [PATCH] ARM: 2654/1: i.MX UART initialization sets and honors UFCR value Patch from Sascha Hauer This patch adds UCFR_RFDIV setting into i.MX serial driver. This is required, if loader does not fully agree with Linux kernel about UART setup manner. Linux only blindly expected some values until now. This should enable to use even serial ports not recognized by boot-loader as for example third UART found in the bluethoot module. Patch also enables to detect original setup baudrate in more cases. Signed-off-by: Pavel Pisa Signed-off-by: Sascha Hauer Signed-off-by: Russell King diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index c682c63..01a8726 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -321,18 +321,39 @@ static void imx_break_ctl(struct uart_port *port, int break_state) #define TXTL 2 /* reset default */ #define RXTL 1 /* reset default */ +static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) +{ + unsigned int val; + unsigned int ufcr_rfdiv; + + /* set receiver / transmitter trigger level. + * RFDIV is set such way to satisfy requested uartclk value + */ + val = TXTL<<10 | RXTL; + ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk; + + if(!ufcr_rfdiv) + ufcr_rfdiv = 1; + + if(ufcr_rfdiv >= 7) + ufcr_rfdiv = 6; + else + ufcr_rfdiv = 6 - ufcr_rfdiv; + + val |= UFCR_RFDIV & (ufcr_rfdiv << 7); + + UFCR((u32)sport->port.membase) = val; + + return 0; +} + static int imx_startup(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; int retval; - unsigned int val; unsigned long flags; - /* set receiver / transmitter trigger level. We assume - * that RFDIV has been set by the arch setup or by the bootloader. - */ - val = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) | TXTL<<10 | RXTL; - UFCR((u32)sport->port.membase) = val; + imx_setup_ufcr(sport, 0); /* disable the DREN bit (Data Ready interrupt enable) before * requesting IRQs @@ -737,9 +758,12 @@ static void __init imx_console_get_options(struct imx_port *sport, int *baud, int *parity, int *bits) { + if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) { /* ok, the port was enabled */ unsigned int ucr2, ubir,ubmr, uartclk; + unsigned int baud_raw; + unsigned int ucfr_rfdiv; ucr2 = UCR2((u32)sport->port.membase); @@ -758,9 +782,35 @@ imx_console_get_options(struct imx_port *sport, int *baud, ubir = UBIR((u32)sport->port.membase) & 0xffff; ubmr = UBMR((u32)sport->port.membase) & 0xffff; - uartclk = sport->port.uartclk; - *baud = ((uartclk/16) * (ubir + 1)) / (ubmr + 1); + + ucfr_rfdiv = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) >> 7; + if (ucfr_rfdiv == 6) + ucfr_rfdiv = 7; + else + ucfr_rfdiv = 6 - ucfr_rfdiv; + + uartclk = imx_get_perclk1(); + uartclk /= ucfr_rfdiv; + + { /* + * The next code provides exact computation of + * baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1)) + * without need of float support or long long division, + * which would be required to prevent 32bit arithmetic overflow + */ + unsigned int mul = ubir + 1; + unsigned int div = 16 * (ubmr + 1); + unsigned int rem = uartclk % div; + + baud_raw = (uartclk / div) * mul; + baud_raw += (rem * mul + div / 2) / div; + *baud = (baud_raw + 50) / 100 * 100; + } + + if(*baud != baud_raw) + printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n", + baud_raw, *baud); } } @@ -787,6 +837,8 @@ imx_console_setup(struct console *co, char *options) else imx_console_get_options(sport, &baud, &parity, &bits); + imx_setup_ufcr(sport, 0); + return uart_set_options(&sport->port, co, baud, parity, bits, flow); } -- cgit v0.10.2 From 54e0f520e7d94b865e0f5465db976dcc5ffe7190 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 30 Apr 2005 07:07:04 +0100 Subject: netlink audit warning fix scumbags! net/netlink/af_netlink.c: In function `netlink_sendmsg': net/netlink/af_netlink.c:908: warning: implicit declaration of function `audit_get_loginuid' Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index cb64cff..379ed06 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -49,6 +49,8 @@ #include #include #include +#include + #include #include -- cgit v0.10.2 From d5aa207e46ff7ee838683a7d95ecf46fe42a9a56 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 30 Apr 2005 12:19:28 +0100 Subject: [PATCH] ARM: RTC: allow driver methods to return error Allow RTC drivers to return error codes from their read_time or read_alarm methods. Signed-off-by: Russell King diff --git a/arch/arm/common/rtctime.c b/arch/arm/common/rtctime.c index c397e71..72b03f2 100644 --- a/arch/arm/common/rtctime.c +++ b/arch/arm/common/rtctime.c @@ -141,10 +141,10 @@ void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc next->tm_sec = alrm->tm_sec; } -static inline void rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm) +static inline int rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm) { memset(tm, 0, sizeof(struct rtc_time)); - ops->read_time(tm); + return ops->read_time(tm); } static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm) @@ -163,8 +163,7 @@ static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) int ret = -EINVAL; if (ops->read_alarm) { memset(alrm, 0, sizeof(struct rtc_wkalrm)); - ops->read_alarm(alrm); - ret = 0; + ret = ops->read_alarm(alrm); } return ret; } @@ -283,7 +282,9 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, break; case RTC_RD_TIME: - rtc_read_time(ops, &tm); + ret = rtc_read_time(ops, &tm); + if (ret) + break; ret = copy_to_user(uarg, &tm, sizeof(tm)); if (ret) ret = -EFAULT; @@ -424,15 +425,15 @@ static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eo struct rtc_time tm; char *p = page; - rtc_read_time(ops, &tm); - - p += sprintf(p, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n" - "rtc_epoch\t: %04lu\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - rtc_epoch); + if (rtc_read_time(ops, &tm) == 0) { + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + rtc_epoch); + } if (rtc_read_alarm(ops, &alrm) == 0) { p += sprintf(p, "alrm_time\t: "); diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c index 20729de..1a844ca 100644 --- a/arch/arm/mach-integrator/time.c +++ b/arch/arm/mach-integrator/time.c @@ -40,25 +40,32 @@ static int integrator_set_rtc(void) return 1; } -static void rtc_read_alarm(struct rtc_wkalrm *alrm) +static int rtc_read_alarm(struct rtc_wkalrm *alrm) { rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time); + return 0; } -static int rtc_set_alarm(struct rtc_wkalrm *alrm) +static inline int rtc_set_alarm(struct rtc_wkalrm *alrm) { unsigned long time; int ret; - ret = rtc_tm_to_time(&alrm->time, &time); + /* + * At the moment, we can only deal with non-wildcarded alarm times. + */ + ret = rtc_valid_tm(&alrm->time); + if (ret == 0) + ret = rtc_tm_to_time(&alrm->time, &time); if (ret == 0) writel(time, rtc_base + RTC_MR); return ret; } -static void rtc_read_time(struct rtc_time *tm) +static int rtc_read_time(struct rtc_time *tm) { rtc_time_to_tm(readl(rtc_base + RTC_DR), tm); + return 0; } /* @@ -69,7 +76,7 @@ static void rtc_read_time(struct rtc_time *tm) * edge of the 1Hz clock, we must write the time one second * in advance. */ -static int rtc_set_time(struct rtc_time *tm) +static inline int rtc_set_time(struct rtc_time *tm) { unsigned long time; int ret; diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c index 8e61be3..ed867db 100644 --- a/drivers/char/s3c2410-rtc.c +++ b/drivers/char/s3c2410-rtc.c @@ -116,7 +116,7 @@ static void s3c2410_rtc_setfreq(int freq) /* Time read/write */ -static void s3c2410_rtc_gettime(struct rtc_time *rtc_tm) +static int s3c2410_rtc_gettime(struct rtc_time *rtc_tm) { unsigned int have_retried = 0; @@ -151,6 +151,8 @@ static void s3c2410_rtc_gettime(struct rtc_time *rtc_tm) rtc_tm->tm_year += 100; rtc_tm->tm_mon -= 1; + + return 0; } @@ -171,7 +173,7 @@ static int s3c2410_rtc_settime(struct rtc_time *tm) return 0; } -static void s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm) +static int s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm) { struct rtc_time *alm_tm = &alrm->time; unsigned int alm_en; @@ -231,6 +233,8 @@ static void s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm) } /* todo - set alrm->enabled ? */ + + return 0; } static int s3c2410_rtc_setalarm(struct rtc_wkalrm *alrm) diff --git a/include/asm-arm/rtc.h b/include/asm-arm/rtc.h index aa7e16b..370dfe7 100644 --- a/include/asm-arm/rtc.h +++ b/include/asm-arm/rtc.h @@ -18,9 +18,9 @@ struct rtc_ops { void (*release)(void); int (*ioctl)(unsigned int, unsigned long); - void (*read_time)(struct rtc_time *); + int (*read_time)(struct rtc_time *); int (*set_time)(struct rtc_time *); - void (*read_alarm)(struct rtc_wkalrm *); + int (*read_alarm)(struct rtc_wkalrm *); int (*set_alarm)(struct rtc_wkalrm *); int (*proc)(char *buf); }; -- cgit v0.10.2 From bb9bffcbef6166cf03385fbcde97c27bc1a5e689 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 30 Apr 2005 13:26:06 +0100 Subject: [PATCH] ARM: PXA I2C: add platform device Add the PXA I2C platform device. Signed-off-by: Russell King diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index b1575b8..a45aaa1 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -220,6 +220,30 @@ static struct platform_device stuart_device = { .id = 2, }; +static struct resource i2c_resources[] = { + { + .start = 0x40301680, + .end = 0x403016a3, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_I2C, + .end = IRQ_I2C, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device i2c_device = { + .name = "pxa2xx-i2c", + .id = 0, + .resource = i2c_resources, + .num_resources = ARRAY_SIZE(i2c_resources), +}; + +void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info) +{ + i2c_device.dev.platform_data = info; +} + static struct platform_device *devices[] __initdata = { &pxamci_device, &udc_device, @@ -227,6 +251,7 @@ static struct platform_device *devices[] __initdata = { &ffuart_device, &btuart_device, &stuart_device, + &i2c_device, }; static int __init pxa_init(void) -- cgit v0.10.2 From 9747dd6fa98f2983f4dd09cd6dad1fa3d2a4c5f2 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 30 Apr 2005 10:01:40 -0700 Subject: [PATCH] ppc64: fix 32-bit signal frame back link When the kernel creates a signal frame on the user stack, it puts the old stack pointer value at the beginning so that the signal frame is linked into the chain of stack frames like any other frame. Unfortunately, for 32-bit processes we are writing the old stack pointer as a 64-bit value rather than a 32-bit value, and the process sees that as a null pointer, since it only looks at the first 32 bits, which are zero since ppc is bigendian and the stack pointer is below 4GB. This bug is in SLES9 and RHEL4 too, hence the ccs. This patch fixes the bug by making the signal code write the old stack pointer as a u32 instead of an unsigned long. Signed-off-by: Paul Mackerras Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c index b0e167d..3c2fa5c 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c @@ -657,7 +657,7 @@ static int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, /* Save user registers on the stack */ frame = &rt_sf->uc.uc_mcontext; - if (put_user(regs->gpr[1], (unsigned long __user *)newsp)) + if (put_user(regs->gpr[1], (u32 __user *)newsp)) goto badframe; if (vdso32_rt_sigtramp && current->thread.vdso_base) { @@ -842,7 +842,7 @@ static int handle_signal32(unsigned long sig, struct k_sigaction *ka, regs->link = (unsigned long) frame->mctx.tramp; } - if (put_user(regs->gpr[1], (unsigned long __user *)newsp)) + if (put_user(regs->gpr[1], (u32 __user *)newsp)) goto badframe; regs->gpr[1] = (unsigned long) newsp; regs->gpr[3] = sig; -- cgit v0.10.2 From 68575476718ed1c6d6ddafeec8310b109e7a7a7f Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Apr 2005 11:10:57 -0700 Subject: [PATCH] cifs: append \* properly on ASCII servers For older servers which do not support Unicode Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 4d24043..95483ba 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -4,7 +4,9 @@ Fix error mapping of the TOO_MANY_LINKS (hardlinks) case. Do not oops if root user kills cifs oplock kernel thread or kills the cifsd thread (NB: killing the cifs kernel threads is not recommended, unmount and rmmod cifs will kill them when they are -no longer needed). +no longer needed). Fix readdir to ASCII servers (ie older servers +which do not support Unicode) and also require asterik. + Version 1.33 ------------ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b004fef..741ff0c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2451,12 +2451,14 @@ findFirstRetry: name_len += 2; } else { /* BB add check for overrun of SMB buf BB */ name_len = strnlen(searchName, PATH_MAX); - name_len++; /* trailing null */ /* BB fix here and in unicode clause above ie if(name_len > buffersize-header) free buffer exit; BB */ strncpy(pSMB->FileName, searchName, name_len); - pSMB->FileName[name_len] = 0; /* just in case */ + pSMB->FileName[name_len] = '\\'; + pSMB->FileName[name_len+1] = '*'; + pSMB->FileName[name_len+2] = 0; + name_len += 3; } params = 12 + name_len /* includes null */ ; -- cgit v0.10.2 From 9ea1f8f505f6f770bd593e689960ac4f893509b2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Apr 2005 11:10:58 -0700 Subject: [PATCH] cifs: Update cifs todo list Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 1e8490e..8cc8816 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -1,4 +1,4 @@ -version 1.32 April 3, 2005 +version 1.34 April 29, 2005 A Partial List of Missing Features ================================== @@ -70,7 +70,15 @@ r) Implement O_DIRECT flag on open (already supported on mount) s) Allow remapping of last remaining character (\) to +0xF000 which (this character is valid for POSIX but not for Windows) -KNOWN BUGS (updated April 3, 2005) +t) Create UID mapping facility so server UIDs can be mapped on a per +mount or a per server basis to client UIDs or nobody if no mapping +exists. This is helpful when Unix extensions are negotiated to +allow better permission checking when UIDs differ on the server +and client. Add new protocol request to the CIFS protocol +standard for asking the server for the corresponding name of a +particular uid. + +KNOWN BUGS (updated April 29, 2005) ==================================== See http://bugzilla.samba.org - search on product "CifsVFS" for current bug list. -- cgit v0.10.2 From 1ddb8a16aa0e60e7fdc48b1f532cf43e692f8fae Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 30 Apr 2005 22:39:51 +0100 Subject: [PATCH] ARM: AMBA CLCD: program palette for pseudocolor visuals Signed-off-by: Russell King diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 3e386fd..2896a38 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -256,7 +256,7 @@ clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, convert_bitfield(green, &fb->fb.var.green) | convert_bitfield(red, &fb->fb.var.red); - if (fb->fb.var.bits_per_pixel == 8 && regno < 256) { + if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) { int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3); u32 val, mask, newval; -- cgit v0.10.2 From ed562ab12733ab75437b3390427d41fce9da83c3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 30 Apr 2005 23:28:47 +0100 Subject: [PATCH] ARM: IntegratorCP: 16bpp is RGB565 not RGB555 Signed-off-by: Russell King diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 2896a38..321dbe9 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -134,16 +134,16 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) break; case 16: var->red.length = 5; - var->green.length = 5; + var->green.length = 6; var->blue.length = 5; if (fb->panel->cntl & CNTL_BGR) { - var->red.offset = 10; + var->red.offset = 11; var->green.offset = 5; var->blue.offset = 0; } else { var->red.offset = 0; var->green.offset = 5; - var->blue.offset = 10; + var->blue.offset = 11; } break; case 32: -- cgit v0.10.2 From 4774e2260cf25c54f2188dd0407676e3af6f1f23 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 30 Apr 2005 23:32:38 +0100 Subject: [PATCH] ARM: IntegratorCP: Fix CLCD MUX selection values The documentation on these values seems to be rather wrong. These values have been determined by mere trial and error. Signed-off-by: Russell King diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 68e15c3..3b948e8 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -420,7 +420,22 @@ static struct clcd_panel vga = { */ static void cp_clcd_enable(struct clcd_fb *fb) { - cm_control(CM_CTRL_LCDMUXSEL_MASK, CM_CTRL_LCDMUXSEL_VGA); + u32 val; + + if (fb->fb.var.bits_per_pixel <= 8) + val = CM_CTRL_LCDMUXSEL_VGA_8421BPP; + else if (fb->fb.var.bits_per_pixel <= 16) + val = CM_CTRL_LCDMUXSEL_VGA_16BPP; + else + val = 0; /* no idea for this, don't trust the docs */ + + cm_control(CM_CTRL_LCDMUXSEL_MASK| + CM_CTRL_LCDEN0| + CM_CTRL_LCDEN1| + CM_CTRL_STATIC1| + CM_CTRL_STATIC2| + CM_CTRL_STATIC| + CM_CTRL_n24BITEN, val); } static unsigned long framesize = SZ_1M; diff --git a/include/asm-arm/arch-integrator/cm.h b/include/asm-arm/arch-integrator/cm.h index d31c1a7..1ab353e 100644 --- a/include/asm-arm/arch-integrator/cm.h +++ b/include/asm-arm/arch-integrator/cm.h @@ -24,9 +24,9 @@ void cm_control(u32, u32); #define CM_CTRL_LCDBIASDN (1 << 10) #define CM_CTRL_LCDMUXSEL_MASK (7 << 11) #define CM_CTRL_LCDMUXSEL_GENLCD (1 << 11) -#define CM_CTRL_LCDMUXSEL_SHARPLCD1 (3 << 11) -#define CM_CTRL_LCDMUXSEL_SHARPLCD2 (4 << 11) -#define CM_CTRL_LCDMUXSEL_VGA (7 << 11) +#define CM_CTRL_LCDMUXSEL_VGA_16BPP (2 << 11) +#define CM_CTRL_LCDMUXSEL_SHARPLCD (3 << 11) +#define CM_CTRL_LCDMUXSEL_VGA_8421BPP (4 << 11) #define CM_CTRL_LCDEN0 (1 << 14) #define CM_CTRL_LCDEN1 (1 << 15) #define CM_CTRL_STATIC1 (1 << 16) -- cgit v0.10.2 From 2cacb3da620a4a93f3a77e1d2c8c06bb3c74bcb0 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Apr 2005 16:51:42 -0700 Subject: [PATCH] kbuild/i386: re-introduce dependency on vmlinux for install target, and add kernel_install Removing the dependency on vmlinux for the install target raised a few complaints, so instead a new target i added: kernel_install. kernel_install will install the kernel just like the ordinary install target. The only difference is that install has a dependency on vmlinux, kernel_install does not. Therefore kernel_install is the best choice when accessing the kernel over a NFS mount or as another user. kernel_install is similar to modules_install in the fact that neither does a full kernel compile before performing the install. In this way they are good for root use. Also added back the dependency on vmlinux for the install target so peoples scripts are no longer broken. Signed-off-by: Sam Ravnborg Signed-off-by: Linus Torvalds diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 314c714..04783ce 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -123,7 +123,7 @@ AFLAGS += $(mflags-y) boot := arch/i386/boot .PHONY: zImage bzImage compressed zlilo bzlilo \ - zdisk bzdisk fdimage fdimage144 fdimage288 install + zdisk bzdisk fdimage fdimage144 fdimage288 install kernel_install all: bzImage @@ -145,8 +145,9 @@ zdisk bzdisk: vmlinux fdimage fdimage144 fdimage288: vmlinux $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@ -install: - $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@ +install: vmlinux +install kernel_install: + $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install prepare: include/asm-$(ARCH)/asm_offsets.h CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h -- cgit v0.10.2 From b3d9ae4b98f6d28481d4d4b768d860a2cfb5805d Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Apr 2005 16:51:42 -0700 Subject: [PATCH] kbuild/ppc: tell when uimage was not built Tom Rini said: Note that there is still a trivial'ish change to make. When mkimage doesn't exist on the host we should say "uImage not made" or something similar. So I did like Tom asked. Signed-off-by: Sam Ravnborg Signed-off-by: Linus Torvalds diff --git a/arch/ppc/boot/images/Makefile b/arch/ppc/boot/images/Makefile index 774de8e..f850fb0 100644 --- a/arch/ppc/boot/images/Makefile +++ b/arch/ppc/boot/images/Makefile @@ -20,8 +20,9 @@ quiet_cmd_uimage = UIMAGE $@ targets += uImage $(obj)/uImage: $(obj)/vmlinux.gz + $(Q)rm -f $@ $(call if_changed,uimage) - @echo ' Image $@ is ready' + @echo ' Image: $@' $(if $(wildcard $@),'is ready','not made') # Files generated that shall be removed upon make clean clean-files := sImage vmapus vmlinux* miboot* zImage* uImage -- cgit v0.10.2 From e8e6993178344eb348f60f05b16d9dc30db3b9cf Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Apr 2005 16:51:42 -0700 Subject: [PATCH] kbuild: Set NOSTDINC_FLAGS late to speed up compile (a little) Move definition of NOSTDINC_FLAGS below inclusion of arch Makefile, so any arch specific settings to $(CC) takes effect before looking up the compiler include directory. The previous solution that replaced ':=' with '=' caused gcc to be invoked one additional time for each directory visited. This decreases kernel compile time with 0.1 second (3.6 -> 3.5 seconds) when running make on a fully built kernel Signed-off-by: Sam Ravnborg Signed-off-by: Linus Torvalds diff --git a/Makefile b/Makefile index 8da3a30..4899089 100644 --- a/Makefile +++ b/Makefile @@ -332,9 +332,7 @@ KALLSYMS = scripts/kallsyms PERL = perl CHECK = sparse -NOSTDINC_FLAGS = -nostdinc -isystem $(shell $(CC) -print-file-name=include) CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -CHECKFLAGS += $(NOSTDINC_FLAGS) MODFLAGS = -DMODULE CFLAGS_MODULE = $(MODFLAGS) AFLAGS_MODULE = $(MODFLAGS) @@ -531,6 +529,10 @@ endif include $(srctree)/arch/$(ARCH)/Makefile +# arch Makefile may override CC so keep this after arch Makefile is included +NOSTDINC_FLAGS := -nostdinc -isystem $(shell $(CC) -print-file-name=include) +CHECKFLAGS += $(NOSTDINC_FLAGS) + # warn about C99 declaration after statement CFLAGS += $(call cc-option,-Wdeclaration-after-statement,) -- cgit v0.10.2 From 69aa3f71580990f39e387d96ed1001d2f5fb04b1 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sun, 1 May 2005 08:58:35 -0700 Subject: [PATCH] ultrastor build fix Fix a typo. James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index a00095c..97f4d91 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -945,7 +945,7 @@ static int ultrastor_abort(Scsi_Cmnd *SCpnt) config.mscp[mscp_index].SCint, SCpnt); #endif if (config.mscp[mscp_index].SCint == 0) - return FAILURE; + return FAILED; if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort"); config.mscp[mscp_index].SCint = NULL; -- cgit v0.10.2 From f021e9210185b46e41ec3a0e78ec1621e168eacb Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sun, 1 May 2005 08:58:35 -0700 Subject: [PATCH] generic_file_buffered_write fixes Anton Altaparmakov points out: - It calls fault_in_pages_readable() which is completely bogus if @nr_segs > 1. It needs to be replaced by a to be written "fault_in_pages_readable_iovec()". - It increments @buf even in the iovec case thus @buf can point to random memory really quickly (in the iovec case) and then it calls fault_in_pages_readable() on this random memory. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/filemap.c b/mm/filemap.c index 93595c3..9b74674 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1949,7 +1949,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, buf = iov->iov_base + written; else { filemap_set_next_iovec(&cur_iov, &iov_base, written); - buf = iov->iov_base + iov_base; + buf = cur_iov->iov_base + iov_base; } do { @@ -2007,9 +2007,11 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, count -= status; pos += status; buf += status; - if (unlikely(nr_segs > 1)) + if (unlikely(nr_segs > 1)) { filemap_set_next_iovec(&cur_iov, &iov_base, status); + buf = cur_iov->iov_base + iov_base; + } } } if (unlikely(copied != bytes)) -- cgit v0.10.2 From 119f657c72fc07d6fd28c61de59cfba1566970a9 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sun, 1 May 2005 08:58:35 -0700 Subject: [PATCH] RLIMIT_AS checking fix Address bug #4508: there's potential for wraparound in the various places where we perform RLIMIT_AS checking. (I'm a bit worried about acct_stack_growth(). Are we sure that vma->vm_mm is always equal to current->mm? If not, then we're comparing some other process's total_vm with the calling process's rlimits). Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/mm.h b/include/linux/mm.h index c74a74c..8b007ad 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -726,6 +726,7 @@ extern void __vma_link_rb(struct mm_struct *, struct vm_area_struct *, extern struct vm_area_struct *copy_vma(struct vm_area_struct **, unsigned long addr, unsigned long len, pgoff_t pgoff); extern void exit_mmap(struct mm_struct *); +extern int may_expand_vm(struct mm_struct *mm, unsigned long npages); extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); diff --git a/mm/mmap.c b/mm/mmap.c index 6ea204c..1ec0f6e 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1009,8 +1009,7 @@ munmap_back: } /* Check against address space limit. */ - if ((mm->total_vm << PAGE_SHIFT) + len - > current->signal->rlim[RLIMIT_AS].rlim_cur) + if (!may_expand_vm(mm, len >> PAGE_SHIFT)) return -ENOMEM; if (accountable && (!(flags & MAP_NORESERVE) || @@ -1421,7 +1420,7 @@ static int acct_stack_growth(struct vm_area_struct * vma, unsigned long size, un struct rlimit *rlim = current->signal->rlim; /* address space limit tests */ - if (mm->total_vm + grow > rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT) + if (!may_expand_vm(mm, grow)) return -ENOMEM; /* Stack limit test */ @@ -1848,8 +1847,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len) } /* Check against address space limits *after* clearing old maps... */ - if ((mm->total_vm << PAGE_SHIFT) + len - > current->signal->rlim[RLIMIT_AS].rlim_cur) + if (!may_expand_vm(mm, len >> PAGE_SHIFT)) return -ENOMEM; if (mm->map_count > sysctl_max_map_count) @@ -2019,3 +2017,19 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, } return new_vma; } + +/* + * Return true if the calling process may expand its vm space by the passed + * number of pages + */ +int may_expand_vm(struct mm_struct *mm, unsigned long npages) +{ + unsigned long cur = mm->total_vm; /* pages */ + unsigned long lim; + + lim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT; + + if (cur + npages > lim) + return 0; + return 1; +} diff --git a/mm/mremap.c b/mm/mremap.c index 0d1c1b9..0dd7ace 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -347,10 +347,10 @@ unsigned long do_mremap(unsigned long addr, if (locked > lock_limit && !capable(CAP_IPC_LOCK)) goto out; } - ret = -ENOMEM; - if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len) - > current->signal->rlim[RLIMIT_AS].rlim_cur) + if (!may_expand_vm(current->mm, (new_len - old_len) >> PAGE_SHIFT)) { + ret = -ENOMEM; goto out; + } if (vma->vm_flags & VM_ACCOUNT) { charged = (new_len - old_len) >> PAGE_SHIFT; -- cgit v0.10.2 From 81b4082dc7666e2bc5ec229d8e837f3bafb96883 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Sun, 1 May 2005 08:58:36 -0700 Subject: [PATCH] mm: rmap.c cleanup mm/rmap.c:page_referenced_one() and mm/rmap.c:try_to_unmap_one() contain identical code that - takes mm->page_table_lock; - drills through page tables; - checks that correct pte is reached. Coalesce this into page_check_address() Signed-off-by: Nikita Danilov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/rmap.c b/mm/rmap.c index 884d6d1..378de23 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -243,6 +243,42 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma) } /* + * Check that @page is mapped at @address into @mm. + * + * On success returns with mapped pte and locked mm->page_table_lock. + */ +static pte_t *page_check_address(struct page *page, struct mm_struct *mm, + unsigned long address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + /* + * We need the page_table_lock to protect us from page faults, + * munmap, fork, etc... + */ + spin_lock(&mm->page_table_lock); + pgd = pgd_offset(mm, address); + if (likely(pgd_present(*pgd))) { + pud = pud_offset(pgd, address); + if (likely(pud_present(*pud))) { + pmd = pmd_offset(pud, address); + if (likely(pmd_present(*pmd))) { + pte = pte_offset_map(pmd, address); + if (likely(pte_present(*pte) && + page_to_pfn(page) == pte_pfn(*pte))) + return pte; + pte_unmap(pte); + } + } + } + spin_unlock(&mm->page_table_lock); + return ERR_PTR(-ENOENT); +} + +/* * Subfunctions of page_referenced: page_referenced_one called * repeatedly from either page_referenced_anon or page_referenced_file. */ @@ -251,9 +287,6 @@ static int page_referenced_one(struct page *page, { struct mm_struct *mm = vma->vm_mm; unsigned long address; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; pte_t *pte; int referenced = 0; @@ -263,39 +296,18 @@ static int page_referenced_one(struct page *page, if (address == -EFAULT) goto out; - spin_lock(&mm->page_table_lock); - - pgd = pgd_offset(mm, address); - if (!pgd_present(*pgd)) - goto out_unlock; - - pud = pud_offset(pgd, address); - if (!pud_present(*pud)) - goto out_unlock; - - pmd = pmd_offset(pud, address); - if (!pmd_present(*pmd)) - goto out_unlock; - - pte = pte_offset_map(pmd, address); - if (!pte_present(*pte)) - goto out_unmap; - - if (page_to_pfn(page) != pte_pfn(*pte)) - goto out_unmap; - - if (ptep_clear_flush_young(vma, address, pte)) - referenced++; - - if (mm != current->mm && !ignore_token && has_swap_token(mm)) - referenced++; + pte = page_check_address(page, mm, address); + if (!IS_ERR(pte)) { + if (ptep_clear_flush_young(vma, address, pte)) + referenced++; - (*mapcount)--; + if (mm != current->mm && !ignore_token && has_swap_token(mm)) + referenced++; -out_unmap: - pte_unmap(pte); -out_unlock: - spin_unlock(&mm->page_table_lock); + (*mapcount)--; + pte_unmap(pte); + spin_unlock(&mm->page_table_lock); + } out: return referenced; } @@ -502,9 +514,6 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma) { struct mm_struct *mm = vma->vm_mm; unsigned long address; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; pte_t *pte; pte_t pteval; int ret = SWAP_AGAIN; @@ -515,30 +524,9 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma) if (address == -EFAULT) goto out; - /* - * We need the page_table_lock to protect us from page faults, - * munmap, fork, etc... - */ - spin_lock(&mm->page_table_lock); - - pgd = pgd_offset(mm, address); - if (!pgd_present(*pgd)) - goto out_unlock; - - pud = pud_offset(pgd, address); - if (!pud_present(*pud)) - goto out_unlock; - - pmd = pmd_offset(pud, address); - if (!pmd_present(*pmd)) - goto out_unlock; - - pte = pte_offset_map(pmd, address); - if (!pte_present(*pte)) - goto out_unmap; - - if (page_to_pfn(page) != pte_pfn(*pte)) - goto out_unmap; + pte = page_check_address(page, mm, address); + if (IS_ERR(pte)) + goto out; /* * If the page is mlock()d, we cannot swap it out. @@ -604,7 +592,6 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma) out_unmap: pte_unmap(pte); -out_unlock: spin_unlock(&mm->page_table_lock); out: return ret; @@ -708,7 +695,6 @@ static void try_to_unmap_cluster(unsigned long cursor, } pte_unmap(pte); - out_unlock: spin_unlock(&mm->page_table_lock); } @@ -860,3 +846,4 @@ int try_to_unmap(struct page *page) ret = SWAP_SUCCESS; return ret; } + -- cgit v0.10.2 From 8e30f272a93ec9c1d5c305c5040dfaebc880499d Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 1 May 2005 08:58:36 -0700 Subject: [PATCH] mm: pcp use non powers of 2 for batch size Jack Steiner reported this to have fixed his problem (bad colouring): "The patches fix both problems that I found - bad coloring & excessive pages in pagesets." In most workloads this is not likely to be such a pronounced problem, however it should help corner cases. And avoiding powers of 2 in these types of memory operations is always a good idea. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c73dbbc..08e8627 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1671,6 +1671,18 @@ static void __init free_area_init_core(struct pglist_data *pgdat, if (batch < 1) batch = 1; + /* + * Clamp the batch to a 2^n - 1 value. Having a power + * of 2 value was found to be more likely to have + * suboptimal cache aliasing properties in some cases. + * + * For example if 2 tasks are alternately allocating + * batches of pages, one task can end up with a lot + * of pages of one half of the possible page colors + * and the other with pages of the other colors. + */ + batch = (1 << fls(batch + batch/2)) - 1; + for (cpu = 0; cpu < NR_CPUS; cpu++) { struct per_cpu_pages *pcp; -- cgit v0.10.2 From b84a35be0285229b0a8a5e2e04d79360c5b75562 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 1 May 2005 08:58:36 -0700 Subject: [PATCH] mempool: NOMEMALLOC and NORETRY Mempools have 2 problems. The first is that mempool_alloc can possibly get stuck in __alloc_pages when they should opt to fail, and take an element from their reserved pool. The second is that it will happily eat emergency PF_MEMALLOC reserves instead of going to their reserved pools. Fix the first by passing __GFP_NORETRY in the allocation calls in mempool_alloc. Fix the second by introducing a __GFP_MEMPOOL flag which directs the page allocator not to allocate from the reserve pool. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 848a1ba..af7407e 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -38,14 +38,16 @@ struct vm_area_struct; #define __GFP_NO_GROW 0x2000u /* Slab internal usage */ #define __GFP_COMP 0x4000u /* Add compound page metadata */ #define __GFP_ZERO 0x8000u /* Return zeroed page on success */ +#define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */ -#define __GFP_BITS_SHIFT 16 /* Room for 16 __GFP_FOO bits */ +#define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */ #define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1) /* if you forget to add the bitmask here kernel will crash, period */ #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \ __GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \ - __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP) + __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \ + __GFP_NOMEMALLOC) #define GFP_ATOMIC (__GFP_HIGH) #define GFP_NOIO (__GFP_WAIT) diff --git a/mm/mempool.c b/mm/mempool.c index b014ffe..d691b5c 100644 --- a/mm/mempool.c +++ b/mm/mempool.c @@ -198,11 +198,16 @@ void * mempool_alloc(mempool_t *pool, unsigned int __nocast gfp_mask) void *element; unsigned long flags; DEFINE_WAIT(wait); - int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO); + int gfp_nowait; + + gfp_mask |= __GFP_NOMEMALLOC; /* don't allocate emergency reserves */ + gfp_mask |= __GFP_NORETRY; /* don't loop in __alloc_pages */ + gfp_mask |= __GFP_NOWARN; /* failures are OK */ + gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO); might_sleep_if(gfp_mask & __GFP_WAIT); repeat_alloc: - element = pool->alloc(gfp_nowait|__GFP_NOWARN, pool->pool_data); + element = pool->alloc(gfp_nowait, pool->pool_data); if (likely(element != NULL)) return element; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 08e8627..04a35b3 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -799,14 +799,18 @@ __alloc_pages(unsigned int __nocast gfp_mask, unsigned int order, } /* This allocation should allow future memory freeing. */ - if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE))) && !in_interrupt()) { - /* go through the zonelist yet again, ignoring mins */ - for (i = 0; (z = zones[i]) != NULL; i++) { - if (!cpuset_zone_allowed(z)) - continue; - page = buffered_rmqueue(z, order, gfp_mask); - if (page) - goto got_pg; + + if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE))) + && !in_interrupt()) { + if (!(gfp_mask & __GFP_NOMEMALLOC)) { + /* go through the zonelist yet again, ignoring mins */ + for (i = 0; (z = zones[i]) != NULL; i++) { + if (!cpuset_zone_allowed(z)) + continue; + page = buffered_rmqueue(z, order, gfp_mask); + if (page) + goto got_pg; + } } goto nopage; } -- cgit v0.10.2 From 20a77776c24800d1e40a73f520cfcb32239568a9 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 1 May 2005 08:58:37 -0700 Subject: [PATCH] mempool: simplify alloc Mempool is pretty clever. Looks too clever for its own good :) It shouldn't really know so much about page reclaim internals. - don't guess about what effective page reclaim might involve. - don't randomly flush out all dirty data if some unlikely thing happens (alloc returns NULL). page reclaim can (sort of :P) handle it. I think the main motivation is trying to avoid pool->lock at all costs. However the first allocation is attempted with __GFP_WAIT cleared, so it will be 'can_try_harder' if it hits the page allocator. So if allocation still fails, then we can probably afford to hit the pool->lock - and what's the alternative? Try page reclaim and hit zone->lru_lock? A nice upshot is that we don't need to do any fancy memory barriers or do (intentionally) racy access to pool-> fields outside the lock. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/mempool.c b/mm/mempool.c index d691b5c..e9a0a63 100644 --- a/mm/mempool.c +++ b/mm/mempool.c @@ -198,36 +198,22 @@ void * mempool_alloc(mempool_t *pool, unsigned int __nocast gfp_mask) void *element; unsigned long flags; DEFINE_WAIT(wait); - int gfp_nowait; + int gfp_temp; + + might_sleep_if(gfp_mask & __GFP_WAIT); gfp_mask |= __GFP_NOMEMALLOC; /* don't allocate emergency reserves */ gfp_mask |= __GFP_NORETRY; /* don't loop in __alloc_pages */ gfp_mask |= __GFP_NOWARN; /* failures are OK */ - gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO); - might_sleep_if(gfp_mask & __GFP_WAIT); + gfp_temp = gfp_mask & ~(__GFP_WAIT|__GFP_IO); + repeat_alloc: - element = pool->alloc(gfp_nowait, pool->pool_data); + + element = pool->alloc(gfp_temp, pool->pool_data); if (likely(element != NULL)) return element; - /* - * If the pool is less than 50% full and we can perform effective - * page reclaim then try harder to allocate an element. - */ - mb(); - if ((gfp_mask & __GFP_FS) && (gfp_mask != gfp_nowait) && - (pool->curr_nr <= pool->min_nr/2)) { - element = pool->alloc(gfp_mask, pool->pool_data); - if (likely(element != NULL)) - return element; - } - - /* - * Kick the VM at this point. - */ - wakeup_bdflush(0); - spin_lock_irqsave(&pool->lock, flags); if (likely(pool->curr_nr)) { element = remove_element(pool); @@ -240,6 +226,8 @@ repeat_alloc: if (!(gfp_mask & __GFP_WAIT)) return NULL; + /* Now start performing page reclaim */ + gfp_temp = gfp_mask; prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE); mb(); if (!pool->curr_nr) -- cgit v0.10.2 From bd53b714d32a29bdf33009f812e295667e92b930 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 1 May 2005 08:58:37 -0700 Subject: [PATCH] mm: use __GFP_NOMEMALLOC Use the new __GFP_NOMEMALLOC to simplify the previous handling of PF_MEMALLOC. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 77619a5..0dd6c2b 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -331,25 +331,19 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size, struct bio *bio; unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; int gfp_mask = GFP_NOIO | __GFP_HIGHMEM; - unsigned long flags = current->flags; unsigned int i; /* - * Tell VM to act less aggressively and fail earlier. - * This is not necessary but increases throughput. + * Use __GFP_NOMEMALLOC to tell the VM to act less aggressively and + * to fail earlier. This is not necessary but increases throughput. * FIXME: Is this really intelligent? */ - current->flags &= ~PF_MEMALLOC; - if (base_bio) - bio = bio_clone(base_bio, GFP_NOIO); + bio = bio_clone(base_bio, GFP_NOIO|__GFP_NOMEMALLOC); else - bio = bio_alloc(GFP_NOIO, nr_iovecs); - if (!bio) { - if (flags & PF_MEMALLOC) - current->flags |= PF_MEMALLOC; + bio = bio_alloc(GFP_NOIO|__GFP_NOMEMALLOC, nr_iovecs); + if (!bio) return NULL; - } /* if the last bio was not complete, continue where that one ended */ bio->bi_idx = *bio_vec_idx; @@ -386,9 +380,6 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size, size -= bv->bv_len; } - if (flags & PF_MEMALLOC) - current->flags |= PF_MEMALLOC; - if (!bio->bi_size) { bio_put(bio); return NULL; diff --git a/mm/swap_state.c b/mm/swap_state.c index a063a90..4f25177 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -143,7 +143,6 @@ void __delete_from_swap_cache(struct page *page) int add_to_swap(struct page * page) { swp_entry_t entry; - int pf_flags; int err; if (!PageLocked(page)) @@ -154,29 +153,19 @@ int add_to_swap(struct page * page) if (!entry.val) return 0; - /* Radix-tree node allocations are performing - * GFP_ATOMIC allocations under PF_MEMALLOC. - * They can completely exhaust the page allocator. - * - * So PF_MEMALLOC is dropped here. This causes the slab - * allocations to fail earlier, so radix-tree nodes will - * then be allocated from the mempool reserves. + /* + * Radix-tree node allocations from PF_MEMALLOC contexts could + * completely exhaust the page allocator. __GFP_NOMEMALLOC + * stops emergency reserves from being allocated. * - * We're still using __GFP_HIGH for radix-tree node - * allocations, so some of the emergency pools are available, - * just not all of them. + * TODO: this could cause a theoretical memory reclaim + * deadlock in the swap out path. */ - - pf_flags = current->flags; - current->flags &= ~PF_MEMALLOC; - /* * Add it to the swap cache and mark it dirty */ - err = __add_to_swap_cache(page, entry, GFP_ATOMIC|__GFP_NOWARN); - - if (pf_flags & PF_MEMALLOC) - current->flags |= PF_MEMALLOC; + err = __add_to_swap_cache(page, entry, + GFP_ATOMIC|__GFP_NOMEMALLOC|__GFP_NOWARN); switch (err) { case 0: /* Success */ -- cgit v0.10.2 From 2054606ad6dd6fee559fe790f190b15ed9355237 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Sun, 1 May 2005 08:58:37 -0700 Subject: [PATCH] doc: Locking update Make the Locking document truer. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index a934bae..1045da5 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -219,8 +219,12 @@ This may also be done to avoid internal deadlocks, but rarely. If the filesytem is called for sync then it must wait on any in-progress I/O and then start new I/O. -The filesystem should unlock the page synchronously, before returning -to the caller. +The filesystem should unlock the page synchronously, before returning to the +caller, unless ->writepage() returns special WRITEPAGE_ACTIVATE +value. WRITEPAGE_ACTIVATE means that page cannot really be written out +currently, and VM should stop calling ->writepage() on this page for some +time. VM does this by moving page to the head of the active list, hence the +name. Unless the filesystem is going to redirty_page_for_writepage(), unlock the page and return zero, writepage *must* run set_page_writeback() against the page, -- cgit v0.10.2 From edfbe2b0038723e5699ab22695ccd62b5542a5c1 Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Sun, 1 May 2005 08:58:37 -0700 Subject: [PATCH] count bounce buffer pages in vmstat This is a patch for counting the number of pages for bounce buffers. It's shown in /proc/vmstat. Currently, the number of bounce pages are not counted anywhere. So, if there are many bounce pages, it seems that there are leaked pages. And it's difficult for a user to imagine the usage of bounce pages. So, it's meaningful to show # of bouce pages. Signed-off-by: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 6b74fcf..39ab8c6 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -131,6 +131,7 @@ struct page_state { unsigned long allocstall; /* direct reclaim calls */ unsigned long pgrotated; /* pages rotated to tail of the LRU */ + unsigned long nr_bounce; /* pages for bounce buffers */ }; extern void get_page_state(struct page_state *ret); diff --git a/mm/highmem.c b/mm/highmem.c index d012765..4009115 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -325,6 +325,7 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool, int err) continue; mempool_free(bvec->bv_page, pool); + dec_page_state(nr_bounce); } bio_endio(bio_orig, bio_orig->bi_size, err); @@ -405,6 +406,7 @@ static void __blk_queue_bounce(request_queue_t *q, struct bio **bio_orig, to->bv_page = mempool_alloc(pool, q->bounce_gfp); to->bv_len = from->bv_len; to->bv_offset = from->bv_offset; + inc_page_state(nr_bounce); if (rw == WRITE) { char *vto, *vfrom; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 04a35b3..80ce7f2 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1897,6 +1897,7 @@ static char *vmstat_text[] = { "allocstall", "pgrotated", + "nr_bounce", }; static void *vmstat_start(struct seq_file *m, loff_t *pos) -- cgit v0.10.2 From 93ea1d0a12623dc1a693642b5758261f35f9bf96 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Sun, 1 May 2005 08:58:38 -0700 Subject: [PATCH] RLIMIT_MEMLOCK checking fix Always use page counts when doing RLIMIT_MEMLOCK checking to avoid possible overflow. Signed-off-by: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/mmap.c b/mm/mmap.c index 1ec0f6e..01f9793 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -937,9 +937,10 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, /* mlock MCL_FUTURE? */ if (vm_flags & VM_LOCKED) { unsigned long locked, lock_limit; - locked = mm->locked_vm << PAGE_SHIFT; + locked = len >> PAGE_SHIFT; + locked += mm->locked_vm; lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; - locked += len; + lock_limit >>= PAGE_SHIFT; if (locked > lock_limit && !capable(CAP_IPC_LOCK)) return -EAGAIN; } @@ -1822,9 +1823,10 @@ unsigned long do_brk(unsigned long addr, unsigned long len) */ if (mm->def_flags & VM_LOCKED) { unsigned long locked, lock_limit; - locked = mm->locked_vm << PAGE_SHIFT; + locked = len >> PAGE_SHIFT; + locked += mm->locked_vm; lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; - locked += len; + lock_limit >>= PAGE_SHIFT; if (locked > lock_limit && !capable(CAP_IPC_LOCK)) return -EAGAIN; } -- cgit v0.10.2 From dd1d5afca8d3bda7ff9db773fc08e648d2503dc6 Mon Sep 17 00:00:00 2001 From: William Lee Irwin III Date: Sun, 1 May 2005 08:58:38 -0700 Subject: [PATCH] sync_page() smp_mb() comment The smp_mb() is becaus sync_page() doesn't have PG_locked while it accesses page_mapping(page). The comments in the patch (the entire patch is the addition of this comment) try to explain further how and why smp_mb() is used. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/filemap.c b/mm/filemap.c index 9b74674..ee79b5d 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -139,7 +139,25 @@ static int sync_page(void *word) page = container_of((page_flags_t *)word, struct page, flags); /* - * FIXME, fercrissake. What is this barrier here for? + * page_mapping() is being called without PG_locked held. + * Some knowledge of the state and use of the page is used to + * reduce the requirements down to a memory barrier. + * The danger here is of a stale page_mapping() return value + * indicating a struct address_space different from the one it's + * associated with when it is associated with one. + * After smp_mb(), it's either the correct page_mapping() for + * the page, or an old page_mapping() and the page's own + * page_mapping() has gone NULL. + * The ->sync_page() address_space operation must tolerate + * page_mapping() going NULL. By an amazing coincidence, + * this comes about because none of the users of the page + * in the ->sync_page() methods make essential use of the + * page_mapping(), merely passing the page down to the backing + * device's unplug functions when it's non-NULL, which in turn + * ignore it for all cases but swap, where only page->private is + * of interest. When page_mapping() does go NULL, the entire + * call stack gracefully ignores the page and returns. + * -- wli */ smp_mb(); mapping = page_mapping(page); -- cgit v0.10.2 From 97e2bde47f886a317909c8a8f9bd2fcd8ce2f0b0 Mon Sep 17 00:00:00 2001 From: Manfred Spraul Date: Sun, 1 May 2005 08:58:38 -0700 Subject: [PATCH] add kmalloc_node, inline cleanup The patch makes the following function calls available to allocate memory on a specific node without changing the basic operation of the slab allocator: kmem_cache_alloc_node(kmem_cache_t *cachep, unsigned int flags, int node); kmalloc_node(size_t size, unsigned int flags, int node); in a similar way to the existing node-blind functions: kmem_cache_alloc(kmem_cache_t *cachep, unsigned int flags); kmalloc(size, flags); kmem_cache_alloc_node was changed to pass flags and the node information through the existing layers of the slab allocator (which lead to some minor rearrangements). The functions at the lowest layer (kmem_getpages, cache_grow) are already node aware. Also __alloc_percpu can call kmalloc_node now. Performance measurements (using the pageset localization patch) yields: w/o patches: Tasks jobs/min jti jobs/min/task real cpu 1 484.27 100 484.2736 12.02 1.97 Wed Mar 30 20:50:43 2005 100 25170.83 91 251.7083 23.12 150.10 Wed Mar 30 20:51:06 2005 200 34601.66 84 173.0083 33.64 294.14 Wed Mar 30 20:51:40 2005 300 37154.47 86 123.8482 46.99 436.56 Wed Mar 30 20:52:28 2005 400 39839.82 80 99.5995 58.43 580.46 Wed Mar 30 20:53:27 2005 500 40036.32 79 80.0726 72.68 728.60 Wed Mar 30 20:54:40 2005 600 44074.21 79 73.4570 79.23 872.10 Wed Mar 30 20:55:59 2005 700 44016.60 78 62.8809 92.56 1015.84 Wed Mar 30 20:57:32 2005 800 40411.05 80 50.5138 115.22 1161.13 Wed Mar 30 20:59:28 2005 900 42298.56 79 46.9984 123.83 1303.42 Wed Mar 30 21:01:33 2005 1000 40955.05 80 40.9551 142.11 1441.92 Wed Mar 30 21:03:55 2005 with pageset localization and slab API patches: Tasks jobs/min jti jobs/min/task real cpu 1 484.19 100 484.1930 12.02 1.98 Wed Mar 30 21:10:18 2005 100 27428.25 92 274.2825 21.22 149.79 Wed Mar 30 21:10:40 2005 200 37228.94 86 186.1447 31.27 293.49 Wed Mar 30 21:11:12 2005 300 41725.42 85 139.0847 41.84 434.10 Wed Mar 30 21:11:54 2005 400 43032.22 82 107.5805 54.10 582.06 Wed Mar 30 21:12:48 2005 500 42211.23 83 84.4225 68.94 722.61 Wed Mar 30 21:13:58 2005 600 40084.49 82 66.8075 87.12 873.11 Wed Mar 30 21:15:25 2005 700 44169.30 79 63.0990 92.24 1008.77 Wed Mar 30 21:16:58 2005 800 43097.94 79 53.8724 108.03 1155.88 Wed Mar 30 21:18:47 2005 900 41846.75 79 46.4964 125.17 1303.38 Wed Mar 30 21:20:52 2005 1000 40247.85 79 40.2478 144.60 1442.21 Wed Mar 30 21:23:17 2005 Signed-off-by: Christoph Lameter Signed-off-by: Manfred Spraul Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/slab.h b/include/linux/slab.h index 3e3c3ab..7d66385 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -62,16 +62,9 @@ extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned lo extern int kmem_cache_destroy(kmem_cache_t *); extern int kmem_cache_shrink(kmem_cache_t *); extern void *kmem_cache_alloc(kmem_cache_t *, unsigned int __nocast); -#ifdef CONFIG_NUMA -extern void *kmem_cache_alloc_node(kmem_cache_t *, int); -#else -static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int node) -{ - return kmem_cache_alloc(cachep, GFP_KERNEL); -} -#endif extern void kmem_cache_free(kmem_cache_t *, void *); extern unsigned int kmem_cache_size(kmem_cache_t *); +extern kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags); /* Size description struct for general caches. */ struct cache_sizes { @@ -109,6 +102,20 @@ extern void *kcalloc(size_t, size_t, unsigned int __nocast); extern void kfree(const void *); extern unsigned int ksize(const void *); +#ifdef CONFIG_NUMA +extern void *kmem_cache_alloc_node(kmem_cache_t *, int flags, int node); +extern void *kmalloc_node(size_t size, int flags, int node); +#else +static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int node) +{ + return kmem_cache_alloc(cachep, flags); +} +static inline void *kmalloc_node(size_t size, int flags, int node) +{ + return kmalloc(size, flags); +} +#endif + extern int FASTCALL(kmem_cache_reap(int)); extern int FASTCALL(kmem_ptr_validate(kmem_cache_t *cachep, void *ptr)); diff --git a/mm/slab.c b/mm/slab.c index ec660d8..771cc09 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -583,7 +583,7 @@ static inline struct array_cache *ac_data(kmem_cache_t *cachep) return cachep->array[smp_processor_id()]; } -static inline kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags) +static inline kmem_cache_t *__find_general_cachep(size_t size, int gfpflags) { struct cache_sizes *csizep = malloc_sizes; @@ -607,6 +607,12 @@ static inline kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags) return csizep->cs_cachep; } +kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags) +{ + return __find_general_cachep(size, gfpflags); +} +EXPORT_SYMBOL(kmem_find_general_cachep); + /* Cal the num objs, wastage, and bytes left over for a given slab size. */ static void cache_estimate(unsigned long gfporder, size_t size, size_t align, int flags, size_t *left_over, unsigned int *num) @@ -672,14 +678,11 @@ static struct array_cache *alloc_arraycache(int cpu, int entries, int memsize = sizeof(void*)*entries+sizeof(struct array_cache); struct array_cache *nc = NULL; - if (cpu != -1) { - kmem_cache_t *cachep; - cachep = kmem_find_general_cachep(memsize, GFP_KERNEL); - if (cachep) - nc = kmem_cache_alloc_node(cachep, cpu_to_node(cpu)); - } - if (!nc) + if (cpu == -1) nc = kmalloc(memsize, GFP_KERNEL); + else + nc = kmalloc_node(memsize, GFP_KERNEL, cpu_to_node(cpu)); + if (nc) { nc->avail = 0; nc->limit = entries; @@ -2361,7 +2364,7 @@ out: * and can sleep. And it will allocate memory on the given node, which * can improve the performance for cpu bound structures. */ -void *kmem_cache_alloc_node(kmem_cache_t *cachep, int nodeid) +void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int nodeid) { int loop; void *objp; @@ -2393,7 +2396,7 @@ void *kmem_cache_alloc_node(kmem_cache_t *cachep, int nodeid) spin_unlock_irq(&cachep->spinlock); local_irq_disable(); - if (!cache_grow(cachep, GFP_KERNEL, nodeid)) { + if (!cache_grow(cachep, flags, nodeid)) { local_irq_enable(); return NULL; } @@ -2435,6 +2438,16 @@ got_slabp: } EXPORT_SYMBOL(kmem_cache_alloc_node); +void *kmalloc_node(size_t size, int flags, int node) +{ + kmem_cache_t *cachep; + + cachep = kmem_find_general_cachep(size, flags); + if (unlikely(cachep == NULL)) + return NULL; + return kmem_cache_alloc_node(cachep, flags, node); +} +EXPORT_SYMBOL(kmalloc_node); #endif /** @@ -2462,7 +2475,12 @@ void *__kmalloc(size_t size, unsigned int __nocast flags) { kmem_cache_t *cachep; - cachep = kmem_find_general_cachep(size, flags); + /* If you want to save a few bytes .text space: replace + * __ with kmem_. + * Then kmalloc uses the uninlined functions instead of the inline + * functions. + */ + cachep = __find_general_cachep(size, flags); if (unlikely(cachep == NULL)) return NULL; return __cache_alloc(cachep, flags); @@ -2489,9 +2507,8 @@ void *__alloc_percpu(size_t size, size_t align) for (i = 0; i < NR_CPUS; i++) { if (!cpu_possible(i)) continue; - pdata->ptrs[i] = kmem_cache_alloc_node( - kmem_find_general_cachep(size, GFP_KERNEL), - cpu_to_node(i)); + pdata->ptrs[i] = kmalloc_node(size, GFP_KERNEL, + cpu_to_node(i)); if (!pdata->ptrs[i]) goto unwind_oom; -- cgit v0.10.2 From 552fca4cbe552520d85b21e839f289c880fa48d2 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Sun, 1 May 2005 08:58:39 -0700 Subject: [PATCH] mpage_writepages() page locking fix When ->writepage() returns WRITEPAGE_ACTIVATE, the page is still locked. Explicitly unlock the page in mpage_writepages(). Signed-off-by: Nikita Danilov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/mpage.c b/fs/mpage.c index e7d8d1a..3923fac 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -727,6 +727,8 @@ retry: &last_block_in_bio, &ret, wbc, writepage_fn); } + if (unlikely(ret == WRITEPAGE_ACTIVATE)) + unlock_page(page); if (ret || (--(wbc->nr_to_write) <= 0)) done = 1; if (wbc->nonblocking && bdi_write_congested(bdi)) { -- cgit v0.10.2 From de7d5a3b6c9ff8429bf046c36b56d3192b75c3da Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sun, 1 May 2005 08:58:39 -0700 Subject: [PATCH] drop_buffers() oops fix In rare situations, drop_buffers() can be called for a page which has buffers, but no ->mapping (it was truncated, but the buffers were left behind because ext3 was still fiddling with them). But if there was an I/O error in a buffer_head, drop_buffers() will try to get at the address_space and will oops. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/buffer.c b/fs/buffer.c index 3b12cf9..665db84 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2917,7 +2917,7 @@ drop_buffers(struct page *page, struct buffer_head **buffers_to_free) bh = head; do { - if (buffer_write_io_error(bh)) + if (buffer_write_io_error(bh) && page->mapping) set_bit(AS_EIO, &page->mapping->flags); if (buffer_busy(bh)) goto failed; -- cgit v0.10.2 From 6af963f1d6789ef20abca5696cd52a758b396e52 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Sun, 1 May 2005 08:58:39 -0700 Subject: [PATCH] SELinux: cleanup ipc_has_perm This patch removes the sclass argument from ipc_has_perm in the SELinux module, as it can be obtained from the ipc security structure. The use of a separate argument was a legacy of the older precondition function handling in SELinux and is obsolete. Please apply. Signed-off-by: Stephen Smalley Signed-off-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 0d37814..aae1e79 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3667,7 +3667,7 @@ static void msg_msg_free_security(struct msg_msg *msg) } static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, - u16 sclass, u32 perms) + u32 perms) { struct task_security_struct *tsec; struct ipc_security_struct *isec; @@ -3679,7 +3679,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = ipc_perms->key; - return avc_has_perm(tsec->sid, isec->sid, sclass, perms, &ad); + return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad); } static int selinux_msg_msg_alloc_security(struct msg_msg *msg) @@ -3764,7 +3764,7 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd) return 0; } - err = ipc_has_perm(&msq->q_perm, SECCLASS_MSGQ, perms); + err = ipc_has_perm(&msq->q_perm, perms); return err; } @@ -3916,7 +3916,7 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd) return 0; } - err = ipc_has_perm(&shp->shm_perm, SECCLASS_SHM, perms); + err = ipc_has_perm(&shp->shm_perm, perms); return err; } @@ -3935,7 +3935,7 @@ static int selinux_shm_shmat(struct shmid_kernel *shp, else perms = SHM__READ | SHM__WRITE; - return ipc_has_perm(&shp->shm_perm, SECCLASS_SHM, perms); + return ipc_has_perm(&shp->shm_perm, perms); } /* Semaphore security operations */ @@ -4024,7 +4024,7 @@ static int selinux_sem_semctl(struct sem_array *sma, int cmd) return 0; } - err = ipc_has_perm(&sma->sem_perm, SECCLASS_SEM, perms); + err = ipc_has_perm(&sma->sem_perm, perms); return err; } @@ -4038,18 +4038,13 @@ static int selinux_sem_semop(struct sem_array *sma, else perms = SEM__READ; - return ipc_has_perm(&sma->sem_perm, SECCLASS_SEM, perms); + return ipc_has_perm(&sma->sem_perm, perms); } static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) { - struct ipc_security_struct *isec = ipcp->security; - u16 sclass = SECCLASS_IPC; u32 av = 0; - if (isec && isec->magic == SELINUX_MAGIC) - sclass = isec->sclass; - av = 0; if (flag & S_IRUGO) av |= IPC__UNIX_READ; @@ -4059,7 +4054,7 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) if (av == 0) return 0; - return ipc_has_perm(ipcp, sclass, av); + return ipc_has_perm(ipcp, av); } /* module stacking operations */ -- cgit v0.10.2 From b207a290ea7dc83dba02e40b81cc8a29415a9c60 Mon Sep 17 00:00:00 2001 From: James Morris Date: Sun, 1 May 2005 08:58:40 -0700 Subject: [PATCH] SELinux: add finer grained permissions to Netlink audit processing This patch provides finer grained permissions for the audit family of Netlink sockets under SELinux. 1. We need a way to differentiate between privileged and unprivileged reads of kernel data maintained by the audit subsystem. The AUDIT_GET operation is unprivileged: it returns the current status of the audit subsystem (e.g. whether it's enabled etc.). The AUDIT_LIST operation however returns a list of the current audit ruleset, which is considered privileged by the audit folk. To deal with this, a new SELinux permission has been implemented and applied to the operation: nlmsg_readpriv, which can be allocated to appropriately privileged domains. Unprivileged domains would only be allocated nlmsg_read. 2. There is a requirement for certain domains to generate audit events from userspace. These events need to be collected by the kernel, collated and transmitted sequentially back to the audit daemon. An example is user level login, an auditable event under CAPP, where login-related domains generate AUDIT_USER messages via PAM which are relayed back to auditd via the kernel. To prevent handing out nlmsg_write permissions to such domains, a new permission has been added, nlmsg_relay, which is intended for this type of purpose: data is passed via the kernel back to userspace but no privileged information is written to the kernel. Also, AUDIT_LOGIN messages are now valid only for kernel->user messaging, so this value has been removed from the SELinux nlmsgtab (which is only used to check user->kernel messages). Signed-off-by: James Morris Signed-off-by: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index eb340b4..8928bb4d 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h @@ -220,6 +220,8 @@ S_(SECCLASS_NETLINK_XFRM_SOCKET, NETLINK_XFRM_SOCKET__NLMSG_WRITE, "nlmsg_write") S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READ, "nlmsg_read") S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE, "nlmsg_write") + S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_RELAY, "nlmsg_relay") + S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV, "nlmsg_readpriv") S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_READ, "nlmsg_read") S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_WRITE, "nlmsg_write") S_(SECCLASS_DBUS, DBUS__ACQUIRE_SVC, "acquire_svc") diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index f9de0f9..bdfce4c 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h @@ -840,6 +840,8 @@ #define NETLINK_AUDIT_SOCKET__NLMSG_READ 0x00400000UL #define NETLINK_AUDIT_SOCKET__NLMSG_WRITE 0x00800000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_RELAY 0x01000000UL +#define NETLINK_AUDIT_SOCKET__NLMSG_READPRIV 0x02000000UL #define NETLINK_IP6FW_SOCKET__IOCTL 0x00000001UL #define NETLINK_IP6FW_SOCKET__READ 0x00000002UL diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index f794082..b3adb48 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -91,13 +91,12 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = static struct nlmsg_perm nlmsg_audit_perms[] = { - { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, - { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READ }, - { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_LOGIN, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, + { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV }, + { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, }; -- cgit v0.10.2 From f1c55dea0bb2df94aa2b01b0871cb02f2e206676 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 1 May 2005 08:58:40 -0700 Subject: [PATCH] ppc32: Fix errata for some G3 CPUs Some G3 CPUs can crash in funny way if a store from an FPU register instruction is executed on a register that has never been initialized since power on. This patch fixes it by making sure all FP registers have been properly initialized at kernel boot and when waking from sleep. It also makes the code that decides wether HID0_BTIC and HID0_DPM are allowed on a given CPU smarter (it can actually _clear_ them now if they are not allowed instead of just setting them when they are allowed in case the firmware got them wrong) Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S index 74f781b..468721d 100644 --- a/arch/ppc/kernel/cpu_setup_6xx.S +++ b/arch/ppc/kernel/cpu_setup_6xx.S @@ -30,12 +30,14 @@ _GLOBAL(__setup_cpu_604) blr _GLOBAL(__setup_cpu_750) mflr r4 + bl __init_fpu_registers bl setup_common_caches bl setup_750_7400_hid0 mtlr r4 blr _GLOBAL(__setup_cpu_750cx) mflr r4 + bl __init_fpu_registers bl setup_common_caches bl setup_750_7400_hid0 bl setup_750cx @@ -43,6 +45,7 @@ _GLOBAL(__setup_cpu_750cx) blr _GLOBAL(__setup_cpu_750fx) mflr r4 + bl __init_fpu_registers bl setup_common_caches bl setup_750_7400_hid0 bl setup_750fx @@ -50,6 +53,7 @@ _GLOBAL(__setup_cpu_750fx) blr _GLOBAL(__setup_cpu_7400) mflr r4 + bl __init_fpu_registers bl setup_7400_workarounds bl setup_common_caches bl setup_750_7400_hid0 @@ -57,6 +61,7 @@ _GLOBAL(__setup_cpu_7400) blr _GLOBAL(__setup_cpu_7410) mflr r4 + bl __init_fpu_registers bl setup_7410_workarounds bl setup_common_caches bl setup_750_7400_hid0 @@ -80,7 +85,7 @@ setup_common_caches: bne 1f /* don't invalidate the D-cache */ ori r8,r8,HID0_DCI /* unless it wasn't enabled */ 1: sync - mtspr SPRN_HID0,r8 /* enable and invalidate caches */ + mtspr SPRN_HID0,r8 /* enable and invalidate caches */ sync mtspr SPRN_HID0,r11 /* enable caches */ sync @@ -152,9 +157,13 @@ setup_7410_workarounds: setup_750_7400_hid0: mfspr r11,SPRN_HID0 ori r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC + oris r11,r11,HID0_DPM@h BEGIN_FTR_SECTION - oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ -END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) + xori r11,r11,HID0_BTIC +END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC) +BEGIN_FTR_SECTION + xoris r11,r11,HID0_DPM@h /* disable dynamic power mgmt */ +END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM) li r3,HID0_SPD andc r11,r11,r3 /* clear SPD: enable speculative */ li r3,0 @@ -218,13 +227,15 @@ setup_745x_specifics: /* All of the bits we have to set..... */ - ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_LRSTK | HID0_BTIC + ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE + ori r11,r11,HID0_LRSTK | HID0_BTIC + oris r11,r11,HID0_DPM@h BEGIN_FTR_SECTION xori r11,r11,HID0_BTIC END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC) BEGIN_FTR_SECTION - oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ -END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) + xoris r11,r11,HID0_DPM@h /* disable dynamic power mgmt */ +END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM) /* All of the bits we have to clear.... */ @@ -248,6 +259,25 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) isync blr +/* + * Initialize the FPU registers. This is needed to work around an errata + * in some 750 cpus where using a not yet initialized FPU register after + * power on reset may hang the CPU + */ +_GLOBAL(__init_fpu_registers) + mfmsr r10 + ori r11,r10,MSR_FP + mtmsr r11 + isync + addis r9,r3,empty_zero_page@ha + addi r9,r9,empty_zero_page@l + REST_32FPRS(0,r9) + sync + mtmsr r10 + isync + blr + + /* Definitions for the table use to save CPU states */ #define CS_HID0 0 #define CS_HID1 4 diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S index 3139b67..f459ade 100644 --- a/arch/ppc/platforms/pmac_sleep.S +++ b/arch/ppc/platforms/pmac_sleep.S @@ -267,6 +267,10 @@ grackle_wake_up: /* Restore various CPU config stuffs */ bl __restore_cpu_setup + /* Make sure all FPRs have been initialized */ + bl reloc_offset + bl __init_fpu_registers + /* Invalidate & enable L1 cache, we don't care about * whatever the ROM may have tried to write to memory */ -- cgit v0.10.2 From 443a848cd30eb5bb5c1038e6371d83404775dcfc Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 1 May 2005 08:58:40 -0700 Subject: [PATCH] ppc32: refactor FPU exception handling Moved common FPU exception handling code out of head.S so it can be used by several of the sub-architectures that might of a full PowerPC FPU. Also, uses new CONFIG_PPC_FPU define to fix alignment exception handling for floating point load/store instructions to only occur if we have a hardware FPU. Signed-off-by: Jason McMullan Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 74aa1e9..c3d9413 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -53,6 +53,7 @@ choice config 6xx bool "6xx/7xx/74xx/52xx/82xx/83xx" + select PPC_FPU help There are four types of PowerPC chips supported. The more common types (601, 603, 604, 740, 750, 7400), the Motorola embedded @@ -86,6 +87,9 @@ config E500 endchoice +config PPC_FPU + bool + config BOOKE bool depends on E500 diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 73cbdda..0432a25 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -53,6 +53,7 @@ head-$(CONFIG_FSL_BOOKE) := arch/ppc/kernel/head_fsl_booke.o head-$(CONFIG_6xx) += arch/ppc/kernel/idle_6xx.o head-$(CONFIG_POWER4) += arch/ppc/kernel/idle_power4.o +head-$(CONFIG_PPC_FPU) += arch/ppc/kernel/fpu.o core-y += arch/ppc/kernel/ arch/ppc/platforms/ \ arch/ppc/mm/ arch/ppc/lib/ arch/ppc/syslib/ diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 86bc878..b284451 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -9,6 +9,7 @@ extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o extra-$(CONFIG_8xx) := head_8xx.o extra-$(CONFIG_6xx) += idle_6xx.o extra-$(CONFIG_POWER4) += idle_power4.o +extra-$(CONFIG_PPC_FPU) += fpu.o extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index 79c9294..40d356c 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -368,16 +368,24 @@ fix_alignment(struct pt_regs *regs) /* Single-precision FP load and store require conversions... */ case LD+F+S: +#ifdef CONFIG_PPC_FPU preempt_disable(); enable_kernel_fp(); cvt_fd(&data.f, &data.d, ¤t->thread.fpscr); preempt_enable(); +#else + return 0; +#endif break; case ST+F+S: +#ifdef CONFIG_PPC_FPU preempt_disable(); enable_kernel_fp(); cvt_df(&data.d, &data.f, ¤t->thread.fpscr); preempt_enable(); +#else + return 0; +#endif break; } diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 035217d..5f075db 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -563,6 +563,65 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) addi r1,r1,INT_FRAME_SIZE blr + .globl fast_exception_return +fast_exception_return: +#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) + andi. r10,r9,MSR_RI /* check for recoverable interrupt */ + beq 1f /* if not, we've got problems */ +#endif + +2: REST_4GPRS(3, r11) + lwz r10,_CCR(r11) + REST_GPR(1, r11) + mtcr r10 + lwz r10,_LINK(r11) + mtlr r10 + REST_GPR(10, r11) + mtspr SPRN_SRR1,r9 + mtspr SPRN_SRR0,r12 + REST_GPR(9, r11) + REST_GPR(12, r11) + lwz r11,GPR11(r11) + SYNC + RFI + +#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) +/* check if the exception happened in a restartable section */ +1: lis r3,exc_exit_restart_end@ha + addi r3,r3,exc_exit_restart_end@l + cmplw r12,r3 + bge 3f + lis r4,exc_exit_restart@ha + addi r4,r4,exc_exit_restart@l + cmplw r12,r4 + blt 3f + lis r3,fee_restarts@ha + tophys(r3,r3) + lwz r5,fee_restarts@l(r3) + addi r5,r5,1 + stw r5,fee_restarts@l(r3) + mr r12,r4 /* restart at exc_exit_restart */ + b 2b + + .comm fee_restarts,4 + +/* aargh, a nonrecoverable interrupt, panic */ +/* aargh, we don't know which trap this is */ +/* but the 601 doesn't implement the RI bit, so assume it's OK */ +3: +BEGIN_FTR_SECTION + b 2b +END_FTR_SECTION_IFSET(CPU_FTR_601) + li r10,-1 + stw r10,TRAP(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + lis r10,MSR_KERNEL@h + ori r10,r10,MSR_KERNEL@l + bl transfer_to_handler_full + .long nonrecoverable_exception + .long ret_from_except +#endif + .globl sigreturn_exit sigreturn_exit: subi r1,r3,STACK_FRAME_OVERHEAD diff --git a/arch/ppc/kernel/fpu.S b/arch/ppc/kernel/fpu.S new file mode 100644 index 0000000..6189b26 --- /dev/null +++ b/arch/ppc/kernel/fpu.S @@ -0,0 +1,133 @@ +/* + * FPU support code, moved here from head.S so that it can be used + * by chips which use other head-whatever.S files. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This task wants to use the FPU now. + * On UP, disable FP for the task which had the FPU previously, + * and save its floating-point registers in its thread_struct. + * Load up this task's FP registers from its thread_struct, + * enable the FPU for the current task and return to the task. + */ + .globl load_up_fpu +load_up_fpu: + mfmsr r5 + ori r5,r5,MSR_FP +#ifdef CONFIG_PPC64BRIDGE + clrldi r5,r5,1 /* turn off 64-bit mode */ +#endif /* CONFIG_PPC64BRIDGE */ + SYNC + MTMSRD(r5) /* enable use of fpu now */ + isync +/* + * For SMP, we don't do lazy FPU switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_fpu in switch_to. + */ +#ifndef CONFIG_SMP + tophys(r6,0) /* get __pa constant */ + addis r3,r6,last_task_used_math@ha + lwz r4,last_task_used_math@l(r3) + cmpwi 0,r4,0 + beq 1f + add r4,r4,r6 + addi r4,r4,THREAD /* want last_task_used_math->thread */ + SAVE_32FPRS(0, r4) + mffs fr0 + stfd fr0,THREAD_FPSCR-4(r4) + lwz r5,PT_REGS(r4) + add r5,r5,r6 + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r10,MSR_FP|MSR_FE0|MSR_FE1 + andc r4,r4,r10 /* disable FP for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#endif /* CONFIG_SMP */ + /* enable use of FP after return */ + mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */ + lwz r4,THREAD_FPEXC_MODE(r5) + ori r9,r9,MSR_FP /* enable FP for current */ + or r9,r9,r4 + lfd fr0,THREAD_FPSCR-4(r5) + mtfsf 0xff,fr0 + REST_32FPRS(0, r5) +#ifndef CONFIG_SMP + subi r4,r5,THREAD + sub r4,r4,r6 + stw r4,last_task_used_math@l(r3) +#endif /* CONFIG_SMP */ + /* restore registers and return */ + /* we haven't used ctr or xer or lr */ + b fast_exception_return + +/* + * FP unavailable trap from kernel - print a message, but let + * the task use FP in the kernel until it returns to user mode. + */ + .globl KernelFP +KernelFP: + lwz r3,_MSR(r1) + ori r3,r3,MSR_FP + stw r3,_MSR(r1) /* enable use of FP after return */ + lis r3,86f@h + ori r3,r3,86f@l + mr r4,r2 /* current */ + lwz r5,_NIP(r1) + bl printk + b ret_from_except +86: .string "floating point used in kernel (task=%p, pc=%x)\n" + .align 4,0 + +/* + * giveup_fpu(tsk) + * Disable FP for the task given as the argument, + * and save the floating-point registers in its thread_struct. + * Enables the FPU for use in the kernel on return. + */ + .globl giveup_fpu +giveup_fpu: + mfmsr r5 + ori r5,r5,MSR_FP + SYNC_601 + ISYNC_601 + MTMSRD(r5) /* enable use of fpu now */ + SYNC_601 + isync + cmpwi 0,r3,0 + beqlr- /* if no previous owner, done */ + addi r3,r3,THREAD /* want THREAD of task */ + lwz r5,PT_REGS(r3) + cmpwi 0,r5,0 + SAVE_32FPRS(0, r3) + mffs fr0 + stfd fr0,THREAD_FPSCR-4(r3) + beq 1f + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r3,MSR_FP|MSR_FE0|MSR_FE1 + andc r4,r4,r3 /* disable FP for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#ifndef CONFIG_SMP + li r5,0 + lis r4,last_task_used_math@ha + stw r5,last_task_used_math@l(r4) +#endif /* CONFIG_SMP */ + blr diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 1a89a71..a931d77 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -775,133 +775,6 @@ InstructionSegment: EXC_XFER_STD(0x480, UnknownException) #endif /* CONFIG_PPC64BRIDGE */ -/* - * This task wants to use the FPU now. - * On UP, disable FP for the task which had the FPU previously, - * and save its floating-point registers in its thread_struct. - * Load up this task's FP registers from its thread_struct, - * enable the FPU for the current task and return to the task. - */ -load_up_fpu: - mfmsr r5 - ori r5,r5,MSR_FP -#ifdef CONFIG_PPC64BRIDGE - clrldi r5,r5,1 /* turn off 64-bit mode */ -#endif /* CONFIG_PPC64BRIDGE */ - SYNC - MTMSRD(r5) /* enable use of fpu now */ - isync -/* - * For SMP, we don't do lazy FPU switching because it just gets too - * horrendously complex, especially when a task switches from one CPU - * to another. Instead we call giveup_fpu in switch_to. - */ -#ifndef CONFIG_SMP - tophys(r6,0) /* get __pa constant */ - addis r3,r6,last_task_used_math@ha - lwz r4,last_task_used_math@l(r3) - cmpwi 0,r4,0 - beq 1f - add r4,r4,r6 - addi r4,r4,THREAD /* want last_task_used_math->thread */ - SAVE_32FPRS(0, r4) - mffs fr0 - stfd fr0,THREAD_FPSCR-4(r4) - lwz r5,PT_REGS(r4) - add r5,r5,r6 - lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r10,MSR_FP|MSR_FE0|MSR_FE1 - andc r4,r4,r10 /* disable FP for previous task */ - stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#endif /* CONFIG_SMP */ - /* enable use of FP after return */ - mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */ - lwz r4,THREAD_FPEXC_MODE(r5) - ori r9,r9,MSR_FP /* enable FP for current */ - or r9,r9,r4 - lfd fr0,THREAD_FPSCR-4(r5) - mtfsf 0xff,fr0 - REST_32FPRS(0, r5) -#ifndef CONFIG_SMP - subi r4,r5,THREAD - sub r4,r4,r6 - stw r4,last_task_used_math@l(r3) -#endif /* CONFIG_SMP */ - /* restore registers and return */ - /* we haven't used ctr or xer or lr */ - /* fall through to fast_exception_return */ - - .globl fast_exception_return -fast_exception_return: - andi. r10,r9,MSR_RI /* check for recoverable interrupt */ - beq 1f /* if not, we've got problems */ -2: REST_4GPRS(3, r11) - lwz r10,_CCR(r11) - REST_GPR(1, r11) - mtcr r10 - lwz r10,_LINK(r11) - mtlr r10 - REST_GPR(10, r11) - mtspr SPRN_SRR1,r9 - mtspr SPRN_SRR0,r12 - REST_GPR(9, r11) - REST_GPR(12, r11) - lwz r11,GPR11(r11) - SYNC - RFI - -/* check if the exception happened in a restartable section */ -1: lis r3,exc_exit_restart_end@ha - addi r3,r3,exc_exit_restart_end@l - cmplw r12,r3 - bge 3f - lis r4,exc_exit_restart@ha - addi r4,r4,exc_exit_restart@l - cmplw r12,r4 - blt 3f - lis r3,fee_restarts@ha - tophys(r3,r3) - lwz r5,fee_restarts@l(r3) - addi r5,r5,1 - stw r5,fee_restarts@l(r3) - mr r12,r4 /* restart at exc_exit_restart */ - b 2b - - .comm fee_restarts,4 - -/* aargh, a nonrecoverable interrupt, panic */ -/* aargh, we don't know which trap this is */ -/* but the 601 doesn't implement the RI bit, so assume it's OK */ -3: -BEGIN_FTR_SECTION - b 2b -END_FTR_SECTION_IFSET(CPU_FTR_601) - li r10,-1 - stw r10,TRAP(r11) - addi r3,r1,STACK_FRAME_OVERHEAD - li r10,MSR_KERNEL - bl transfer_to_handler_full - .long nonrecoverable_exception - .long ret_from_except - -/* - * FP unavailable trap from kernel - print a message, but let - * the task use FP in the kernel until it returns to user mode. - */ -KernelFP: - lwz r3,_MSR(r1) - ori r3,r3,MSR_FP - stw r3,_MSR(r1) /* enable use of FP after return */ - lis r3,86f@h - ori r3,r3,86f@l - mr r4,r2 /* current */ - lwz r5,_NIP(r1) - bl printk - b ret_from_except -86: .string "floating point used in kernel (task=%p, pc=%x)\n" - .align 4,0 - #ifdef CONFIG_ALTIVEC /* Note that the AltiVec support is closely modeled after the FP * support. Changes to one are likely to be applicable to the @@ -1016,42 +889,6 @@ giveup_altivec: #endif /* CONFIG_ALTIVEC */ /* - * giveup_fpu(tsk) - * Disable FP for the task given as the argument, - * and save the floating-point registers in its thread_struct. - * Enables the FPU for use in the kernel on return. - */ - .globl giveup_fpu -giveup_fpu: - mfmsr r5 - ori r5,r5,MSR_FP - SYNC_601 - ISYNC_601 - MTMSRD(r5) /* enable use of fpu now */ - SYNC_601 - isync - cmpwi 0,r3,0 - beqlr- /* if no previous owner, done */ - addi r3,r3,THREAD /* want THREAD of task */ - lwz r5,PT_REGS(r3) - cmpwi 0,r5,0 - SAVE_32FPRS(0, r3) - mffs fr0 - stfd fr0,THREAD_FPSCR-4(r3) - beq 1f - lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r3,MSR_FP|MSR_FE0|MSR_FE1 - andc r4,r4,r3 /* disable FP for previous task */ - stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#ifndef CONFIG_SMP - li r5,0 - lis r4,last_task_used_math@ha - stw r5,last_task_used_math@l(r4) -#endif /* CONFIG_SMP */ - blr - -/* * This code is jumped to from the startup code to copy * the kernel image to physical address 0. */ diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S index 9ed8165..9b6a8e5 100644 --- a/arch/ppc/kernel/head_44x.S +++ b/arch/ppc/kernel/head_44x.S @@ -426,7 +426,11 @@ interrupt_base: PROGRAM_EXCEPTION /* Floating Point Unavailable Interrupt */ +#ifdef CONFIG_PPC_FPU + FP_UNAVAILABLE_EXCEPTION +#else EXCEPTION(0x2010, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) +#endif /* System Call Interrupt */ START_EXCEPTION(SystemCall) @@ -686,8 +690,10 @@ _GLOBAL(giveup_altivec) * * The 44x core does not have an FPU. */ +#ifndef CONFIG_PPC_FPU _GLOBAL(giveup_fpu) blr +#endif /* * extern void abort(void) diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h index 884dac9..f213d12 100644 --- a/arch/ppc/kernel/head_booke.h +++ b/arch/ppc/kernel/head_booke.h @@ -337,4 +337,11 @@ label: addi r3,r1,STACK_FRAME_OVERHEAD; \ EXC_XFER_LITE(0x0900, timer_interrupt) +#define FP_UNAVAILABLE_EXCEPTION \ + START_EXCEPTION(FloatingPointUnavailable) \ + NORMAL_EXCEPTION_PROLOG; \ + bne load_up_fpu; /* if from user, just load it up */ \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_EE_LITE(0x800, KernelFP) + #endif /* __HEAD_BOOKE_H__ */ diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S index d64bf61..f22ddce 100644 --- a/arch/ppc/kernel/head_fsl_booke.S +++ b/arch/ppc/kernel/head_fsl_booke.S @@ -504,7 +504,11 @@ interrupt_base: PROGRAM_EXCEPTION /* Floating Point Unavailable Interrupt */ +#ifdef CONFIG_PPC_FPU + FP_UNAVAILABLE_EXCEPTION +#else EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) +#endif /* System Call Interrupt */ START_EXCEPTION(SystemCall) @@ -916,10 +920,12 @@ _GLOBAL(giveup_spe) /* * extern void giveup_fpu(struct task_struct *prev) * - * The e500 core does not have an FPU. + * Not all FSL Book-E cores have an FPU */ +#ifndef CONFIG_PPC_FPU _GLOBAL(giveup_fpu) blr +#endif /* * extern void abort(void) diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 73f7c23..e4f1615 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -1096,17 +1096,7 @@ _GLOBAL(_get_SP) * and exceptions as if the cpu had performed the load or store. */ -#if defined(CONFIG_4xx) || defined(CONFIG_E500) -_GLOBAL(cvt_fd) - lfs 0,0(r3) - stfd 0,0(r4) - blr - -_GLOBAL(cvt_df) - lfd 0,0(r3) - stfs 0,0(r4) - blr -#else +#ifdef CONFIG_PPC_FPU _GLOBAL(cvt_fd) lfd 0,-4(r5) /* load up fpscr value */ mtfsf 0xff,0 diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 361865c..f8e7e32 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -176,7 +176,7 @@ static inline int check_io_access(struct pt_regs *regs) #else #define get_mc_reason(regs) (mfspr(SPRN_MCSR)) #endif -#define REASON_FP 0 +#define REASON_FP ESR_FP #define REASON_ILLEGAL ESR_PIL #define REASON_PRIVILEGED ESR_PPR #define REASON_TRAP ESR_PTR diff --git a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h index e70c25f..45c5e6f 100644 --- a/include/asm-ppc/reg_booke.h +++ b/include/asm-ppc/reg_booke.h @@ -305,6 +305,7 @@ do { \ #define ESR_PIL 0x08000000 /* Program Exception - Illegal */ #define ESR_PPR 0x04000000 /* Program Exception - Priveleged */ #define ESR_PTR 0x02000000 /* Program Exception - Trap */ +#define ESR_FP 0x01000000 /* Floating Point Operation */ #define ESR_DST 0x00800000 /* Storage Exception - Data miss */ #define ESR_DIZ 0x00400000 /* Storage Exception - Zone fault */ #define ESR_ST 0x00800000 /* Store Operation */ -- cgit v0.10.2 From 630710e3f72b6a324a525f6e5db3f7985d0fc4a2 Mon Sep 17 00:00:00 2001 From: Chris Elston Date: Sun, 1 May 2005 08:58:40 -0700 Subject: [PATCH] ppc32: fix for misreported SDRAM size on Radstone PPC7D platform This patch fixes the SDRAM output from /proc/cpuinfo. The previous code assumed that there was only one bank of SDRAM, and that the size in the memory configuration register was the total size. Signed-off-by: Chris Elston Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c index 2a99b43..df2ea05 100644 --- a/arch/ppc/platforms/radstone_ppc7d.c +++ b/arch/ppc/platforms/radstone_ppc7d.c @@ -253,6 +253,8 @@ static int ppc7d_show_cpuinfo(struct seq_file *m) u8 val1, val2; static int flash_sizes[4] = { 64, 32, 0, 16 }; static int flash_banks[4] = { 4, 3, 2, 1 }; + static int sdram_bank_sizes[4] = { 128, 256, 512, 1 }; + int sdram_num_banks = 2; static char *pci_modes[] = { "PCI33", "PCI66", "Unknown", "Unknown", "PCIX33", "PCIX66", @@ -279,13 +281,17 @@ static int ppc7d_show_cpuinfo(struct seq_file *m) (val1 == PPC7D_CPLD_MB_TYPE_PLL_100) ? 100 : (val1 == PPC7D_CPLD_MB_TYPE_PLL_64) ? 64 : 0); + val = inb(PPC7D_CPLD_MEM_CONFIG); + if (val & PPC7D_CPLD_SDRAM_BANK_NUM_MASK) sdram_num_banks--; + val = inb(PPC7D_CPLD_MEM_CONFIG_EXTEND); - val1 = val & PPC7D_CPLD_SDRAM_BANK_SIZE_MASK; - seq_printf(m, "SDRAM\t\t: %d%c", - (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_128M) ? 128 : - (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_256M) ? 256 : - (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_512M) ? 512 : 1, - (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_1G) ? 'G' : 'M'); + val1 = (val & PPC7D_CPLD_SDRAM_BANK_SIZE_MASK) >> 6; + seq_printf(m, "SDRAM\t\t: %d banks of %d%c, total %d%c", + sdram_num_banks, + sdram_bank_sizes[val1], + (sdram_bank_sizes[val1] < 128) ? 'G' : 'M', + sdram_num_banks * sdram_bank_sizes[val1], + (sdram_bank_sizes[val1] < 128) ? 'G' : 'M'); if (val2 & PPC7D_CPLD_MB_TYPE_ECC_FITTED_MASK) { seq_printf(m, " [ECC %sabled]", (val2 & PPC7D_CPLD_MB_TYPE_ECC_ENABLE_MASK) ? "en" : diff --git a/arch/ppc/platforms/radstone_ppc7d.h b/arch/ppc/platforms/radstone_ppc7d.h index 4546fff2..9383755 100644 --- a/arch/ppc/platforms/radstone_ppc7d.h +++ b/arch/ppc/platforms/radstone_ppc7d.h @@ -240,6 +240,7 @@ #define PPC7D_CPLD_FLASH_CNTL 0x086E /* MEMORY_CONFIG_EXTEND */ +#define PPC7D_CPLD_SDRAM_BANK_NUM_MASK 0x02 #define PPC7D_CPLD_SDRAM_BANK_SIZE_MASK 0xc0 #define PPC7D_CPLD_SDRAM_BANK_SIZE_128M 0 #define PPC7D_CPLD_SDRAM_BANK_SIZE_256M 0x40 -- cgit v0.10.2 From a497aa20e5ea54fdee474192d6dc138b4832fc9e Mon Sep 17 00:00:00 2001 From: Chris Elston Date: Sun, 1 May 2005 08:58:41 -0700 Subject: [PATCH] ppc32: add rtc hooks in PPC7D platform file This patch adds the hooks into the PPC7D platforms file to support the DS1337 RTC device as the clock device for the PPC7D board. Signed-off-by: Chris Elston Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c index df2ea05..c30607a 100644 --- a/arch/ppc/platforms/radstone_ppc7d.c +++ b/arch/ppc/platforms/radstone_ppc7d.c @@ -68,6 +68,7 @@ #define PPC7D_RST_PIN 17 /* GPP17 */ extern u32 mv64360_irq_base; +extern spinlock_t rtc_lock; static struct mv64x60_handle bh; static int ppc7d_has_alma; @@ -75,6 +76,11 @@ static int ppc7d_has_alma; extern void gen550_progress(char *, unsigned short); extern void gen550_init(int, struct uart_port *); +/* FIXME - move to h file */ +extern int ds1337_do_command(int id, int cmd, void *arg); +#define DS1337_GET_DATE 0 +#define DS1337_SET_DATE 1 + /* residual data */ unsigned char __res[sizeof(bd_t)]; @@ -1242,6 +1248,38 @@ static void __init ppc7d_setup_arch(void) printk(KERN_INFO "Radstone Technology PPC7D\n"); if (ppc_md.progress) ppc_md.progress("ppc7d_setup_arch: exit", 0); + +} + +/* Real Time Clock support. + * PPC7D has a DS1337 accessed by I2C. + */ +static ulong ppc7d_get_rtc_time(void) +{ + struct rtc_time tm; + int result; + + spin_lock(&rtc_lock); + result = ds1337_do_command(0, DS1337_GET_DATE, &tm); + spin_unlock(&rtc_lock); + + if (result == 0) + result = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + + return result; +} + +static int ppc7d_set_rtc_time(unsigned long nowtime) +{ + struct rtc_time tm; + int result; + + spin_lock(&rtc_lock); + to_tm(nowtime, &tm); + result = ds1337_do_command(0, DS1337_SET_DATE, &tm); + spin_unlock(&rtc_lock); + + return result; } /* This kernel command line parameter can be used to have the target @@ -1299,6 +1337,10 @@ static void ppc7d_init2(void) data8 |= 0x07; outb(data8, PPC7D_CPLD_LEDS); + /* Hook up RTC. We couldn't do this earlier because we need the I2C subsystem */ + ppc_md.set_rtc_time = ppc7d_set_rtc_time; + ppc_md.get_rtc_time = ppc7d_get_rtc_time; + pr_debug("%s: exit\n", __FUNCTION__); } -- cgit v0.10.2 From 616299afcebfb2228f45a95aac7e63704c3733fc Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 1 May 2005 08:58:41 -0700 Subject: [PATCH] ppc32: Fix IDE related crash on wakeup I noticed an occasional crash on wakeup from sleep on my powerbook (strangly never happened before, probably timing related) that appears to be due to a dangling interrupt while the chip is put to sleep and beeing reset on wakeup. This patch fixes is by disabling the irq in the ide pmac driver while asleep and only re-enable it after the chip has been fully reset. This is safe to do so as the interrupt of these apple IDE cells is never shared. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 6dc273a..569f167 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1204,6 +1204,8 @@ pmac_ide_do_suspend(ide_hwif_t *hwif) } #endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */ + disable_irq(pmif->irq); + /* The media bay will handle itself just fine */ if (pmif->mediabay) return 0; @@ -1236,7 +1238,6 @@ pmac_ide_do_resume(ide_hwif_t *hwif) ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1); msleep(10); ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 0); - msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY)); /* Kauai has it different */ if (pmif->kauai_fcr) { @@ -1244,11 +1245,15 @@ pmac_ide_do_resume(ide_hwif_t *hwif) fcr |= KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE; writel(fcr, pmif->kauai_fcr); } + + msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY)); } /* Sanitize drive timings */ sanitize_timings(pmif); + enable_irq(pmif->irq); + return 0; } -- cgit v0.10.2 From 146a4b3bdfb5641bfbf975e29680b482b8b343ba Mon Sep 17 00:00:00 2001 From: Andreas Jaggi Date: Sun, 1 May 2005 08:58:41 -0700 Subject: [PATCH] macintosh/adbhid.c: adb buttons support for aluminium PowerBook G4 This patch adds support for the special adb buttons of the aluminium PowerBook G4. Signed-off-by: Andreas Jaggi Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index 8f93d01..db654e8 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -555,6 +555,42 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto #endif /* CONFIG_PMAC_BACKLIGHT */ input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSUP, down); break; + + case 0xc: /* videomode switch */ + input_report_key(&adbhid[id]->input, KEY_SWITCHVIDEOMODE, down); + break; + + case 0xd: /* keyboard illumination toggle */ + input_report_key(&adbhid[id]->input, KEY_KBDILLUMTOGGLE, down); + break; + + case 0xe: /* keyboard illumination decrease */ + input_report_key(&adbhid[id]->input, KEY_KBDILLUMDOWN, down); + break; + + case 0xf: + switch (data[1]) { + case 0x8f: + case 0x0f: + /* keyboard illumination increase */ + input_report_key(&adbhid[id]->input, KEY_KBDILLUMUP, down); + break; + + case 0x7f: + case 0xff: + /* keypad overlay toogle */ + break; + + default: + printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", + data[0], data[1], data[2], data[3]); + break; + } + break; + default: + printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", + data[0], data[1], data[2], data[3]); + break; } } break; @@ -775,6 +811,10 @@ adbhid_input_register(int id, int default_id, int original_handler_id, set_bit(KEY_BRIGHTNESSUP, adbhid[id]->input.keybit); set_bit(KEY_BRIGHTNESSDOWN, adbhid[id]->input.keybit); set_bit(KEY_EJECTCD, adbhid[id]->input.keybit); + set_bit(KEY_SWITCHVIDEOMODE, adbhid[id]->input.keybit); + set_bit(KEY_KBDILLUMTOGGLE, adbhid[id]->input.keybit); + set_bit(KEY_KBDILLUMDOWN, adbhid[id]->input.keybit); + set_bit(KEY_KBDILLUMUP, adbhid[id]->input.keybit); break; } if (adbhid[id]->name[0]) diff --git a/include/linux/input.h b/include/linux/input.h index b70df8f..72731d7 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -328,6 +328,11 @@ struct input_absinfo { #define KEY_BRIGHTNESSUP 225 #define KEY_MEDIA 226 +#define KEY_SWITCHVIDEOMODE 227 +#define KEY_KBDILLUMTOGGLE 228 +#define KEY_KBDILLUMDOWN 229 +#define KEY_KBDILLUMUP 230 + #define KEY_UNKNOWN 240 #define BTN_MISC 0x100 -- cgit v0.10.2 From b20cc8aff258eea5a2339107605ebea949fa6ecf Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 1 May 2005 08:58:42 -0700 Subject: [PATCH] ppc32: Fix a sleep issues on some laptops Some earlier models of aluminium powerbooks and ibook G4s have a clock chip that requires some tweaking before and after sleep. It seems that without that magic incantation to disable and re-enable clock spreading, RAM isn't properly refreshed during sleep. This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c index 46cbf36..be41f6f 100644 --- a/arch/ppc/platforms/pmac_feature.c +++ b/arch/ppc/platforms/pmac_feature.c @@ -1590,6 +1590,112 @@ intrepid_shutdown(struct macio_chip* macio, int sleep_mode) mdelay(10); } + +static void __pmac pmac_tweak_clock_spreading(struct macio_chip* macio, int enable) +{ + /* Hack for doing clock spreading on some machines PowerBooks and + * iBooks. This implements the "platform-do-clockspreading" OF + * property as decoded manually on various models. For safety, we also + * check the product ID in the device-tree in cases we'll whack the i2c + * chip to make reasonably sure we won't set wrong values in there + * + * Of course, ultimately, we have to implement a real parser for + * the platform-do-* stuff... + */ + + if (macio->type == macio_intrepid) { + if (enable) + UN_OUT(UNI_N_CLOCK_SPREADING, 2); + else + UN_OUT(UNI_N_CLOCK_SPREADING, 0); + mdelay(40); + } + + while (machine_is_compatible("PowerBook5,2") || + machine_is_compatible("PowerBook5,3") || + machine_is_compatible("PowerBook6,2") || + machine_is_compatible("PowerBook6,3")) { + struct device_node *ui2c = of_find_node_by_type(NULL, "i2c"); + struct device_node *dt = of_find_node_by_name(NULL, "device-tree"); + u8 buffer[9]; + u32 *productID; + int i, rc, changed = 0; + + if (dt == NULL) + break; + productID = (u32 *)get_property(dt, "pid#", NULL); + if (productID == NULL) + break; + while(ui2c) { + struct device_node *p = of_get_parent(ui2c); + if (p && !strcmp(p->name, "uni-n")) + break; + ui2c = of_find_node_by_type(ui2c, "i2c"); + } + if (ui2c == NULL) + break; + DBG("Trying to bump clock speed for PID: %08x...\n", *productID); + rc = pmac_low_i2c_open(ui2c, 1); + if (rc != 0) + break; + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); + DBG("read result: %d,", rc); + if (rc != 0) { + pmac_low_i2c_close(ui2c); + break; + } + for (i=0; i<9; i++) + DBG(" %02x", buffer[i]); + DBG("\n"); + + switch(*productID) { + case 0x1182: /* AlBook 12" rev 2 */ + case 0x1183: /* iBook G4 12" */ + buffer[0] = (buffer[0] & 0x8f) | 0x70; + buffer[2] = (buffer[2] & 0x7f) | 0x00; + buffer[5] = (buffer[5] & 0x80) | 0x31; + buffer[6] = (buffer[6] & 0x40) | 0xb0; + buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba); + buffer[8] = (buffer[8] & 0x00) | 0x30; + changed = 1; + break; + case 0x3142: /* AlBook 15" (ATI M10) */ + case 0x3143: /* AlBook 17" (ATI M10) */ + buffer[0] = (buffer[0] & 0xaf) | 0x50; + buffer[2] = (buffer[2] & 0x7f) | 0x00; + buffer[5] = (buffer[5] & 0x80) | 0x31; + buffer[6] = (buffer[6] & 0x40) | 0xb0; + buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0); + buffer[8] = (buffer[8] & 0x00) | 0x30; + changed = 1; + break; + default: + DBG("i2c-hwclock: Machine model not handled\n"); + break; + } + if (!changed) { + pmac_low_i2c_close(ui2c); + break; + } + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9); + DBG("write result: %d,", rc); + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); + DBG("read result: %d,", rc); + if (rc != 0) { + pmac_low_i2c_close(ui2c); + break; + } + for (i=0; i<9; i++) + DBG(" %02x", buffer[i]); + pmac_low_i2c_close(ui2c); + break; + } +} + + static int __pmac core99_sleep(void) { @@ -1601,11 +1707,8 @@ core99_sleep(void) macio->type != macio_intrepid) return -ENODEV; - /* The device-tree contains that in the hwclock node */ - if (macio->type == macio_intrepid) { - UN_OUT(UNI_N_CLOCK_SPREADING, 0); - mdelay(40); - } + /* Disable clock spreading */ + pmac_tweak_clock_spreading(macio, 0); /* We power off the wireless slot in case it was not done * by the driver. We don't power it on automatically however @@ -1749,11 +1852,8 @@ core99_wake_up(void) UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl); udelay(100); - /* Restore clock spreading */ - if (macio->type == macio_intrepid) { - UN_OUT(UNI_N_CLOCK_SPREADING, 2); - mdelay(40); - } + /* Enable clock spreading */ + pmac_tweak_clock_spreading(macio, 1); return 0; } @@ -2718,97 +2818,11 @@ set_initial_features(void) MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); } - /* Hack for bumping clock speed on the new PowerBooks and the - * iBook G4. This implements the "platform-do-clockspreading" OF - * property. For safety, we also check the product ID in the - * device-tree to make reasonably sure we won't set wrong values - * in the clock chip. - * - * Of course, ultimately, we have to implement a real parser for - * the platform-do-* stuff... + /* Some machine models need the clock chip to be properly setup for + * clock spreading now. This should be a platform function but we + * don't do these at the moment */ - while (machine_is_compatible("PowerBook5,2") || - machine_is_compatible("PowerBook5,3") || - machine_is_compatible("PowerBook6,2") || - machine_is_compatible("PowerBook6,3")) { - struct device_node *ui2c = of_find_node_by_type(NULL, "i2c"); - struct device_node *dt = of_find_node_by_name(NULL, "device-tree"); - u8 buffer[9]; - u32 *productID; - int i, rc, changed = 0; - - if (dt == NULL) - break; - productID = (u32 *)get_property(dt, "pid#", NULL); - if (productID == NULL) - break; - while(ui2c) { - struct device_node *p = of_get_parent(ui2c); - if (p && !strcmp(p->name, "uni-n")) - break; - ui2c = of_find_node_by_type(ui2c, "i2c"); - } - if (ui2c == NULL) - break; - DBG("Trying to bump clock speed for PID: %08x...\n", *productID); - rc = pmac_low_i2c_open(ui2c, 1); - if (rc != 0) - break; - pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); - rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); - DBG("read result: %d,", rc); - if (rc != 0) { - pmac_low_i2c_close(ui2c); - break; - } - for (i=0; i<9; i++) - DBG(" %02x", buffer[i]); - DBG("\n"); - - switch(*productID) { - case 0x1182: /* AlBook 12" rev 2 */ - case 0x1183: /* iBook G4 12" */ - buffer[0] = (buffer[0] & 0x8f) | 0x70; - buffer[2] = (buffer[2] & 0x7f) | 0x00; - buffer[5] = (buffer[5] & 0x80) | 0x31; - buffer[6] = (buffer[6] & 0x40) | 0xb0; - buffer[7] = (buffer[7] & 0x00) | 0xc0; - buffer[8] = (buffer[8] & 0x00) | 0x30; - changed = 1; - break; - case 0x3142: /* AlBook 15" (ATI M10) */ - case 0x3143: /* AlBook 17" (ATI M10) */ - buffer[0] = (buffer[0] & 0xaf) | 0x50; - buffer[2] = (buffer[2] & 0x7f) | 0x00; - buffer[5] = (buffer[5] & 0x80) | 0x31; - buffer[6] = (buffer[6] & 0x40) | 0xb0; - buffer[7] = (buffer[7] & 0x00) | 0xd0; - buffer[8] = (buffer[8] & 0x00) | 0x30; - changed = 1; - break; - default: - DBG("i2c-hwclock: Machine model not handled\n"); - break; - } - if (!changed) { - pmac_low_i2c_close(ui2c); - break; - } - pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub); - rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9); - DBG("write result: %d,", rc); - pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); - rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); - DBG("read result: %d,", rc); - if (rc != 0) { - pmac_low_i2c_close(ui2c); - break; - } - for (i=0; i<9; i++) - DBG(" %02x", buffer[i]); - pmac_low_i2c_close(ui2c); - break; - } + pmac_tweak_clock_spreading(&macio_chips[0], 1); #endif /* CONFIG_POWER4 */ -- cgit v0.10.2 From d5812a77e5803468a5033be91af978be0f7a17d9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 1 May 2005 08:58:42 -0700 Subject: [PATCH] ppc32: Fix address checking on lmw/stmw align exception The handling of misaligned load/store multiple instructions did not check to see if the address was ok to access before using __{get,put}_user(). Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index 40d356c..ff81da9 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -290,6 +290,10 @@ fix_alignment(struct pt_regs *regs) /* lwm, stmw */ nb = (32 - reg) * 4; } + + if (!access_ok((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb+nb0)) + return -EFAULT; /* bad address */ + rptr = (unsigned char *) ®s->gpr[reg]; if (flags & LD) { for (i = 0; i < nb; ++i) -- cgit v0.10.2 From 1bdacf88ebd7969fecbbf4c5b388cc094871222e Mon Sep 17 00:00:00 2001 From: Dan Malek Date: Sun, 1 May 2005 08:58:42 -0700 Subject: [PATCH] ppc32: workaround for spurious IRQs on PQ2 There is a problem with large amounts of spurious IRQs on PowerPC 82xx systems. The problem is corrected by adding sync at the end of cpm2_mask_and_ack. This may be needed on 8xx as well but has not yet been confirmed. Signed-off-by: Eugene Surovegin Signed-off-by: Dan Malek Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c index 954b07f..c867be6 100644 --- a/arch/ppc/syslib/cpm2_pic.c +++ b/arch/ppc/syslib/cpm2_pic.c @@ -107,6 +107,11 @@ static void cpm2_end_irq(unsigned int irq_nr) simr = &(cpm2_immr->im_intctl.ic_simrh); ppc_cached_irq_mask[word] |= 1 << bit; simr[word] = ppc_cached_irq_mask[word]; + /* + * Work around large numbers of spurious IRQs on PowerPC 82xx + * systems. + */ + mb(); } } -- cgit v0.10.2 From 4be8dc7ff69182610b40a078b9815bcdf27e0c49 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 1 May 2005 08:58:43 -0700 Subject: [PATCH] ppc64: improve g5 sound headphone mute This patch fixes a couple more issues with the management of the GPIOs dealing with headphone and line out mute on the G5. It should fix the remaining problems of people not getting any sound out of the headphone jack. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index c71807e..f3e0107 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -177,11 +177,22 @@ static void write_audio_gpio(pmac_gpio_t *gp, int active) if (! gp->addr) return; active = active ? gp->active_val : gp->inactive_val; - do_gpio_write(gp, active); DBG("(I) gpio %x write %d\n", gp->addr, active); } +static int check_audio_gpio(pmac_gpio_t *gp) +{ + int ret; + + if (! gp->addr) + return 0; + + ret = do_gpio_read(gp); + + return (ret & 0xd) == (gp->active_val & 0xd); +} + static int read_audio_gpio(pmac_gpio_t *gp) { int ret; @@ -683,7 +694,7 @@ static int tumbler_get_mute_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_ } if (gp == NULL) return -EINVAL; - ucontrol->value.integer.value[0] = ! read_audio_gpio(gp); + ucontrol->value.integer.value[0] = !check_audio_gpio(gp); return 0; } @@ -711,7 +722,7 @@ static int tumbler_put_mute_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_ } if (gp == NULL) return -EINVAL; - val = ! read_audio_gpio(gp); + val = ! check_audio_gpio(gp); if (val != ucontrol->value.integer.value[0]) { write_audio_gpio(gp, ! ucontrol->value.integer.value[0]); return 1; @@ -897,11 +908,11 @@ static int tumbler_detect_lineout(pmac_t *chip) static void check_mute(pmac_t *chip, pmac_gpio_t *gp, int val, int do_notify, snd_kcontrol_t *sw) { - //pmac_tumbler_t *mix = chip->mixer_data; - if (val != read_audio_gpio(gp)) { + if (check_audio_gpio(gp) != val) { write_audio_gpio(gp, val); if (do_notify) - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &sw->id); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &sw->id); } } -- cgit v0.10.2 From 1f7b49d042abfbda71f41b8aff6e1bf7685c1f00 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 1 May 2005 08:58:43 -0700 Subject: [PATCH] ppc32: add sound support for Mac Mini This patch applies on top of my previous g5 related sound patches and adds support for the Mac Mini to the PowerMac Alsa driver. However, I haven't found any kind of HW support for volume control on this machine. If it exist, it's well hidden. That means that you probably want to make sure you use software with the ability to do soft volume control, or use Alsa 0.9 pre-release with the softvol plugin. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile index 4d95c65..d6ba995 100644 --- a/sound/ppc/Makefile +++ b/sound/ppc/Makefile @@ -3,7 +3,7 @@ # Copyright (c) 2001 by Jaroslav Kysela # -snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o +snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o toonie.o keywest.o beep.o # Toplevel Module Dependency obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 3bf5f06..32d9475 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -986,7 +986,13 @@ static int __init snd_pmac_detect(pmac_t *chip) chip->num_freqs = ARRAY_SIZE(tumbler_freqs); chip->model = PMAC_SNAPPER; chip->can_byte_swap = 0; /* FIXME: check this */ - chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ + chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */ + break; + case 0x3a: + chip->num_freqs = ARRAY_SIZE(tumbler_freqs); + chip->model = PMAC_TOONIE; + chip->can_byte_swap = 0; /* FIXME: check this */ + chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */ break; } } diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h index dc6c99d..0a84c05 100644 --- a/sound/ppc/pmac.h +++ b/sound/ppc/pmac.h @@ -94,7 +94,8 @@ struct snd_pmac_stream { */ enum snd_pmac_model { - PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER, PMAC_SNAPPER + PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER, + PMAC_SNAPPER, PMAC_TOONIE }; struct snd_pmac { @@ -191,6 +192,7 @@ int snd_pmac_burgundy_init(pmac_t *chip); int snd_pmac_daca_init(pmac_t *chip); int snd_pmac_tumbler_init(pmac_t *chip); int snd_pmac_tumbler_post_init(void); +int snd_pmac_toonie_init(pmac_t *chip); /* i2c functions */ typedef struct snd_pmac_keywest { diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c index 8f1953a..231f643 100644 --- a/sound/ppc/powermac.c +++ b/sound/ppc/powermac.c @@ -95,6 +95,13 @@ static int __init snd_pmac_probe(void) if ( snd_pmac_tumbler_init(chip) < 0 || snd_pmac_tumbler_post_init() < 0) goto __error; break; + case PMAC_TOONIE: + strcpy(card->driver, "PMac Toonie"); + strcpy(card->shortname, "PowerMac Toonie"); + strcpy(card->longname, card->shortname); + if ((err = snd_pmac_toonie_init(chip)) < 0) + goto __error; + break; case PMAC_AWACS: case PMAC_SCREAMER: name_ext = chip->model == PMAC_SCREAMER ? "Screamer" : "AWACS"; diff --git a/sound/ppc/toonie.c b/sound/ppc/toonie.c new file mode 100644 index 0000000..0f90919 --- /dev/null +++ b/sound/ppc/toonie.c @@ -0,0 +1,380 @@ +/* + * Mac Mini "toonie" mixer control + * + * Copyright (c) 2005 by Benjamin Herrenschmidt + * + * 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 +#include +#include +#include +#include +#include +#include "pmac.h" + +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt...) printk(fmt) +#else +#define DBG(fmt...) +#endif + +struct pmac_gpio { + unsigned int addr; + u8 active_val; + u8 inactive_val; + u8 active_state; +}; + +struct pmac_toonie +{ + struct pmac_gpio hp_detect_gpio; + struct pmac_gpio hp_mute_gpio; + struct pmac_gpio amp_mute_gpio; + int hp_detect_irq; + int auto_mute_notify; + struct work_struct detect_work; +}; + + +/* + * gpio access + */ +#define do_gpio_write(gp, val) \ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, (gp)->addr, val) +#define do_gpio_read(gp) \ + pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, (gp)->addr, 0) +#define tumbler_gpio_free(gp) /* NOP */ + +static void write_audio_gpio(struct pmac_gpio *gp, int active) +{ + if (! gp->addr) + return; + active = active ? gp->active_val : gp->inactive_val; + do_gpio_write(gp, active); + DBG("(I) gpio %x write %d\n", gp->addr, active); +} + +static int check_audio_gpio(struct pmac_gpio *gp) +{ + int ret; + + if (! gp->addr) + return 0; + + ret = do_gpio_read(gp); + + return (ret & 0xd) == (gp->active_val & 0xd); +} + +static int read_audio_gpio(struct pmac_gpio *gp) +{ + int ret; + if (! gp->addr) + return 0; + ret = ((do_gpio_read(gp) & 0x02) !=0); + return ret == gp->active_state; +} + + +enum { TOONIE_MUTE_HP, TOONIE_MUTE_AMP }; + +static int toonie_get_mute_switch(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + pmac_t *chip = snd_kcontrol_chip(kcontrol); + struct pmac_toonie *mix = chip->mixer_data; + struct pmac_gpio *gp; + + if (mix == NULL) + return -ENODEV; + switch(kcontrol->private_value) { + case TOONIE_MUTE_HP: + gp = &mix->hp_mute_gpio; + break; + case TOONIE_MUTE_AMP: + gp = &mix->amp_mute_gpio; + break; + default: + return -EINVAL;; + } + ucontrol->value.integer.value[0] = !check_audio_gpio(gp); + return 0; +} + +static int toonie_put_mute_switch(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + pmac_t *chip = snd_kcontrol_chip(kcontrol); + struct pmac_toonie *mix = chip->mixer_data; + struct pmac_gpio *gp; + int val; + + if (chip->update_automute && chip->auto_mute) + return 0; /* don't touch in the auto-mute mode */ + + if (mix == NULL) + return -ENODEV; + + switch(kcontrol->private_value) { + case TOONIE_MUTE_HP: + gp = &mix->hp_mute_gpio; + break; + case TOONIE_MUTE_AMP: + gp = &mix->amp_mute_gpio; + break; + default: + return -EINVAL;; + } + val = ! check_audio_gpio(gp); + if (val != ucontrol->value.integer.value[0]) { + write_audio_gpio(gp, ! ucontrol->value.integer.value[0]); + return 1; + } + return 0; +} + +static snd_kcontrol_new_t toonie_hp_sw __initdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphone Playback Switch", + .info = snd_pmac_boolean_mono_info, + .get = toonie_get_mute_switch, + .put = toonie_put_mute_switch, + .private_value = TOONIE_MUTE_HP, +}; +static snd_kcontrol_new_t toonie_speaker_sw __initdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PC Speaker Playback Switch", + .info = snd_pmac_boolean_mono_info, + .get = toonie_get_mute_switch, + .put = toonie_put_mute_switch, + .private_value = TOONIE_MUTE_AMP, +}; + +/* + * auto-mute stuffs + */ +static int toonie_detect_headphone(pmac_t *chip) +{ + struct pmac_toonie *mix = chip->mixer_data; + int detect = 0; + + if (mix->hp_detect_gpio.addr) + detect |= read_audio_gpio(&mix->hp_detect_gpio); + return detect; +} + +static void toonie_check_mute(pmac_t *chip, struct pmac_gpio *gp, int val, + int do_notify, snd_kcontrol_t *sw) +{ + if (check_audio_gpio(gp) != val) { + write_audio_gpio(gp, val); + if (do_notify) + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &sw->id); + } +} + +static void toonie_detect_handler(void *self) +{ + pmac_t *chip = (pmac_t*) self; + struct pmac_toonie *mix; + int headphone; + + if (!chip) + return; + + mix = chip->mixer_data; + snd_assert(mix, return); + + headphone = toonie_detect_headphone(chip); + + DBG("headphone: %d, lineout: %d\n", headphone, lineout); + + if (headphone) { + /* unmute headphone/lineout & mute speaker */ + toonie_check_mute(chip, &mix->hp_mute_gpio, 0, + mix->auto_mute_notify, chip->master_sw_ctl); + toonie_check_mute(chip, &mix->amp_mute_gpio, 1, + mix->auto_mute_notify, chip->speaker_sw_ctl); + } else { + /* unmute speaker, mute others */ + toonie_check_mute(chip, &mix->amp_mute_gpio, 0, + mix->auto_mute_notify, chip->speaker_sw_ctl); + toonie_check_mute(chip, &mix->hp_mute_gpio, 1, + mix->auto_mute_notify, chip->master_sw_ctl); + } + if (mix->auto_mute_notify) { + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->hp_detect_ctl->id); + } +} + +static void toonie_update_automute(pmac_t *chip, int do_notify) +{ + if (chip->auto_mute) { + struct pmac_toonie *mix; + mix = chip->mixer_data; + snd_assert(mix, return); + mix->auto_mute_notify = do_notify; + schedule_work(&mix->detect_work); + } +} + +/* interrupt - headphone plug changed */ +static irqreturn_t toonie_hp_intr(int irq, void *devid, struct pt_regs *regs) +{ + pmac_t *chip = devid; + + if (chip->update_automute && chip->initialized) { + chip->update_automute(chip, 1); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +/* look for audio gpio device */ +static int find_audio_gpio(const char *name, const char *platform, + struct pmac_gpio *gp) +{ + struct device_node *np; + u32 *base, addr; + + if (! (np = find_devices("gpio"))) + return -ENODEV; + + for (np = np->child; np; np = np->sibling) { + char *property = get_property(np, "audio-gpio", NULL); + if (property && strcmp(property, name) == 0) + break; + if (device_is_compatible(np, name)) + break; + } + if (np == NULL) + return -ENODEV; + + base = (u32 *)get_property(np, "AAPL,address", NULL); + if (! base) { + base = (u32 *)get_property(np, "reg", NULL); + if (!base) { + DBG("(E) cannot find address for device %s !\n", device); + snd_printd("cannot find address for device %s\n", device); + return -ENODEV; + } + addr = *base; + if (addr < 0x50) + addr += 0x50; + } else + addr = *base; + + gp->addr = addr & 0x0000ffff; + + /* Try to find the active state, default to 0 ! */ + base = (u32 *)get_property(np, "audio-gpio-active-state", NULL); + if (base) { + gp->active_state = *base; + gp->active_val = (*base) ? 0x5 : 0x4; + gp->inactive_val = (*base) ? 0x4 : 0x5; + } else { + u32 *prop = NULL; + gp->active_state = 0; + gp->active_val = 0x4; + gp->inactive_val = 0x5; + /* Here are some crude hacks to extract the GPIO polarity and + * open collector informations out of the do-platform script + * as we don't yet have an interpreter for these things + */ + if (platform) + prop = (u32 *)get_property(np, platform, NULL); + if (prop) { + if (prop[3] == 0x9 && prop[4] == 0x9) { + gp->active_val = 0xd; + gp->inactive_val = 0xc; + } + if (prop[3] == 0x1 && prop[4] == 0x1) { + gp->active_val = 0x5; + gp->inactive_val = 0x4; + } + } + } + + DBG("(I) GPIO device %s found, offset: %x, active state: %d !\n", + device, gp->addr, gp->active_state); + + return (np->n_intrs > 0) ? np->intrs[0].line : 0; +} + +static void toonie_cleanup(pmac_t *chip) +{ + struct pmac_toonie *mix = chip->mixer_data; + if (! mix) + return; + if (mix->hp_detect_irq >= 0) + free_irq(mix->hp_detect_irq, chip); + kfree(mix); + chip->mixer_data = NULL; +} + +int snd_pmac_toonie_init(pmac_t *chip) +{ + struct pmac_toonie *mix; + + mix = kmalloc(sizeof(*mix), GFP_KERNEL); + if (! mix) + return -ENOMEM; + + chip->mixer_data = mix; + chip->mixer_free = toonie_cleanup; + + find_audio_gpio("headphone-mute", NULL, &mix->hp_mute_gpio); + find_audio_gpio("amp-mute", NULL, &mix->amp_mute_gpio); + mix->hp_detect_irq = find_audio_gpio("headphone-detect", + NULL, &mix->hp_detect_gpio); + + strcpy(chip->card->mixername, "PowerMac Toonie"); + + chip->master_sw_ctl = snd_ctl_new1(&toonie_hp_sw, chip); + snd_ctl_add(chip->card, chip->master_sw_ctl); + + chip->speaker_sw_ctl = snd_ctl_new1(&toonie_speaker_sw, chip); + snd_ctl_add(chip->card, chip->speaker_sw_ctl); + + INIT_WORK(&mix->detect_work, toonie_detect_handler, (void *)chip); + + if (mix->hp_detect_irq >= 0) { + snd_pmac_add_automute(chip); + + chip->detect_headphone = toonie_detect_headphone; + chip->update_automute = toonie_update_automute; + toonie_update_automute(chip, 0); + + if (request_irq(mix->hp_detect_irq, toonie_hp_intr, 0, + "Sound Headphone Detection", chip) < 0) + mix->hp_detect_irq = -1; + } + + return 0; +} + -- cgit v0.10.2 From 085e6fc96bcf239cab8adc600aab2452d75590b1 Mon Sep 17 00:00:00 2001 From: Colin Leroy Date: Sun, 1 May 2005 08:58:43 -0700 Subject: [PATCH] pmac: save master volume on sleep Ben's patch that shutdowns master switch and restores it after resume ("pmac: Improve sleep code of tumbler driver") isn't enough here on an iBook (snapper chip). The master switch is correctly saved and restored, but somehow tumbler_put_master_volume() gets called just after tumbler_set_master_volume() and sets mix->master_vol[*] to 0. So, on resuming, the master switch is reenabled, but the volume is set to 0. Here's a patch that also saves and restores master_vol. Signed-off-by: Colin Leroy Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index f3e0107..9332237 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -99,6 +99,7 @@ typedef struct pmac_tumbler_t { pmac_gpio_t hp_detect; int headphone_irq; int lineout_irq; + unsigned int save_master_vol[2]; unsigned int master_vol[2]; unsigned int save_master_switch[2]; unsigned int master_switch[2]; @@ -1139,6 +1140,8 @@ static void tumbler_suspend(pmac_t *chip) disable_irq(mix->lineout_irq); mix->save_master_switch[0] = mix->master_switch[0]; mix->save_master_switch[1] = mix->master_switch[1]; + mix->save_master_vol[0] = mix->master_vol[0]; + mix->save_master_vol[1] = mix->master_vol[1]; mix->master_switch[0] = mix->master_switch[1] = 0; tumbler_set_master_volume(mix); if (!mix->anded_reset) { @@ -1166,6 +1169,8 @@ static void tumbler_resume(pmac_t *chip) mix->acs &= ~1; mix->master_switch[0] = mix->save_master_switch[0]; mix->master_switch[1] = mix->save_master_switch[1]; + mix->master_vol[0] = mix->save_master_vol[0]; + mix->master_vol[1] = mix->save_master_vol[1]; tumbler_reset_audio(chip); if (mix->i2c.client && mix->i2c.init_client) { if (mix->i2c.init_client(&mix->i2c) < 0) -- cgit v0.10.2 From 1b29f9d13e3cf0fe86bf7f82a3399c9e3caf58e5 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 1 May 2005 08:58:43 -0700 Subject: [PATCH] ppc64: add PT_NOTE section to vDSO This patch from Roland adds a PT_NOTE section to both 32 and 64 bits vDSOs to expose the kernel version to glibc, thus avoiding a uname syscall on every launch. This is equivalent to the patches Roland posted already for x86 and x86-64. Note: the 64 bits .note is actually using the 32 bits format. This is normal. The ELF spec specifies a different format for 64 bits .note, but for some reason, this was never properly implemented, the core dumps for example are all using 32 bits format .note, and binutils cannot even read a 64 bits format .note. Talking to our toolchain folks, they think we'd rather stick to 32 bits format .note everywhere and get the spec fixed some day ... Signed-off-by: Roland McGrath Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/vdso32/Makefile b/arch/ppc64/kernel/vdso32/Makefile index ede2f7e..0b1b0df 100644 --- a/arch/ppc64/kernel/vdso32/Makefile +++ b/arch/ppc64/kernel/vdso32/Makefile @@ -1,7 +1,7 @@ # List of files in the vdso, has to be asm only for now -obj-vdso32 = sigtramp.o gettimeofday.o datapage.o cacheflush.o +obj-vdso32 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o # Build rules diff --git a/arch/ppc64/kernel/vdso32/note.S b/arch/ppc64/kernel/vdso32/note.S new file mode 100644 index 0000000..d4b5be4 --- /dev/null +++ b/arch/ppc64/kernel/vdso32/note.S @@ -0,0 +1,25 @@ +/* + * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. + * Here we can supply some information useful to userland. + */ + +#include +#include + +#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \ + .section name, flags; \ + .balign 4; \ + .long 1f - 0f; /* name length */ \ + .long 3f - 2f; /* data length */ \ + .long type; /* note type */ \ +0: .asciz vendor; /* vendor name */ \ +1: .balign 4; \ +2: + +#define ASM_ELF_NOTE_END \ +3: .balign 4; /* pad out section */ \ + .previous + + ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0) + .long LINUX_VERSION_CODE + ASM_ELF_NOTE_END diff --git a/arch/ppc64/kernel/vdso32/vdso32.lds.S b/arch/ppc64/kernel/vdso32/vdso32.lds.S index cca27bd..11290c9 100644 --- a/arch/ppc64/kernel/vdso32/vdso32.lds.S +++ b/arch/ppc64/kernel/vdso32/vdso32.lds.S @@ -20,6 +20,8 @@ SECTIONS .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } + .note : { *(.note.*) } :text :note + . = ALIGN (16); .text : { @@ -87,6 +89,7 @@ SECTIONS PHDRS { text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ + note PT_NOTE FLAGS(4); /* PF_R */ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ } diff --git a/arch/ppc64/kernel/vdso64/Makefile b/arch/ppc64/kernel/vdso64/Makefile index bd3f70b..ab39988 100644 --- a/arch/ppc64/kernel/vdso64/Makefile +++ b/arch/ppc64/kernel/vdso64/Makefile @@ -1,6 +1,6 @@ # List of files in the vdso, has to be asm only for now -obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o +obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o # Build rules diff --git a/arch/ppc64/kernel/vdso64/note.S b/arch/ppc64/kernel/vdso64/note.S new file mode 100644 index 0000000..dc2a509 --- /dev/null +++ b/arch/ppc64/kernel/vdso64/note.S @@ -0,0 +1 @@ +#include "../vdso32/note.S" diff --git a/arch/ppc64/kernel/vdso64/vdso64.lds.S b/arch/ppc64/kernel/vdso64/vdso64.lds.S index 942c815..9cb2818 100644 --- a/arch/ppc64/kernel/vdso64/vdso64.lds.S +++ b/arch/ppc64/kernel/vdso64/vdso64.lds.S @@ -18,12 +18,14 @@ SECTIONS .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } + .note : { *(.note.*) } :text :note + . = ALIGN (16); .text : { *(.text .stub .text.* .gnu.linkonce.t.*) *(.sfpr .glink) - } + } :text PROVIDE (__etext = .); PROVIDE (_etext = .); PROVIDE (etext = .); @@ -88,6 +90,7 @@ SECTIONS PHDRS { text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ + note PT_NOTE FLAGS(4); /* PF_R */ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ } -- cgit v0.10.2 From bb78cb72201985ae9269b723c82ea0f892048b9e Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sun, 1 May 2005 08:58:44 -0700 Subject: [PATCH] ppc64: remove unused argument to create_slbe Remove vsid argument to create_slbe, since it's no longer used. Spotted by R Sharada. Signed-off-by: Olof Johansson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/mm/slb.c b/arch/ppc64/mm/slb.c index 6a20773..244150a 100644 --- a/arch/ppc64/mm/slb.c +++ b/arch/ppc64/mm/slb.c @@ -33,8 +33,8 @@ static inline unsigned long mk_vsid_data(unsigned long ea, unsigned long flags) return (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | flags; } -static inline void create_slbe(unsigned long ea, unsigned long vsid, - unsigned long flags, unsigned long entry) +static inline void create_slbe(unsigned long ea, unsigned long flags, + unsigned long entry) { asm volatile("slbmte %0,%1" : : "r" (mk_vsid_data(ea, flags)), @@ -145,9 +145,8 @@ void slb_initialize(void) asm volatile("isync":::"memory"); asm volatile("slbmte %0,%0"::"r" (0) : "memory"); asm volatile("isync; slbia; isync":::"memory"); - create_slbe(KERNELBASE, get_kernel_vsid(KERNELBASE), flags, 0); - create_slbe(VMALLOCBASE, get_kernel_vsid(KERNELBASE), - SLB_VSID_KERNEL, 1); + create_slbe(KERNELBASE, flags, 0); + create_slbe(VMALLOCBASE, SLB_VSID_KERNEL, 1); /* We don't bolt the stack for the time being - we're in boot, * so the stack is in the bolted segment. By the time it goes * elsewhere, we'll call _switch() which will bolt in the new -- cgit v0.10.2 From dc3ec7503e693e05c01d85b664482d0f694429ab Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 1 May 2005 08:58:44 -0700 Subject: [PATCH] ppc64: Fix irq parsing on powermac When I tried Ben's patches to the powermac sound driver on my G5, I found that it was taking enormous numbers of sound DMA transmit interrupts. This turned out to be because it was incorrectly configured as level-sensitive instead of edge-sensitive, which in turn was because the code that parses the interrupt tree that Open Firmware gives us was incorrectly assigning another device the same irq number as the sound DMA transmit interrupt (i.e. 1). This patch fixes the problem, in a somewhat quick and dirty way for now, but one which will work for all the machines we currently run on. Ultimately Ben and I want to do something more general and robust, but this should go in for 2.6.12. Signed-off-by: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c index 45a4ad0..fe2946c 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c @@ -321,6 +321,10 @@ static int __devinit finish_node_interrupts(struct device_node *np, char *name = get_property(ic->parent, "name", NULL); if (name && !strcmp(name, "u3")) np->intrs[intrcount].line += 128; + else if (!(name && !strcmp(name, "mac-io"))) + /* ignore other cascaded controllers, such as + the k2-sata-root */ + break; } np->intrs[intrcount].sense = 1; if (n > 1) -- cgit v0.10.2 From 0339ad77c4a06fa8529db17c91f790058e18b65b Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sun, 1 May 2005 08:58:44 -0700 Subject: [PATCH] ppc64: nvram cleanups - Fix arch/ppc64/kernel/nvram.c:342: warning: `part' might be used uninitialized in this function - Various codingstyle tweaks. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c index b9069c2..4e71781 100644 --- a/arch/ppc64/kernel/nvram.c +++ b/arch/ppc64/kernel/nvram.c @@ -339,9 +339,9 @@ static int nvram_remove_os_partition(void) static int nvram_create_os_partition(void) { struct list_head * p; - struct nvram_partition * part; - struct nvram_partition * new_part = NULL; - struct nvram_partition * free_part = NULL; + struct nvram_partition *part = NULL; + struct nvram_partition *new_part = NULL; + struct nvram_partition *free_part = NULL; int seq_init[2] = { 0, 0 }; loff_t tmp_index; long size = 0; @@ -364,13 +364,11 @@ static int nvram_create_os_partition(void) free_part = part; } } - if (!size) { + if (!size) return -ENOSPC; - } /* Create our OS partition */ - new_part = (struct nvram_partition *) - kmalloc(sizeof(struct nvram_partition), GFP_KERNEL); + new_part = kmalloc(sizeof(*new_part), GFP_KERNEL); if (!new_part) { printk(KERN_ERR "nvram_create_os_partition: kmalloc failed\n"); return -ENOMEM; @@ -379,7 +377,7 @@ static int nvram_create_os_partition(void) new_part->index = free_part->index; new_part->header.signature = NVRAM_SIG_OS; new_part->header.length = size; - sprintf(new_part->header.name, "ppc64,linux"); + strcpy(new_part->header.name, "ppc64,linux"); new_part->header.checksum = nvram_checksum(&new_part->header); rc = nvram_write_header(new_part); @@ -394,7 +392,8 @@ static int nvram_create_os_partition(void) tmp_index = new_part->index + NVRAM_HEADER_LEN; rc = ppc_md.nvram_write((char *)&seq_init, sizeof(seq_init), &tmp_index); if (rc <= 0) { - printk(KERN_ERR "nvram_create_os_partition: nvram_write failed (%d)\n", rc); + printk(KERN_ERR "nvram_create_os_partition: nvram_write " + "failed (%d)\n", rc); return rc; } -- cgit v0.10.2 From 58366af5861eee1479426380e3c91ecb334c301d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 1 May 2005 08:58:44 -0700 Subject: [PATCH] ppc64: update to use the new 4L headers This patch converts ppc64 to use the generic pgtable-nopud.h instead of the "fixup" header. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c index 390296e..d3bf86a 100644 --- a/arch/ppc64/mm/hugetlbpage.c +++ b/arch/ppc64/mm/hugetlbpage.c @@ -42,7 +42,7 @@ static inline int hugepgd_index(unsigned long addr) return (addr & ~REGION_MASK) >> HUGEPGDIR_SHIFT; } -static pgd_t *hugepgd_offset(struct mm_struct *mm, unsigned long addr) +static pud_t *hugepgd_offset(struct mm_struct *mm, unsigned long addr) { int index; @@ -52,21 +52,21 @@ static pgd_t *hugepgd_offset(struct mm_struct *mm, unsigned long addr) index = hugepgd_index(addr); BUG_ON(index >= PTRS_PER_HUGEPGD); - return mm->context.huge_pgdir + index; + return (pud_t *)(mm->context.huge_pgdir + index); } -static inline pte_t *hugepte_offset(pgd_t *dir, unsigned long addr) +static inline pte_t *hugepte_offset(pud_t *dir, unsigned long addr) { int index; - if (pgd_none(*dir)) + if (pud_none(*dir)) return NULL; index = (addr >> HPAGE_SHIFT) % PTRS_PER_HUGEPTE; - return (pte_t *)pgd_page(*dir) + index; + return (pte_t *)pud_page(*dir) + index; } -static pgd_t *hugepgd_alloc(struct mm_struct *mm, unsigned long addr) +static pud_t *hugepgd_alloc(struct mm_struct *mm, unsigned long addr) { BUG_ON(! in_hugepage_area(mm->context, addr)); @@ -90,10 +90,9 @@ static pgd_t *hugepgd_alloc(struct mm_struct *mm, unsigned long addr) return hugepgd_offset(mm, addr); } -static pte_t *hugepte_alloc(struct mm_struct *mm, pgd_t *dir, - unsigned long addr) +static pte_t *hugepte_alloc(struct mm_struct *mm, pud_t *dir, unsigned long addr) { - if (! pgd_present(*dir)) { + if (! pud_present(*dir)) { pte_t *new; spin_unlock(&mm->page_table_lock); @@ -104,7 +103,7 @@ static pte_t *hugepte_alloc(struct mm_struct *mm, pgd_t *dir, * Because we dropped the lock, we should re-check the * entry, as somebody else could have populated it.. */ - if (pgd_present(*dir)) { + if (pud_present(*dir)) { if (new) kmem_cache_free(zero_cache, new); } else { @@ -115,7 +114,7 @@ static pte_t *hugepte_alloc(struct mm_struct *mm, pgd_t *dir, ptepage = virt_to_page(new); ptepage->mapping = (void *) mm; ptepage->index = addr & HUGEPGDIR_MASK; - pgd_populate(mm, dir, new); + pud_populate(mm, dir, new); } } @@ -124,28 +123,28 @@ static pte_t *hugepte_alloc(struct mm_struct *mm, pgd_t *dir, static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) { - pgd_t *pgd; + pud_t *pud; BUG_ON(! in_hugepage_area(mm->context, addr)); - pgd = hugepgd_offset(mm, addr); - if (! pgd) + pud = hugepgd_offset(mm, addr); + if (! pud) return NULL; - return hugepte_offset(pgd, addr); + return hugepte_offset(pud, addr); } static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) { - pgd_t *pgd; + pud_t *pud; BUG_ON(! in_hugepage_area(mm->context, addr)); - pgd = hugepgd_alloc(mm, addr); - if (! pgd) + pud = hugepgd_alloc(mm, addr); + if (! pud) return NULL; - return hugepte_alloc(mm, pgd, addr); + return hugepte_alloc(mm, pud, addr); } static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, @@ -709,10 +708,10 @@ void hugetlb_mm_free_pgd(struct mm_struct *mm) /* cleanup any hugepte pages leftover */ for (i = 0; i < PTRS_PER_HUGEPGD; i++) { - pgd_t *pgd = pgdir + i; + pud_t *pud = (pud_t *)(pgdir + i); - if (! pgd_none(*pgd)) { - pte_t *pte = (pte_t *)pgd_page(*pgd); + if (! pud_none(*pud)) { + pte_t *pte = (pte_t *)pud_page(*pud); struct page *ptepage = virt_to_page(pte); ptepage->mapping = NULL; @@ -720,7 +719,7 @@ void hugetlb_mm_free_pgd(struct mm_struct *mm) BUG_ON(memcmp(pte, empty_zero_page, PAGE_SIZE)); kmem_cache_free(zero_cache, pte); } - pgd_clear(pgd); + pud_clear(pud); } BUG_ON(memcmp(pgdir, empty_zero_page, PAGE_SIZE)); diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index a7149b9..cf33d7e 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c @@ -136,14 +136,78 @@ void iounmap(volatile void __iomem *addr) #else +static void unmap_im_area_pte(pmd_t *pmd, unsigned long addr, + unsigned long end) +{ + pte_t *pte; + + pte = pte_offset_kernel(pmd, addr); + do { + pte_t ptent = ptep_get_and_clear(&ioremap_mm, addr, pte); + WARN_ON(!pte_none(ptent) && !pte_present(ptent)); + } while (pte++, addr += PAGE_SIZE, addr != end); +} + +static inline void unmap_im_area_pmd(pud_t *pud, unsigned long addr, + unsigned long end) +{ + pmd_t *pmd; + unsigned long next; + + pmd = pmd_offset(pud, addr); + do { + next = pmd_addr_end(addr, end); + if (pmd_none_or_clear_bad(pmd)) + continue; + unmap_im_area_pte(pmd, addr, next); + } while (pmd++, addr = next, addr != end); +} + +static inline void unmap_im_area_pud(pgd_t *pgd, unsigned long addr, + unsigned long end) +{ + pud_t *pud; + unsigned long next; + + pud = pud_offset(pgd, addr); + do { + next = pud_addr_end(addr, end); + if (pud_none_or_clear_bad(pud)) + continue; + unmap_im_area_pmd(pud, addr, next); + } while (pud++, addr = next, addr != end); +} + +static void unmap_im_area(unsigned long addr, unsigned long end) +{ + struct mm_struct *mm = &ioremap_mm; + unsigned long next; + pgd_t *pgd; + + spin_lock(&mm->page_table_lock); + + pgd = pgd_offset_i(addr); + flush_cache_vunmap(addr, end); + do { + next = pgd_addr_end(addr, end); + if (pgd_none_or_clear_bad(pgd)) + continue; + unmap_im_area_pud(pgd, addr, next); + } while (pgd++, addr = next, addr != end); + flush_tlb_kernel_range(start, end); + + spin_unlock(&mm->page_table_lock); +} + /* * map_io_page currently only called by __ioremap * map_io_page adds an entry to the ioremap page table * and adds an entry to the HPT, possibly bolting it */ -static void map_io_page(unsigned long ea, unsigned long pa, int flags) +static int map_io_page(unsigned long ea, unsigned long pa, int flags) { pgd_t *pgdp; + pud_t *pudp; pmd_t *pmdp; pte_t *ptep; unsigned long vsid; @@ -151,9 +215,15 @@ static void map_io_page(unsigned long ea, unsigned long pa, int flags) if (mem_init_done) { spin_lock(&ioremap_mm.page_table_lock); pgdp = pgd_offset_i(ea); - pmdp = pmd_alloc(&ioremap_mm, pgdp, ea); + pudp = pud_alloc(&ioremap_mm, pgdp, ea); + if (!pudp) + return -ENOMEM; + pmdp = pmd_alloc(&ioremap_mm, pudp, ea); + if (!pmdp) + return -ENOMEM; ptep = pte_alloc_kernel(&ioremap_mm, pmdp, ea); - + if (!ptep) + return -ENOMEM; pa = abs_to_phys(pa); set_pte_at(&ioremap_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); @@ -181,6 +251,7 @@ static void map_io_page(unsigned long ea, unsigned long pa, int flags) panic("map_io_page: could not insert mapping"); } } + return 0; } @@ -194,9 +265,14 @@ static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa, flags |= pgprot_val(PAGE_KERNEL); for (i = 0; i < size; i += PAGE_SIZE) - map_io_page(ea+i, pa+i, flags); + if (map_io_page(ea+i, pa+i, flags)) + goto failure; return (void __iomem *) (ea + (addr & ~PAGE_MASK)); + failure: + if (mem_init_done) + unmap_im_area(ea, ea + size); + return NULL; } @@ -206,10 +282,11 @@ ioremap(unsigned long addr, unsigned long size) return __ioremap(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED); } -void __iomem * -__ioremap(unsigned long addr, unsigned long size, unsigned long flags) +void __iomem * __ioremap(unsigned long addr, unsigned long size, + unsigned long flags) { unsigned long pa, ea; + void __iomem *ret; /* * Choose an address to map it to. @@ -232,12 +309,16 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags) if (area == NULL) return NULL; ea = (unsigned long)(area->addr); + ret = __ioremap_com(addr, pa, ea, size, flags); + if (!ret) + im_free(area->addr); } else { ea = ioremap_bot; - ioremap_bot += size; + ret = __ioremap_com(addr, pa, ea, size, flags); + if (ret) + ioremap_bot += size; } - - return __ioremap_com(addr, pa, ea, size, flags); + return ret; } #define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK)) @@ -246,6 +327,7 @@ int __ioremap_explicit(unsigned long pa, unsigned long ea, unsigned long size, unsigned long flags) { struct vm_struct *area; + void __iomem *ret; /* For now, require page-aligned values for pa, ea, and size */ if (!IS_PAGE_ALIGNED(pa) || !IS_PAGE_ALIGNED(ea) || @@ -276,7 +358,12 @@ int __ioremap_explicit(unsigned long pa, unsigned long ea, } } - if (__ioremap_com(pa, pa, ea, size, flags) != (void *) ea) { + ret = __ioremap_com(pa, pa, ea, size, flags); + if (ret == NULL) { + printk(KERN_ERR "ioremap_explicit() allocation failure !\n"); + return 1; + } + if (ret != (void *) ea) { printk(KERN_ERR "__ioremap_com() returned unexpected addr\n"); return 1; } @@ -284,69 +371,6 @@ int __ioremap_explicit(unsigned long pa, unsigned long ea, return 0; } -static void unmap_im_area_pte(pmd_t *pmd, unsigned long address, - unsigned long size) -{ - unsigned long base, end; - pte_t *pte; - - if (pmd_none(*pmd)) - return; - if (pmd_bad(*pmd)) { - pmd_ERROR(*pmd); - pmd_clear(pmd); - return; - } - - pte = pte_offset_kernel(pmd, address); - base = address & PMD_MASK; - address &= ~PMD_MASK; - end = address + size; - if (end > PMD_SIZE) - end = PMD_SIZE; - - do { - pte_t page; - page = ptep_get_and_clear(&ioremap_mm, base + address, pte); - address += PAGE_SIZE; - pte++; - if (pte_none(page)) - continue; - if (pte_present(page)) - continue; - printk(KERN_CRIT "Whee.. Swapped out page in kernel page" - " table\n"); - } while (address < end); -} - -static void unmap_im_area_pmd(pgd_t *dir, unsigned long address, - unsigned long size) -{ - unsigned long base, end; - pmd_t *pmd; - - if (pgd_none(*dir)) - return; - if (pgd_bad(*dir)) { - pgd_ERROR(*dir); - pgd_clear(dir); - return; - } - - pmd = pmd_offset(dir, address); - base = address & PGDIR_MASK; - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - - do { - unmap_im_area_pte(pmd, base + address, end - address); - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address < end); -} - /* * Unmap an IO region and remove it from imalloc'd list. * Access to IO memory should be serialized by driver. @@ -356,39 +380,19 @@ static void unmap_im_area_pmd(pgd_t *dir, unsigned long address, */ void iounmap(volatile void __iomem *token) { - unsigned long address, start, end, size; - struct mm_struct *mm; - pgd_t *dir; + unsigned long address, size; void *addr; - if (!mem_init_done) { + if (!mem_init_done) return; - } addr = (void *) ((unsigned long __force) token & PAGE_MASK); - if ((size = im_free(addr)) == 0) { + if ((size = im_free(addr)) == 0) return; - } address = (unsigned long)addr; - start = address; - end = address + size; - - mm = &ioremap_mm; - spin_lock(&mm->page_table_lock); - - dir = pgd_offset_i(address); - flush_cache_vunmap(address, end); - do { - unmap_im_area_pmd(dir, address, end - address); - address = (address + PGDIR_SIZE) & PGDIR_MASK; - dir++; - } while (address && (address < end)); - flush_tlb_kernel_range(start, end); - - spin_unlock(&mm->page_table_lock); - return; + unmap_im_area(address, address + size); } static int iounmap_subset_regions(unsigned long addr, unsigned long size) diff --git a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h index 16232d7..4fc4b73 100644 --- a/include/asm-ppc64/pgalloc.h +++ b/include/asm-ppc64/pgalloc.h @@ -27,7 +27,7 @@ pgd_free(pgd_t *pgd) kmem_cache_free(zero_cache, pgd); } -#define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD) +#define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD) static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long addr) diff --git a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h index a261205..b984e27 100644 --- a/include/asm-ppc64/pgtable.h +++ b/include/asm-ppc64/pgtable.h @@ -1,8 +1,6 @@ #ifndef _PPC64_PGTABLE_H #define _PPC64_PGTABLE_H -#include - /* * This file contains the functions and defines necessary to modify and use * the ppc64 hashed page table. @@ -17,6 +15,8 @@ #include #endif /* __ASSEMBLY__ */ +#include + /* PMD_SHIFT determines what a second-level page table entry can map */ #define PMD_SHIFT (PAGE_SHIFT + PAGE_SHIFT - 3) #define PMD_SIZE (1UL << PMD_SHIFT) @@ -228,12 +228,13 @@ void hugetlb_mm_free_pgd(struct mm_struct *mm); #define pmd_page_kernel(pmd) \ (__bpn_to_ba(pmd_val(pmd) >> PMD_TO_PTEPAGE_SHIFT)) #define pmd_page(pmd) virt_to_page(pmd_page_kernel(pmd)) -#define pgd_set(pgdp, pmdp) (pgd_val(*(pgdp)) = (__ba_to_bpn(pmdp))) -#define pgd_none(pgd) (!pgd_val(pgd)) -#define pgd_bad(pgd) ((pgd_val(pgd)) == 0) -#define pgd_present(pgd) (pgd_val(pgd) != 0UL) -#define pgd_clear(pgdp) (pgd_val(*(pgdp)) = 0UL) -#define pgd_page(pgd) (__bpn_to_ba(pgd_val(pgd))) + +#define pud_set(pudp, pmdp) (pud_val(*(pudp)) = (__ba_to_bpn(pmdp))) +#define pud_none(pud) (!pud_val(pud)) +#define pud_bad(pud) ((pud_val(pud)) == 0UL) +#define pud_present(pud) (pud_val(pud) != 0UL) +#define pud_clear(pudp) (pud_val(*(pudp)) = 0UL) +#define pud_page(pud) (__bpn_to_ba(pud_val(pud))) /* * Find an entry in a page-table-directory. We combine the address region @@ -245,12 +246,13 @@ void hugetlb_mm_free_pgd(struct mm_struct *mm); #define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) /* Find an entry in the second-level page table.. */ -#define pmd_offset(dir,addr) \ - ((pmd_t *) pgd_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))) +#define pmd_offset(pudp,addr) \ + ((pmd_t *) pud_page(*(pudp)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))) /* Find an entry in the third-level page table.. */ #define pte_offset_kernel(dir,addr) \ - ((pte_t *) pmd_page_kernel(*(dir)) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))) + ((pte_t *) pmd_page_kernel(*(dir)) \ + + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))) #define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr)) #define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr)) @@ -582,19 +584,22 @@ extern long native_hpte_insert(unsigned long hpte_group, unsigned long va, static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea) { pgd_t *pg; + pud_t *pu; pmd_t *pm; pte_t *pt = NULL; pte_t pte; pg = pgdir + pgd_index(ea); if (!pgd_none(*pg)) { - - pm = pmd_offset(pg, ea); - if (pmd_present(*pm)) { - pt = pte_offset_kernel(pm, ea); - pte = *pt; - if (!pte_present(pte)) - pt = NULL; + pu = pud_offset(pg, ea); + if (!pud_none(*pu)) { + pm = pmd_offset(pu, ea); + if (pmd_present(*pm)) { + pt = pte_offset_kernel(pm, ea); + pte = *pt; + if (!pte_present(pte)) + pt = NULL; + } } } -- cgit v0.10.2 From 66faf9845a05905d75da380767e93455f3e6d620 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 1 May 2005 08:58:45 -0700 Subject: [PATCH] ppc64: tell firmware about kernel capabilities On pSeries systems, according to the platform architecture specs, we are supposed to be supplying a structure to firmware that tells firmware about our capabilities, such as which version of the data structures that describe available memory we are expecting to see. The way we end up having to supply this data structure is a bit gross, since it was designed for AIX and doesn't suit us very well. This patch adds the code to supply this data structure to the firmware. Signed-off-by: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/boot/addnote.c b/arch/ppc64/boot/addnote.c index 66ff810..719663a 100644 --- a/arch/ppc64/boot/addnote.c +++ b/arch/ppc64/boot/addnote.c @@ -19,6 +19,7 @@ #include #include +/* CHRP note section */ char arch[] = "PowerPC"; #define N_DESCR 6 @@ -31,6 +32,29 @@ unsigned int descr[N_DESCR] = { 0x4000, /* load-base */ }; +/* RPA note section */ +char rpaname[] = "IBM,RPA-Client-Config"; + +/* + * Note: setting ignore_my_client_config *should* mean that OF ignores + * all the other fields, but there is a firmware bug which means that + * it looks at the splpar field at least. So these values need to be + * reasonable. + */ +#define N_RPA_DESCR 8 +unsigned int rpanote[N_RPA_DESCR] = { + 0, /* lparaffinity */ + 64, /* min_rmo_size */ + 0, /* min_rmo_percent */ + 40, /* max_pft_size */ + 1, /* splpar */ + -1, /* min_load */ + 0, /* new_mem_def */ + 1, /* ignore_my_client_config */ +}; + +#define ROUNDUP(len) (((len) + 3) & ~3) + unsigned char buf[512]; #define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) @@ -69,7 +93,7 @@ main(int ac, char **av) { int fd, n, i; int ph, ps, np; - int nnote, ns; + int nnote, nnote2, ns; if (ac != 2) { fprintf(stderr, "Usage: %s elf-file\n", av[0]); @@ -81,7 +105,8 @@ main(int ac, char **av) exit(1); } - nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4; + nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr); + nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote); n = read(fd, buf, sizeof(buf)); if (n < 0) { @@ -104,7 +129,7 @@ main(int ac, char **av) np = GET_16BE(E_PHNUM); if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) goto notelf; - if (ph + (np + 1) * ps + nnote > n) + if (ph + (np + 2) * ps + nnote + nnote2 > n) goto nospace; for (i = 0; i < np; ++i) { @@ -117,12 +142,12 @@ main(int ac, char **av) } /* XXX check that the area we want to use is all zeroes */ - for (i = 0; i < ps + nnote; ++i) + for (i = 0; i < 2 * ps + nnote + nnote2; ++i) if (buf[ph + i] != 0) goto nospace; /* fill in the program header entry */ - ns = ph + ps; + ns = ph + 2 * ps; PUT_32BE(ph + PH_TYPE, PT_NOTE); PUT_32BE(ph + PH_OFFSET, ns); PUT_32BE(ph + PH_FILESZ, nnote); @@ -134,11 +159,26 @@ main(int ac, char **av) PUT_32BE(ns + 8, 0x1275); strcpy(&buf[ns + 12], arch); ns += 12 + strlen(arch) + 1; - for (i = 0; i < N_DESCR; ++i) - PUT_32BE(ns + i * 4, descr[i]); + for (i = 0; i < N_DESCR; ++i, ns += 4) + PUT_32BE(ns, descr[i]); + + /* fill in the second program header entry and the RPA note area */ + ph += ps; + PUT_32BE(ph + PH_TYPE, PT_NOTE); + PUT_32BE(ph + PH_OFFSET, ns); + PUT_32BE(ph + PH_FILESZ, nnote2); + + /* fill in the note area we point to */ + PUT_32BE(ns, strlen(rpaname) + 1); + PUT_32BE(ns + 4, sizeof(rpanote)); + PUT_32BE(ns + 8, 0x12759999); + strcpy(&buf[ns + 12], rpaname); + ns += 12 + ROUNDUP(strlen(rpaname) + 1); + for (i = 0; i < N_RPA_DESCR; ++i, ns += 4) + PUT_32BE(ns, rpanote[i]); /* Update the number of program headers */ - PUT_16BE(E_PHNUM, np + 1); + PUT_16BE(E_PHNUM, np + 2); /* write back */ lseek(fd, (long) 0, SEEK_SET); @@ -155,11 +195,11 @@ main(int ac, char **av) exit(0); notelf: - fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]); + fprintf(stderr, "%s does not appear to be an ELF file\n", av[1]); exit(1); nospace: fprintf(stderr, "sorry, I can't find space in %s to put the note\n", - av[0]); + av[1]); exit(1); } diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index 8dffa9a..b0b784f 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -493,6 +493,113 @@ static void __init early_cmdline_parse(void) } /* + * To tell the firmware what our capabilities are, we have to pass + * it a fake 32-bit ELF header containing a couple of PT_NOTE sections + * that contain structures that contain the actual values. + */ +static struct fake_elf { + Elf32_Ehdr elfhdr; + Elf32_Phdr phdr[2]; + struct chrpnote { + u32 namesz; + u32 descsz; + u32 type; + char name[8]; /* "PowerPC" */ + struct chrpdesc { + u32 real_mode; + u32 real_base; + u32 real_size; + u32 virt_base; + u32 virt_size; + u32 load_base; + } chrpdesc; + } chrpnote; + struct rpanote { + u32 namesz; + u32 descsz; + u32 type; + char name[24]; /* "IBM,RPA-Client-Config" */ + struct rpadesc { + u32 lpar_affinity; + u32 min_rmo_size; + u32 min_rmo_percent; + u32 max_pft_size; + u32 splpar; + u32 min_load; + u32 new_mem_def; + u32 ignore_me; + } rpadesc; + } rpanote; +} fake_elf = { + .elfhdr = { + .e_ident = { 0x7f, 'E', 'L', 'F', + ELFCLASS32, ELFDATA2MSB, EV_CURRENT }, + .e_type = ET_EXEC, /* yeah right */ + .e_machine = EM_PPC, + .e_version = EV_CURRENT, + .e_phoff = offsetof(struct fake_elf, phdr), + .e_phentsize = sizeof(Elf32_Phdr), + .e_phnum = 2 + }, + .phdr = { + [0] = { + .p_type = PT_NOTE, + .p_offset = offsetof(struct fake_elf, chrpnote), + .p_filesz = sizeof(struct chrpnote) + }, [1] = { + .p_type = PT_NOTE, + .p_offset = offsetof(struct fake_elf, rpanote), + .p_filesz = sizeof(struct rpanote) + } + }, + .chrpnote = { + .namesz = sizeof("PowerPC"), + .descsz = sizeof(struct chrpdesc), + .type = 0x1275, + .name = "PowerPC", + .chrpdesc = { + .real_mode = ~0U, /* ~0 means "don't care" */ + .real_base = ~0U, + .real_size = ~0U, + .virt_base = ~0U, + .virt_size = ~0U, + .load_base = ~0U + }, + }, + .rpanote = { + .namesz = sizeof("IBM,RPA-Client-Config"), + .descsz = sizeof(struct rpadesc), + .type = 0x12759999, + .name = "IBM,RPA-Client-Config", + .rpadesc = { + .lpar_affinity = 0, + .min_rmo_size = 64, /* in megabytes */ + .min_rmo_percent = 0, + .max_pft_size = 48, /* 2^48 bytes max PFT size */ + .splpar = 1, + .min_load = ~0U, + .new_mem_def = 0 + } + } +}; + +static void __init prom_send_capabilities(void) +{ + unsigned long offset = reloc_offset(); + ihandle elfloader; + int ret; + + elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); + if (elfloader == 0) { + prom_printf("couldn't open /packages/elf-loader\n"); + return; + } + ret = call_prom("call-method", 3, 1, ADDR("process-elf-header"), + elfloader, ADDR(&fake_elf)); + call_prom("close", 1, 0, elfloader); +} + +/* * Memory allocation strategy... our layout is normally: * * at 14Mb or more we vmlinux, then a gap and initrd. In some rare cases, initrd -- cgit v0.10.2 From d03853d566fb32c6bb8cab4bf2ecf53e692f001c Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sun, 1 May 2005 08:58:45 -0700 Subject: [PATCH] PPC64: Remove hot busy-wait loop in __hash_page It turns out that our current __hash_page code will do a very hot busy-wait loop waiting on _PAGE_BUSY to be cleared. It even does ldarx/stdcx in the loop, which will bounce reservations around like crazy if there's more than one CPU spinning on the same PTE (or even another PTE in the same reservation granule). The end result is that each fault takes longer when there's contention, which in turn increases the chance of another thread hitting the same fault and also piling up. Not pretty. There's two options here: 1. Do an out-of-line busy loop a'la spinlocks with just loads (no reserves) 2. Just bail and refault if needed. (2) makes sense here: If the PTE is busy, chances are it's in flux anyway and the other code path making a change might just be ready to hash it. This fixes a stampede seen on a large-ish system where a multithreaded HPC app faults in the same text pages on several cpus at the same time. Signed-off-by: Olof Johansson Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/mm/hash_low.S b/arch/ppc64/mm/hash_low.S index 8c0156a..c23d469 100644 --- a/arch/ppc64/mm/hash_low.S +++ b/arch/ppc64/mm/hash_low.S @@ -85,7 +85,10 @@ _GLOBAL(__hash_page) bne- htab_wrong_access /* Check if PTE is busy */ andi. r0,r31,_PAGE_BUSY - bne- 1b + /* If so, just bail out and refault if needed. Someone else + * is changing this PTE anyway and might hash it. + */ + bne- bail_ok /* Prepare new PTE value (turn access RW into DIRTY, then * add BUSY,HASHPTE and ACCESSED) */ @@ -215,6 +218,10 @@ _GLOBAL(htab_call_hpte_remove) /* Try all again */ b htab_insert_pte +bail_ok: + li r3,0 + b bail + htab_pte_insert_ok: /* Insert slot number & secondary bit in PTE */ rldimi r30,r3,12,63-15 -- cgit v0.10.2 From a2f95a5ae99eb8209ad8d9faeaada00600bd8027 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 1 May 2005 08:58:45 -0700 Subject: [PATCH] ppc64: noexec fixes There were a few issues with the ppc64 noexec support: The 64bit ABI has a non executable stack by default. At the moment 64bit apps require a PT_GNU_STACK section in order to have a non executable stack. Disable the read implies exec workaround on the 64bit ABI. The 64bit toolchain has never had problems with incorrect mmap permissions (the 32bit has, thats why we need to retain the workaround). With these fixes as well as a gcc fix from Alan Modra (that was recently committed) 64bit apps work as expected. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h index 8457d90..6c42d61 100644 --- a/include/asm-ppc64/elf.h +++ b/include/asm-ppc64/elf.h @@ -229,9 +229,13 @@ do { \ /* * An executable for which elf_read_implies_exec() returns TRUE will - * have the READ_IMPLIES_EXEC personality flag set automatically. + * have the READ_IMPLIES_EXEC personality flag set automatically. This + * is only required to work around bugs in old 32bit toolchains. Since + * the 64bit ABI has never had these issues dont enable the workaround + * even if we have an executable stack. */ -#define elf_read_implies_exec(ex, exec_stk) (exec_stk != EXSTACK_DISABLE_X) +#define elf_read_implies_exec(ex, exec_stk) (test_thread_flag(TIF_32BIT) ? \ + (exec_stk != EXSTACK_DISABLE_X) : 0) #endif diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h index 20e0f19..8621957 100644 --- a/include/asm-ppc64/page.h +++ b/include/asm-ppc64/page.h @@ -252,10 +252,19 @@ extern u64 ppc64_pft_size; /* Log 2 of page table size */ /* * This is the default if a program doesn't have a PT_GNU_STACK - * program header entry. + * program header entry. The PPC64 ELF ABI has a non executable stack + * stack by default, so in the absense of a PT_GNU_STACK program header + * we turn execute permission off. */ -#define VM_STACK_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define VM_STACK_DEFAULT_FLAGS32 (VM_READ | VM_WRITE | VM_EXEC | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +#define VM_STACK_DEFAULT_FLAGS64 (VM_READ | VM_WRITE | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +#define VM_STACK_DEFAULT_FLAGS \ + (test_thread_flag(TIF_32BIT) ? \ + VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64) #endif /* __KERNEL__ */ #endif /* _PPC64_PAGE_H */ -- cgit v0.10.2 From 4b88e927e8c38f4053680a3098325142017a37f0 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 1 May 2005 08:58:46 -0700 Subject: [PATCH] ppc64: remove unnecessary include We no longer use any ppcdebug stuff in a.out.h, so remove the define. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-ppc64/a.out.h b/include/asm-ppc64/a.out.h index 802338e..3871e25 100644 --- a/include/asm-ppc64/a.out.h +++ b/include/asm-ppc64/a.out.h @@ -1,8 +1,6 @@ #ifndef __PPC64_A_OUT_H__ #define __PPC64_A_OUT_H__ -#include - /* * c 2001 PPC 64 Team, IBM Corp * -- cgit v0.10.2 From c4005e4f661a9ec8d91720a6b570865d060afcaf Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 1 May 2005 08:58:46 -0700 Subject: [PATCH] ppc64: firmware workaround Recent gcc 4.0 testing uncovered a firmware issue. Some properties are larger than 31 bytes and due to gcc 4.0s better stack allocation this overflow ran over non volatile register storage. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index b0b784f..35ec42d 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -1555,6 +1555,12 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, } } +/* + * The Open Firmware 1275 specification states properties must be 31 bytes or + * less, however not all firmwares obey this. Make it 64 bytes to be safe. + */ +#define MAX_PROPERTY_NAME 64 + static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long *mem_end) { @@ -1564,7 +1570,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long soff; unsigned char *valp; unsigned long offset = reloc_offset(); - char pname[32]; + char pname[MAX_PROPERTY_NAME]; char *path; path = RELOC(prom_scratch); -- cgit v0.10.2 From eeb24de431ac8c80fd13a2c479cd0eb51b70484e Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 1 May 2005 08:58:46 -0700 Subject: [PATCH] ppc64: enforce medium thread priority in hypervisor calls Calls into the hypervisor do not raise the thread priority. Ensure we are running at medium priority upon entry to the hypervisor. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/pSeries_hvCall.S b/arch/ppc64/kernel/pSeries_hvCall.S index 0715d30..176e8da 100644 --- a/arch/ppc64/kernel/pSeries_hvCall.S +++ b/arch/ppc64/kernel/pSeries_hvCall.S @@ -28,6 +28,8 @@ unsigned long *out3); R10 */ _GLOBAL(plpar_hcall) + HMT_MEDIUM + mfcr r0 std r8,STK_PARM(r8)(r1) /* Save out ptrs */ @@ -53,6 +55,8 @@ _GLOBAL(plpar_hcall) /* Simple interface with no output values (other than status) */ _GLOBAL(plpar_hcall_norets) + HMT_MEDIUM + mfcr r0 stw r0,8(r1) @@ -75,6 +79,8 @@ _GLOBAL(plpar_hcall_norets) unsigned long *out1); 120(R1) */ _GLOBAL(plpar_hcall_8arg_2ret) + HMT_MEDIUM + mfcr r0 ld r11,STK_PARM(r11)(r1) /* put arg8 in R11 */ stw r0,8(r1) @@ -99,6 +105,8 @@ _GLOBAL(plpar_hcall_8arg_2ret) unsigned long *out4); 112(R1) */ _GLOBAL(plpar_hcall_4out) + HMT_MEDIUM + mfcr r0 stw r0,8(r1) -- cgit v0.10.2 From 0d8d4d42f2d00eb65262b49f4edd4cf7ef4eb6fc Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 1 May 2005 08:58:47 -0700 Subject: [PATCH] ppc64: use smp_mb and smp_wmb Use smp_mb and smp_wmb. In particular smp_wmb is lighter weight than wmb. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 1c92da3..3b906cd 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -125,7 +125,7 @@ void __devinit smp_generic_kick_cpu(int nr) * the processor will continue on to secondary_start */ paca[nr].cpu_start = 1; - mb(); + smp_mb(); } #endif /* CONFIG_PPC_MULTIPLATFORM */ @@ -256,7 +256,7 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, } call_data = &data; - wmb(); + smp_wmb(); /* Send a message to all other CPUs and wait for them to respond */ smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION); @@ -431,7 +431,7 @@ int generic_cpu_enable(unsigned int cpu) /* get the target out of it's holding state */ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; - wmb(); + smp_wmb(); while (!cpu_online(cpu)) cpu_relax(); @@ -447,7 +447,7 @@ void generic_cpu_die(unsigned int cpu) int i; for (i = 0; i < 100; i++) { - rmb(); + smp_rmb(); if (per_cpu(cpu_state, cpu) == CPU_DEAD) return; msleep(100); @@ -463,7 +463,7 @@ void generic_mach_cpu_die(void) cpu = smp_processor_id(); printk(KERN_DEBUG "CPU%d offline\n", cpu); __get_cpu_var(cpu_state) = CPU_DEAD; - wmb(); + smp_wmb(); while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) cpu_relax(); @@ -515,7 +515,7 @@ int __devinit __cpu_up(unsigned int cpu) * be written out to main store before we release * the processor. */ - mb(); + smp_mb(); /* wake up cpus */ DBG("smp: kicking cpu %d\n", cpu); diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 77ded5a..772a465 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -221,15 +221,15 @@ static __inline__ void timer_recalc_offset(unsigned long cur_tb) temp_varp->tb_to_xs = do_gtod.varp->tb_to_xs; temp_varp->tb_orig_stamp = new_tb_orig_stamp; temp_varp->stamp_xsec = new_stamp_xsec; - mb(); + smp_mb(); do_gtod.varp = temp_varp; do_gtod.var_idx = temp_idx; ++(systemcfg->tb_update_count); - wmb(); + smp_wmb(); systemcfg->tb_orig_stamp = new_tb_orig_stamp; systemcfg->stamp_xsec = new_stamp_xsec; - wmb(); + smp_wmb(); ++(systemcfg->tb_update_count); } @@ -648,7 +648,7 @@ void ppc_adjtimex(void) temp_varp->tb_to_xs = new_tb_to_xs; temp_varp->stamp_xsec = new_stamp_xsec; temp_varp->tb_orig_stamp = do_gtod.varp->tb_orig_stamp; - mb(); + smp_mb(); do_gtod.varp = temp_varp; do_gtod.var_idx = temp_idx; @@ -662,10 +662,10 @@ void ppc_adjtimex(void) * loops back and reads them again until this criteria is met. */ ++(systemcfg->tb_update_count); - wmb(); + smp_wmb(); systemcfg->tb_to_xs = new_tb_to_xs; systemcfg->stamp_xsec = new_stamp_xsec; - wmb(); + smp_wmb(); ++(systemcfg->tb_update_count); write_sequnlock_irqrestore( &xtime_lock, flags ); -- cgit v0.10.2 From d59dd4620fb8d6422555a9e2b82a707718e68327 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sun, 1 May 2005 08:58:47 -0700 Subject: [PATCH] use smp_mb/wmb/rmb where possible Replace a number of memory barriers with smp_ variants. This means we won't take the unnecessary hit on UP machines. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/buffer.c b/fs/buffer.c index 665db84..188365c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -218,7 +218,7 @@ struct super_block *freeze_bdev(struct block_device *bdev) sb = get_super(bdev); if (sb && !(sb->s_flags & MS_RDONLY)) { sb->s_frozen = SB_FREEZE_WRITE; - wmb(); + smp_wmb(); sync_inodes_sb(sb, 0); DQUOT_SYNC(sb); @@ -235,7 +235,7 @@ struct super_block *freeze_bdev(struct block_device *bdev) sync_inodes_sb(sb, 1); sb->s_frozen = SB_FREEZE_TRANS; - wmb(); + smp_wmb(); sync_blockdev(sb->s_bdev); @@ -263,7 +263,7 @@ void thaw_bdev(struct block_device *bdev, struct super_block *sb) if (sb->s_op->unlockfs) sb->s_op->unlockfs(sb); sb->s_frozen = SB_UNFROZEN; - wmb(); + smp_wmb(); wake_up(&sb->s_wait_unfrozen); drop_super(sb); } diff --git a/ipc/mqueue.c b/ipc/mqueue.c index cb0cd3c..33f7152 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -767,7 +767,7 @@ static inline void pipelined_send(struct mqueue_inode_info *info, list_del(&receiver->list); receiver->state = STATE_PENDING; wake_up_process(receiver->task); - wmb(); + smp_wmb(); receiver->state = STATE_READY; } @@ -786,7 +786,7 @@ static inline void pipelined_receive(struct mqueue_inode_info *info) list_del(&sender->list); sender->state = STATE_PENDING; wake_up_process(sender->task); - wmb(); + smp_wmb(); sender->state = STATE_READY; } diff --git a/kernel/kthread.c b/kernel/kthread.c index e377e22..f50f174 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -174,7 +174,7 @@ int kthread_stop(struct task_struct *k) /* Must init completion *before* thread sees kthread_stop_info.k */ init_completion(&kthread_stop_info.done); - wmb(); + smp_wmb(); /* Now set kthread_should_stop() to true, and wake it up. */ kthread_stop_info.k = k; diff --git a/kernel/profile.c b/kernel/profile.c index a38fa70..a66be46 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -522,7 +522,7 @@ static int __init create_hash_tables(void) return 0; out_cleanup: prof_on = 0; - mb(); + smp_mb(); on_each_cpu(profile_nop, NULL, 0, 1); for_each_online_cpu(cpu) { struct page *page; diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 88b306c..f5cc1ce 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -135,7 +135,7 @@ int ptrace_attach(struct task_struct *task) (current->gid != task->sgid) || (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) goto bad; - rmb(); + smp_rmb(); if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE)) goto bad; /* the same process cannot be attached many times */ diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index c39ed70..6116b25 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -33,7 +33,7 @@ static int stopmachine(void *cpu) set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu)); /* Ack: we are alive */ - mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */ + smp_mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */ atomic_inc(&stopmachine_thread_ack); /* Simple state machine */ @@ -43,14 +43,14 @@ static int stopmachine(void *cpu) local_irq_disable(); irqs_disabled = 1; /* Ack: irqs disabled. */ - mb(); /* Must read state first. */ + smp_mb(); /* Must read state first. */ atomic_inc(&stopmachine_thread_ack); } else if (stopmachine_state == STOPMACHINE_PREPARE && !prepared) { /* Everyone is in place, hold CPU. */ preempt_disable(); prepared = 1; - mb(); /* Must read state first. */ + smp_mb(); /* Must read state first. */ atomic_inc(&stopmachine_thread_ack); } /* Yield in first stage: migration threads need to @@ -62,7 +62,7 @@ static int stopmachine(void *cpu) } /* Ack: we are exiting. */ - mb(); /* Must read state first. */ + smp_mb(); /* Must read state first. */ atomic_inc(&stopmachine_thread_ack); if (irqs_disabled) @@ -77,7 +77,7 @@ static int stopmachine(void *cpu) static void stopmachine_set_state(enum stopmachine_state state) { atomic_set(&stopmachine_thread_ack, 0); - wmb(); + smp_wmb(); stopmachine_state = state; while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads) cpu_relax(); diff --git a/kernel/sys.c b/kernel/sys.c index 462d78d..df2ddcc 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -525,7 +525,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid) if (new_egid != old_egid) { current->mm->dumpable = 0; - wmb(); + smp_wmb(); } if (rgid != (gid_t) -1 || (egid != (gid_t) -1 && egid != old_rgid)) @@ -556,7 +556,7 @@ asmlinkage long sys_setgid(gid_t gid) if(old_egid != gid) { current->mm->dumpable=0; - wmb(); + smp_wmb(); } current->gid = current->egid = current->sgid = current->fsgid = gid; } @@ -565,7 +565,7 @@ asmlinkage long sys_setgid(gid_t gid) if(old_egid != gid) { current->mm->dumpable=0; - wmb(); + smp_wmb(); } current->egid = current->fsgid = gid; } @@ -596,7 +596,7 @@ static int set_user(uid_t new_ruid, int dumpclear) if(dumpclear) { current->mm->dumpable = 0; - wmb(); + smp_wmb(); } current->uid = new_ruid; return 0; @@ -653,7 +653,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) if (new_euid != old_euid) { current->mm->dumpable=0; - wmb(); + smp_wmb(); } current->fsuid = current->euid = new_euid; if (ruid != (uid_t) -1 || @@ -703,7 +703,7 @@ asmlinkage long sys_setuid(uid_t uid) if (old_euid != uid) { current->mm->dumpable = 0; - wmb(); + smp_wmb(); } current->fsuid = current->euid = uid; current->suid = new_suid; @@ -748,7 +748,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) if (euid != current->euid) { current->mm->dumpable = 0; - wmb(); + smp_wmb(); } current->euid = euid; } @@ -798,7 +798,7 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) if (egid != current->egid) { current->mm->dumpable = 0; - wmb(); + smp_wmb(); } current->egid = egid; } @@ -845,7 +845,7 @@ asmlinkage long sys_setfsuid(uid_t uid) if (uid != old_fsuid) { current->mm->dumpable = 0; - wmb(); + smp_wmb(); } current->fsuid = uid; } @@ -875,7 +875,7 @@ asmlinkage long sys_setfsgid(gid_t gid) if (gid != old_fsgid) { current->mm->dumpable = 0; - wmb(); + smp_wmb(); } current->fsgid = gid; key_fsgid_changed(current); diff --git a/kernel/timer.c b/kernel/timer.c index ecb3d67..207aa4f0 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1007,7 +1007,7 @@ asmlinkage long sys_getppid(void) * Make sure we read the pid before re-reading the * parent pointer: */ - rmb(); + smp_rmb(); parent = me->group_leader->real_parent; if (old != parent) continue; diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c index 21f0db2..40ffde9 100644 --- a/lib/rwsem-spinlock.c +++ b/lib/rwsem-spinlock.c @@ -76,7 +76,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) list_del(&waiter->list); tsk = waiter->task; /* Don't touch waiter after ->task has been NULLed */ - mb(); + smp_mb(); waiter->task = NULL; wake_up_process(tsk); put_task_struct(tsk); @@ -91,7 +91,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) list_del(&waiter->list); tsk = waiter->task; - mb(); + smp_mb(); waiter->task = NULL; wake_up_process(tsk); put_task_struct(tsk); @@ -123,7 +123,7 @@ __rwsem_wake_one_writer(struct rw_semaphore *sem) list_del(&waiter->list); tsk = waiter->task; - mb(); + smp_mb(); waiter->task = NULL; wake_up_process(tsk); put_task_struct(tsk); diff --git a/lib/rwsem.c b/lib/rwsem.c index 7644089..62fa4eb 100644 --- a/lib/rwsem.c +++ b/lib/rwsem.c @@ -74,7 +74,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int downgrading) */ list_del(&waiter->list); tsk = waiter->task; - mb(); + smp_mb(); waiter->task = NULL; wake_up_process(tsk); put_task_struct(tsk); @@ -117,7 +117,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int downgrading) waiter = list_entry(next, struct rwsem_waiter, list); next = waiter->list.next; tsk = waiter->task; - mb(); + smp_mb(); waiter->task = NULL; wake_up_process(tsk); put_task_struct(tsk); diff --git a/mm/mempool.c b/mm/mempool.c index e9a0a63..c9f3d46 100644 --- a/mm/mempool.c +++ b/mm/mempool.c @@ -229,7 +229,7 @@ repeat_alloc: /* Now start performing page reclaim */ gfp_temp = gfp_mask; prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE); - mb(); + smp_mb(); if (!pool->curr_nr) io_schedule(); finish_wait(&pool->wait, &wait); @@ -250,7 +250,7 @@ void mempool_free(void *element, mempool_t *pool) { unsigned long flags; - mb(); + smp_mb(); if (pool->curr_nr < pool->min_nr) { spin_lock_irqsave(&pool->lock, flags); if (pool->curr_nr < pool->min_nr) { -- cgit v0.10.2 From d637413f3f05b41f678f8004225b33b62274183f Mon Sep 17 00:00:00 2001 From: Jake Moilanen Date: Sun, 1 May 2005 08:58:47 -0700 Subject: [PATCH] ppc64: reverse prediction on spinlock busy loop code On our raw spinlocks, we currently have an attempt at the lock, and if we do not get it we enter a spin loop. This spinloop will likely continue for awhile, and we pridict likely. Shouldn't we predict that we will get out of the loop so our next instructions are already prefetched. Even when we miss because the lock is still held, it won't matter since we are waiting anyways. I did a couple quick benchmarks, but the results are inconclusive. 16-way 690 running specjbb with original code # ./specjbb 3000 16 1 1 19 30 120 ... Valid run, Score is 59282 16-way 690 running specjbb with unlikely code # ./specjbb 3000 16 1 1 19 30 120 ... Valid run, Score is 59541 I saw a smaller increase on a JS20 (~1.6%) JS20 specjbb w/ original code # ./specjbb 400 2 1 1 19 30 120 ... Valid run, Score is 20460 JS20 specjbb w/ unlikely code # ./specjbb 400 2 1 1 19 30 120 ... Valid run, Score is 20803 Anton said: Mispredicting the spinlock busy loop also means we slow down the rate at which we do the loads which can be good for heavily contended locks. Note: There are some gcc issues with our default build and branch prediction, but a CONFIG_POWER4_ONLY build should emit them correctly. I'm working with Alan Modra on it now. Signed-off-by: Jake Moilanen Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-ppc64/spinlock.h b/include/asm-ppc64/spinlock.h index a9b2a11..acd1156 100644 --- a/include/asm-ppc64/spinlock.h +++ b/include/asm-ppc64/spinlock.h @@ -110,7 +110,7 @@ static void __inline__ _raw_spin_lock(spinlock_t *lock) HMT_low(); if (SHARED_PROCESSOR) __spin_yield(lock); - } while (likely(lock->lock != 0)); + } while (unlikely(lock->lock != 0)); HMT_medium(); } } @@ -128,7 +128,7 @@ static void __inline__ _raw_spin_lock_flags(spinlock_t *lock, unsigned long flag HMT_low(); if (SHARED_PROCESSOR) __spin_yield(lock); - } while (likely(lock->lock != 0)); + } while (unlikely(lock->lock != 0)); HMT_medium(); local_irq_restore(flags_dis); } @@ -194,7 +194,7 @@ static void __inline__ _raw_read_lock(rwlock_t *rw) HMT_low(); if (SHARED_PROCESSOR) __rw_yield(rw); - } while (likely(rw->lock < 0)); + } while (unlikely(rw->lock < 0)); HMT_medium(); } } @@ -251,7 +251,7 @@ static void __inline__ _raw_write_lock(rwlock_t *rw) HMT_low(); if (SHARED_PROCESSOR) __rw_yield(rw); - } while (likely(rw->lock != 0)); + } while (unlikely(rw->lock != 0)); HMT_medium(); } } -- cgit v0.10.2 From d5b63d78f1e75f6c6f04862dfb2f2a4aeffafd4c Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sun, 1 May 2005 08:58:48 -0700 Subject: [PATCH] fix i386 memcpy This patch shortens non-constant memcpy() by two bytes and fixes spurious out-of-line constant memcpy(). # size vmlinux.org vmlinux text data bss dec hex filename 3954591 1553426 236544 5744561 57a7b1 vmlinux.org 3952615 1553426 236544 5742585 579ff9 vmlinux Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h index 1679983..6a78ac5 100644 --- a/include/asm-i386/string.h +++ b/include/asm-i386/string.h @@ -198,47 +198,80 @@ static inline void * __memcpy(void * to, const void * from, size_t n) int d0, d1, d2; __asm__ __volatile__( "rep ; movsl\n\t" - "testb $2,%b4\n\t" - "je 1f\n\t" - "movsw\n" - "1:\ttestb $1,%b4\n\t" - "je 2f\n\t" - "movsb\n" - "2:" + "movl %4,%%ecx\n\t" + "andl $3,%%ecx\n\t" +#if 1 /* want to pay 2 byte penalty for a chance to skip microcoded rep? */ + "jz 1f\n\t" +#endif + "rep ; movsb\n\t" + "1:" : "=&c" (d0), "=&D" (d1), "=&S" (d2) - :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) + : "0" (n/4), "g" (n), "1" ((long) to), "2" ((long) from) : "memory"); return (to); } /* - * This looks horribly ugly, but the compiler can optimize it totally, + * This looks ugly, but the compiler can optimize it totally, * as the count is constant. */ static inline void * __constant_memcpy(void * to, const void * from, size_t n) { - if (n <= 128) - return __builtin_memcpy(to, from, n); - -#define COMMON(x) \ -__asm__ __volatile__( \ - "rep ; movsl" \ - x \ - : "=&c" (d0), "=&D" (d1), "=&S" (d2) \ - : "0" (n/4),"1" ((long) to),"2" ((long) from) \ - : "memory"); -{ - int d0, d1, d2; + long esi, edi; + if (!n) return to; +#if 1 /* want to do small copies with non-string ops? */ + switch (n) { + case 1: *(char*)to = *(char*)from; return to; + case 2: *(short*)to = *(short*)from; return to; + case 4: *(int*)to = *(int*)from; return to; +#if 1 /* including those doable with two moves? */ + case 3: *(short*)to = *(short*)from; + *((char*)to+2) = *((char*)from+2); return to; + case 5: *(int*)to = *(int*)from; + *((char*)to+4) = *((char*)from+4); return to; + case 6: *(int*)to = *(int*)from; + *((short*)to+2) = *((short*)from+2); return to; + case 8: *(int*)to = *(int*)from; + *((int*)to+1) = *((int*)from+1); return to; +#endif + } +#endif + esi = (long) from; + edi = (long) to; + if (n >= 5*4) { + /* large block: use rep prefix */ + int ecx; + __asm__ __volatile__( + "rep ; movsl" + : "=&c" (ecx), "=&D" (edi), "=&S" (esi) + : "0" (n/4), "1" (edi),"2" (esi) + : "memory" + ); + } else { + /* small block: don't clobber ecx + smaller code */ + if (n >= 4*4) __asm__ __volatile__("movsl" + :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory"); + if (n >= 3*4) __asm__ __volatile__("movsl" + :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory"); + if (n >= 2*4) __asm__ __volatile__("movsl" + :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory"); + if (n >= 1*4) __asm__ __volatile__("movsl" + :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory"); + } switch (n % 4) { - case 0: COMMON(""); return to; - case 1: COMMON("\n\tmovsb"); return to; - case 2: COMMON("\n\tmovsw"); return to; - default: COMMON("\n\tmovsw\n\tmovsb"); return to; + /* tail */ + case 0: return to; + case 1: __asm__ __volatile__("movsb" + :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory"); + return to; + case 2: __asm__ __volatile__("movsw" + :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory"); + return to; + default: __asm__ __volatile__("movsw\n\tmovsb" + :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory"); + return to; } } - -#undef COMMON -} #define __HAVE_ARCH_MEMCPY -- cgit v0.10.2 From fd51f666fa591294bd7462447512666e61c56ea0 Mon Sep 17 00:00:00 2001 From: "H. J. Lu" Date: Sun, 1 May 2005 08:58:48 -0700 Subject: [PATCH] i386/x86_64 segment register access update The new i386/x86_64 assemblers no longer accept instructions for moving between a segment register and a 32bit memory location, i.e., movl (%eax),%ds movl %ds,(%eax) To generate instructions for moving between a segment register and a 16bit memory location without the 16bit operand size prefix, 0x66, mov (%eax),%ds mov %ds,(%eax) should be used. It will work with both new and old assemblers. The assembler starting from 2.16.90.0.1 will also support movw (%eax),%ds movw %ds,(%eax) without the 0x66 prefix. I am enclosing patches for 2.4 and 2.6 kernels here. The resulting kernel binaries should be unchanged as before, with old and new assemblers, if gcc never generates memory access for unsigned gsindex; asm volatile("movl %%gs,%0" : "=g" (gsindex)); If gcc does generate memory access for the code above, the upper bits in gsindex are undefined and the new assembler doesn't allow it. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index b2203e2..85bd56d 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -611,8 +611,8 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas * Save away %fs and %gs. No need to save %es and %ds, as * those are always kernel segments while inside the kernel. */ - asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs)); - asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs)); + asm volatile("mov %%fs,%0":"=m" (prev->fs)); + asm volatile("mov %%gs,%0":"=m" (prev->gs)); /* * Restore %fs and %gs if needed. diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index 2f3d52d..d16cd37 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -294,8 +294,8 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk */ info->regs32->eax = 0; tsk->thread.saved_esp0 = tsk->thread.esp0; - asm volatile("movl %%fs,%0":"=m" (tsk->thread.saved_fs)); - asm volatile("movl %%gs,%0":"=m" (tsk->thread.saved_gs)); + asm volatile("mov %%fs,%0":"=m" (tsk->thread.saved_fs)); + asm volatile("mov %%gs,%0":"=m" (tsk->thread.saved_gs)); tss = &per_cpu(init_tss, get_cpu()); tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 9922d2b..761b6d3 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -402,10 +402,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, p->thread.fs = me->thread.fs; p->thread.gs = me->thread.gs; - asm("movl %%gs,%0" : "=m" (p->thread.gsindex)); - asm("movl %%fs,%0" : "=m" (p->thread.fsindex)); - asm("movl %%es,%0" : "=m" (p->thread.es)); - asm("movl %%ds,%0" : "=m" (p->thread.ds)); + asm("mov %%gs,%0" : "=m" (p->thread.gsindex)); + asm("mov %%fs,%0" : "=m" (p->thread.fsindex)); + asm("mov %%es,%0" : "=m" (p->thread.es)); + asm("mov %%ds,%0" : "=m" (p->thread.ds)); if (unlikely(me->thread.io_bitmap_ptr != NULL)) { p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); @@ -468,11 +468,11 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct * * Switch DS and ES. * This won't pick up thread selector changes, but I guess that is ok. */ - asm volatile("movl %%es,%0" : "=m" (prev->es)); + asm volatile("mov %%es,%0" : "=m" (prev->es)); if (unlikely(next->es | prev->es)) loadsegment(es, next->es); - asm volatile ("movl %%ds,%0" : "=m" (prev->ds)); + asm volatile ("mov %%ds,%0" : "=m" (prev->ds)); if (unlikely(next->ds | prev->ds)) loadsegment(ds, next->ds); diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index 6f74d4c..3db717a 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -81,7 +81,7 @@ static inline unsigned long _get_base(char * addr) #define loadsegment(seg,value) \ asm volatile("\n" \ "1:\t" \ - "movl %0,%%" #seg "\n" \ + "mov %0,%%" #seg "\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3:\t" \ @@ -93,13 +93,13 @@ static inline unsigned long _get_base(char * addr) ".align 4\n\t" \ ".long 1b,3b\n" \ ".previous" \ - : :"m" (*(unsigned int *)&(value))) + : :"m" (value)) /* * Save a segment register away */ #define savesegment(seg, value) \ - asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value))) + asm volatile("mov %%" #seg ",%0":"=m" (value)) /* * Clear and set 'TS' bit respectively -- cgit v0.10.2 From 67701ae9767534534d3710664037dfde2cc04935 Mon Sep 17 00:00:00 2001 From: Jack F Vogel Date: Sun, 1 May 2005 08:58:48 -0700 Subject: [PATCH] check nmi watchdog is broken A bug against an xSeries system showed up recently noting that the check_nmi_watchdog() test was failing. I have been investigating it and discovered in both i386 and x86_64 the recent change to the routine to use the cpu_callin_map has uncovered a problem. Prior to that change, on an SMP box, the test was trivally passing because all cpu's were found to not yet be online, but now with the callin_map they are discovered, it goes on to test the counter and they have not yet begun to increment, so it announces a CPU is stuck and bails out. On all the systems I have access to test, the announcement of failure is also bougs... by the time you can login and check /proc/interrupts, the NMI count is happily incrementing on all CPUs. Its just that the test is being done too early. I have tried moving the call to the test around a bit, and it was always too early. I finally hit on this proposed solution, it delays the routine via a late_initcall(), seems like the right solution to me. Signed-off-by: Adrian Bunk Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index e3879f7..d509836 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -1265,8 +1265,6 @@ int __init APIC_init_uniprocessor (void) setup_local_APIC(); - if (nmi_watchdog == NMI_LOCAL_APIC) - check_nmi_watchdog(); #ifdef CONFIG_X86_IO_APIC if (smp_found_config) if (!skip_ioapic_setup && nr_ioapics) diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 5e0d55b..7a324e8 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -2175,7 +2175,6 @@ static inline void check_timer(void) disable_8259A_irq(0); setup_nmi(); enable_8259A_irq(0); - check_nmi_watchdog(); } return; } @@ -2198,7 +2197,6 @@ static inline void check_timer(void) add_pin_to_irq(0, 0, pin2); if (nmi_watchdog == NMI_IO_APIC) { setup_nmi(); - check_nmi_watchdog(); } return; } diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 2f89d00..2c0ee9c 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -102,20 +102,21 @@ int nmi_active; (P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \ P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE) -int __init check_nmi_watchdog (void) +static int __init check_nmi_watchdog(void) { unsigned int prev_nmi_count[NR_CPUS]; int cpu; - printk(KERN_INFO "testing NMI watchdog ... "); + if (nmi_watchdog == NMI_NONE) + return 0; + + printk(KERN_INFO "Testing NMI watchdog ... "); for (cpu = 0; cpu < NR_CPUS; cpu++) prev_nmi_count[cpu] = per_cpu(irq_stat, cpu).__nmi_count; local_irq_enable(); mdelay((10*1000)/nmi_hz); // wait 10 ticks - /* FIXME: Only boot CPU is online at this stage. Check CPUs - as they come up. */ for (cpu = 0; cpu < NR_CPUS; cpu++) { #ifdef CONFIG_SMP /* Check cpu_callin_map here because that is set @@ -139,6 +140,8 @@ int __init check_nmi_watchdog (void) return 0; } +/* This needs to happen later in boot so counters are working */ +late_initcall(check_nmi_watchdog); static int __init setup_nmi_watchdog(char *str) { diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index fd36d2f..cbea7ac 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -1089,9 +1089,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus) } } - if (nmi_watchdog == NMI_LOCAL_APIC) - check_nmi_watchdog(); - smpboot_setup_io_apic(); setup_boot_APIC_clock(); diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 29a2572..60be586 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1607,7 +1607,6 @@ static inline void check_timer(void) disable_8259A_irq(0); setup_nmi(); enable_8259A_irq(0); - check_nmi_watchdog(); } return; } @@ -1627,7 +1626,6 @@ static inline void check_timer(void) nmi_watchdog_default(); if (nmi_watchdog == NMI_IO_APIC) { setup_nmi(); - check_nmi_watchdog(); } return; } diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index e00d4ad..61de0b3 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -112,17 +112,20 @@ static __init int cpu_has_lapic(void) } } -int __init check_nmi_watchdog (void) +static int __init check_nmi_watchdog (void) { int counts[NR_CPUS]; int cpu; + if (nmi_watchdog == NMI_NONE) + return 0; + if (nmi_watchdog == NMI_LOCAL_APIC && !cpu_has_lapic()) { nmi_watchdog = NMI_NONE; return -1; } - printk(KERN_INFO "testing NMI watchdog ... "); + printk(KERN_INFO "Testing NMI watchdog ... "); for (cpu = 0; cpu < NR_CPUS; cpu++) counts[cpu] = cpu_pda[cpu].__nmi_count; @@ -148,6 +151,8 @@ int __init check_nmi_watchdog (void) return 0; } +/* Have this called later during boot so counters are updating */ +late_initcall(check_nmi_watchdog); int __init setup_nmi_watchdog(char *str) { diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index e1de674..a5810cf 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -109,7 +109,6 @@ extern int APIC_init_uniprocessor (void); extern void disable_APIC_timer(void); extern void enable_APIC_timer(void); -extern int check_nmi_watchdog (void); extern void enable_NMI_through_LVT0 (void * dummy); extern unsigned int nmi_watchdog; diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h index c025cc3..e4b1017 100644 --- a/include/asm-x86_64/apic.h +++ b/include/asm-x86_64/apic.h @@ -99,7 +99,6 @@ extern void disable_APIC_timer(void); extern void enable_APIC_timer(void); extern void clustered_apic_check(void); -extern int check_nmi_watchdog(void); extern void nmi_watchdog_default(void); extern int setup_nmi_watchdog(char *); -- cgit v0.10.2 From a2f7c354159b87dfbd9900f597d48d18755a9d16 Mon Sep 17 00:00:00 2001 From: Jaya Kumar Date: Sun, 1 May 2005 08:58:49 -0700 Subject: [PATCH] x86 reboot: Add reboot fixup for gx1/cs5530a This patch by Jaya Kumar introduces a generic infrastructure to deal with x86 chipsets with nonstandard reset sequences, and adds support for the Geode gx1/cs5530a chipset. Signed-off-by: Jaya Kumar Signed-off-by: H. Peter Anvin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 17a0cbc..99b4f29 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -653,6 +653,24 @@ config I8K Say Y if you intend to run this kernel on a Dell Inspiron 8000. Say N otherwise. +config X86_REBOOTFIXUPS + bool "Enable X86 board specific fixups for reboot" + depends on X86 + default n + ---help--- + This enables chipset and/or board specific fixups to be done + in order to get reboot to work correctly. This is only needed on + some combinations of hardware and BIOS. The symptom, for which + this config is intended, is when reboot ends with a stalled/hung + system. + + Currently, the only fixup is for the Geode GX1/CS5530A/TROM2.1. + combination. + + Say Y if you want to enable the fixup. Currently, it's safe to + enable this option even if you don't need it. + Say N otherwise. + config MICROCODE tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support" ---help--- diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index aacdae6..0fbcfe0 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o +obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o obj-$(CONFIG_KPROBES) += kprobes.o diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c index 3d7e994..6dc27eb 100644 --- a/arch/i386/kernel/reboot.c +++ b/arch/i386/kernel/reboot.c @@ -13,6 +13,7 @@ #include #include #include "mach_reboot.h" +#include /* * Power off function, if any @@ -348,6 +349,7 @@ void machine_restart(char * __unused) /* rebooting needs to touch the page at absolute addr 0 */ *((unsigned short *)__va(0x472)) = reboot_mode; for (;;) { + mach_reboot_fixups(); /* for board specific fixups */ mach_reboot(); /* That didn't work - force a triple fault.. */ __asm__ __volatile__("lidt %0": :"m" (no_idt)); diff --git a/arch/i386/kernel/reboot_fixups.c b/arch/i386/kernel/reboot_fixups.c new file mode 100644 index 0000000..1b183b3 --- /dev/null +++ b/arch/i386/kernel/reboot_fixups.c @@ -0,0 +1,56 @@ +/* + * linux/arch/i386/kernel/reboot_fixups.c + * + * This is a good place to put board specific reboot fixups. + * + * List of supported fixups: + * geode-gx1/cs5530a - Jaya Kumar + * + */ + +#include +#include + +static void cs5530a_warm_reset(struct pci_dev *dev) +{ + /* writing 1 to the reset control register, 0x44 causes the + cs5530a to perform a system warm reset */ + pci_write_config_byte(dev, 0x44, 0x1); + udelay(50); /* shouldn't get here but be safe and spin-a-while */ + return; +} + +struct device_fixup { + unsigned int vendor; + unsigned int device; + void (*reboot_fixup)(struct pci_dev *); +}; + +static struct device_fixup fixups_table[] = { +{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, cs5530a_warm_reset }, +}; + +/* + * we see if any fixup is available for our current hardware. if there + * is a fixup, we call it and we expect to never return from it. if we + * do return, we keep looking and then eventually fall back to the + * standard mach_reboot on return. + */ +void mach_reboot_fixups(void) +{ + struct device_fixup *cur; + struct pci_dev *dev; + int i; + + for (i=0; i < (sizeof(fixups_table)/sizeof(fixups_table[0])); i++) { + cur = &(fixups_table[i]); + dev = pci_get_device(cur->vendor, cur->device, 0); + if (!dev) + continue; + + cur->reboot_fixup(dev); + } + + printk(KERN_WARNING "No reboot fixup found for your hardware\n"); +} + diff --git a/include/linux/reboot_fixups.h b/include/linux/reboot_fixups.h new file mode 100644 index 0000000..480ea2d --- /dev/null +++ b/include/linux/reboot_fixups.h @@ -0,0 +1,10 @@ +#ifndef _LINUX_REBOOT_FIXUPS_H +#define _LINUX_REBOOT_FIXUPS_H + +#ifdef CONFIG_X86_REBOOTFIXUPS +extern void mach_reboot_fixups(void); +#else +#define mach_reboot_fixups() ((void)(0)) +#endif + +#endif /* _LINUX_REBOOT_FIXUPS_H */ -- cgit v0.10.2 From 48c88211a65bc30f030fe228bda30fda870deb90 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Sun, 1 May 2005 08:58:49 -0700 Subject: [PATCH] x86: entry.S trap return fixes do_debug() and do_int3() return void. This patch fixes the CONFIG_KPROBES variant of do_int3() to return void too and adjusts entry.S accordingly. Signed-off-by: Stas Sergeev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index fe1918c..25bf758 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -514,8 +514,6 @@ debug_stack_correct: xorl %edx,%edx # error code 0 movl %esp,%eax # pt_regs pointer call do_debug - testl %eax,%eax - jnz restore_all jmp ret_from_exception /* @@ -596,8 +594,6 @@ ENTRY(int3) xorl %edx,%edx # zero error code movl %esp,%eax # pt_regs pointer call do_int3 - testl %eax,%eax - jnz restore_all jmp ret_from_exception ENTRY(overflow) diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index d708194..00c6341 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -643,16 +643,15 @@ void unset_nmi_callback(void) } #ifdef CONFIG_KPROBES -fastcall int do_int3(struct pt_regs *regs, long error_code) +fastcall void do_int3(struct pt_regs *regs, long error_code) { if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) - return 1; + return; /* This is an interrupt gate, because kprobes wants interrupts disabled. Normal trap handlers don't. */ restore_interrupts(regs); do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); - return 0; } #endif -- cgit v0.10.2 From a6954ba2e8d344a07e066737827116eb7bc0fdcd Mon Sep 17 00:00:00 2001 From: Lee Revell Date: Sun, 1 May 2005 08:58:49 -0700 Subject: [PATCH] Enable write combining for server works LE rev > 6 Enable write combining for server works LE rev > 6 per http://www.ussg.iu.edu/hypermail/linux/kernel/0104.3/1007.html Signed-Off-By: Lee Revell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c index 54999e4..e1c2042 100644 --- a/arch/i386/kernel/cpu/mtrr/main.c +++ b/arch/i386/kernel/cpu/mtrr/main.c @@ -72,17 +72,21 @@ void set_mtrr_ops(struct mtrr_ops * ops) static int have_wrcomb(void) { struct pci_dev *dev; + u8 rev; if ((dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { - /* ServerWorks LE chipsets have problems with write-combining + /* ServerWorks LE chipsets < rev 6 have problems with write-combining Don't allow it and leave room for other chipsets to be tagged */ if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS && dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) { - printk(KERN_INFO "mtrr: Serverworks LE detected. Write-combining disabled.\n"); - pci_dev_put(dev); - return 0; + pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); + if (rev <= 5) { + printk(KERN_INFO "mtrr: Serverworks LE rev < 6 detected. Write-combining disabled.\n"); + pci_dev_put(dev); + return 0; + } } - /* Intel 450NX errata # 23. Non ascending cachline evictions to + /* Intel 450NX errata # 23. Non ascending cacheline evictions to write combining memory may resulting in data corruption */ if (dev->vendor == PCI_VENDOR_ID_INTEL && dev->device == PCI_DEVICE_ID_INTEL_82451NX) { -- cgit v0.10.2 From 5b7abc6fdcaf103f15e06c518ef0aec02a9c00e7 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sun, 1 May 2005 08:58:49 -0700 Subject: [PATCH] CPUID bug and inconsistency fix The recent support for K8 multicore was misported from x86-64 to i386, due to an unnecessary inconsistency between the CPUID code. Sure, there is are no x86-64 VIA chips yet, but it should happen eventually. This patch fixes the i386 bug as well as makes x86-64 match i386 in the handing of the CPUID array. Signed-off-by: H. Peter Anvin Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index b18c114..2959ce7 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -977,7 +977,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c) if ((xlvl & 0xffff0000) == 0x80000000) { if (xlvl >= 0x80000001) { c->x86_capability[1] = cpuid_edx(0x80000001); - c->x86_capability[5] = cpuid_ecx(0x80000001); + c->x86_capability[6] = cpuid_ecx(0x80000001); } if (xlvl >= 0x80000004) get_model_name(c); /* Default name */ @@ -1100,11 +1100,17 @@ static int show_cpuinfo(struct seq_file *m, void *v) NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /* VIA/Cyrix/Centaur-defined */ + NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /* AMD-defined (#2) */ "lahf_lm", "cmp_legacy", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; static char *x86_power_flags[] = { "ts", /* temperature sensor */ diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h index e147cab..ff1187e 100644 --- a/include/asm-i386/cpufeature.h +++ b/include/asm-i386/cpufeature.h @@ -87,8 +87,8 @@ #define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* on-CPU crypto enabled */ /* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */ -#define X86_FEATURE_LAHF_LM (5*32+ 0) /* LAHF/SAHF in long mode */ -#define X86_FEATURE_CMP_LEGACY (5*32+ 1) /* If yes HyperThreading not valid */ +#define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */ +#define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */ #define cpu_has(c, bit) test_bit(bit, (c)->x86_capability) #define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability) diff --git a/include/asm-x86_64/cpufeature.h b/include/asm-x86_64/cpufeature.h index e68ad97..aea308c 100644 --- a/include/asm-x86_64/cpufeature.h +++ b/include/asm-x86_64/cpufeature.h @@ -7,7 +7,7 @@ #ifndef __ASM_X8664_CPUFEATURE_H #define __ASM_X8664_CPUFEATURE_H -#define NCAPINTS 6 +#define NCAPINTS 7 /* N 32-bit words worth of info */ /* Intel-defined CPU features, CPUID level 0x00000001, word 0 */ #define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */ @@ -74,9 +74,15 @@ #define X86_FEATURE_CX16 (4*32+13) /* CMPXCHG16B */ #define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */ -/* More extended AMD flags: CPUID level 0x80000001, ecx, word 5 */ -#define X86_FEATURE_LAHF_LM (5*32+ 0) /* LAHF/SAHF in long mode */ -#define X86_FEATURE_CMP_LEGACY (5*32+ 1) /* If yes HyperThreading not valid */ +/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ +#define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */ +#define X86_FEATURE_XSTORE_EN (5*32+ 3) /* on-CPU RNG enabled */ +#define X86_FEATURE_XCRYPT (5*32+ 6) /* on-CPU crypto (xcrypt insn) */ +#define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* on-CPU crypto enabled */ + +/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */ +#define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */ +#define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */ #define cpu_has(c, bit) test_bit(bit, (c)->x86_capability) #define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability) -- cgit v0.10.2 From 35492df5ae0f36f717448b2aea908d3a8891d1c4 Mon Sep 17 00:00:00 2001 From: john stultz Date: Sun, 1 May 2005 08:58:50 -0700 Subject: [PATCH] i386: fix hpet for systems that don't support legacy replacement Currently the i386 HPET code assumes the entire HPET implementation from the spec is present. This breaks on boxes that do not implement the optional legacy timer replacement functionality portion of the spec. This patch, which is very similar to my x86-64 patch for the same issue, fixes the problem allowing i386 systems that cannot use the HPET for the timer interrupt and RTC to still use the HPET as a time source. I've tested this patch on a system systems without HPET, with HPET but without legacy timer replacement, as well as HPET with legacy timer replacement. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 4d75b37..a0dcb7c 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -441,7 +441,7 @@ static void __init hpet_time_init(void) set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); - if (hpet_enable() >= 0) { + if ((hpet_enable() >= 0) && hpet_use_timer) { printk("Using HPET for base-timer\n"); } diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c index 244a31b..10a0cbb 100644 --- a/arch/i386/kernel/time_hpet.c +++ b/arch/i386/kernel/time_hpet.c @@ -26,6 +26,7 @@ static unsigned long hpet_period; /* fsecs / HPET clock */ unsigned long hpet_tick; /* hpet clks count per tick */ unsigned long hpet_address; /* hpet memory map physical address */ +int hpet_use_timer; static int use_hpet; /* can be used for runtime check of hpet */ static int boot_hpet_disable; /* boottime override for HPET timer */ @@ -73,27 +74,30 @@ static int hpet_timer_stop_set_go(unsigned long tick) hpet_writel(0, HPET_COUNTER); hpet_writel(0, HPET_COUNTER + 4); - /* - * Set up timer 0, as periodic with first interrupt to happen at - * hpet_tick, and period also hpet_tick. - */ - cfg = hpet_readl(HPET_T0_CFG); - cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | - HPET_TN_SETVAL | HPET_TN_32BIT; - hpet_writel(cfg, HPET_T0_CFG); - - /* - * The first write after writing TN_SETVAL to the config register sets - * the counter value, the second write sets the threshold. - */ - hpet_writel(tick, HPET_T0_CMP); - hpet_writel(tick, HPET_T0_CMP); + if (hpet_use_timer) { + /* + * Set up timer 0, as periodic with first interrupt to happen at + * hpet_tick, and period also hpet_tick. + */ + cfg = hpet_readl(HPET_T0_CFG); + cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | + HPET_TN_SETVAL | HPET_TN_32BIT; + hpet_writel(cfg, HPET_T0_CFG); + /* + * The first write after writing TN_SETVAL to the config register sets + * the counter value, the second write sets the threshold. + */ + hpet_writel(tick, HPET_T0_CMP); + hpet_writel(tick, HPET_T0_CMP); + } /* * Go! */ cfg = hpet_readl(HPET_CFG); - cfg |= HPET_CFG_ENABLE | HPET_CFG_LEGACY; + if (hpet_use_timer) + cfg |= HPET_CFG_LEGACY; + cfg |= HPET_CFG_ENABLE; hpet_writel(cfg, HPET_CFG); return 0; @@ -128,12 +132,11 @@ int __init hpet_enable(void) * However, we can do with one timer otherwise using the * the single HPET timer for system time. */ - if ( #ifdef CONFIG_HPET_EMULATE_RTC - !(id & HPET_ID_NUMBER) || -#endif - !(id & HPET_ID_LEGSUP)) + if (!(id & HPET_ID_NUMBER)) return -1; +#endif + hpet_period = hpet_readl(HPET_PERIOD); if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > HPET_MAX_PERIOD)) @@ -152,6 +155,8 @@ int __init hpet_enable(void) if (hpet_tick_rem > (hpet_period >> 1)) hpet_tick++; /* rounding the result */ + hpet_use_timer = id & HPET_ID_LEGSUP; + if (hpet_timer_stop_set_go(hpet_tick)) return -1; @@ -202,7 +207,8 @@ int __init hpet_enable(void) #endif #ifdef CONFIG_X86_LOCAL_APIC - wait_timer_tick = wait_hpet_tick; + if (hpet_use_timer) + wait_timer_tick = wait_hpet_tick; #endif return 0; } diff --git a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c index 713134e..f778f47 100644 --- a/arch/i386/kernel/timers/timer_hpet.c +++ b/arch/i386/kernel/timers/timer_hpet.c @@ -79,7 +79,7 @@ static unsigned long get_offset_hpet(void) eax = hpet_readl(HPET_COUNTER); eax -= hpet_last; /* hpet delta */ - + eax = min(hpet_tick, eax); /* * Time offset = (hpet delta) * ( usecs per HPET clock ) * = (hpet delta) * ( usecs per tick / HPET clocks per tick) @@ -105,9 +105,12 @@ static void mark_offset_hpet(void) last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; rdtsc(last_tsc_low, last_tsc_high); - offset = hpet_readl(HPET_T0_CMP) - hpet_tick; - if (unlikely(((offset - hpet_last) > hpet_tick) && (hpet_last != 0))) { - int lost_ticks = (offset - hpet_last) / hpet_tick; + if (hpet_use_timer) + offset = hpet_readl(HPET_T0_CMP) - hpet_tick; + else + offset = hpet_readl(HPET_COUNTER); + if (unlikely(((offset - hpet_last) >= (2*hpet_tick)) && (hpet_last != 0))) { + int lost_ticks = ((offset - hpet_last) / hpet_tick) - 1; jiffies_64 += lost_ticks; } hpet_last = offset; diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c index a685994..7926d96 100644 --- a/arch/i386/kernel/timers/timer_tsc.c +++ b/arch/i386/kernel/timers/timer_tsc.c @@ -477,7 +477,7 @@ static int __init init_tsc(char* override) if (cpu_has_tsc) { unsigned long tsc_quotient; #ifdef CONFIG_HPET_TIMER - if (is_hpet_enabled()){ + if (is_hpet_enabled() && hpet_use_timer) { unsigned long result, remain; printk("Using TSC for gettimeofday\n"); tsc_quotient = calibrate_tsc_hpet(NULL); diff --git a/include/asm-i386/hpet.h b/include/asm-i386/hpet.h index 6e20b07..16ef9f9 100644 --- a/include/asm-i386/hpet.h +++ b/include/asm-i386/hpet.h @@ -92,6 +92,7 @@ extern unsigned long hpet_tick; /* hpet clks count per tick */ extern unsigned long hpet_address; /* hpet memory map physical address */ +extern int hpet_use_timer; extern int hpet_rtc_timer_init(void); extern int hpet_enable(void); -- cgit v0.10.2 From 4d24a439a6b2280357d62fb30a73350cf253bdb7 Mon Sep 17 00:00:00 2001 From: Jason Gaston Date: Sun, 1 May 2005 08:58:50 -0700 Subject: [PATCH] irq and pci_ids for Intel ICH7DH & ICH7-M DH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the Intel ICH7DH and ICH7-M DH DID's to the irq.c and pci_ids.h files. Signed-off-by:  Jason Gaston Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index e07589d..d6598da 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -495,6 +495,8 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route case PCI_DEVICE_ID_INTEL_ICH6_1: case PCI_DEVICE_ID_INTEL_ICH7_0: case PCI_DEVICE_ID_INTEL_ICH7_1: + case PCI_DEVICE_ID_INTEL_ICH7_30: + case PCI_DEVICE_ID_INTEL_ICH7_31: case PCI_DEVICE_ID_INTEL_ESB2_0: r->name = "PIIX/ICH"; r->get = pirq_piix_get; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6a18974..5d5820a 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2415,6 +2415,8 @@ #define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9 #define PCI_DEVICE_ID_INTEL_ICH7_2 0x27c0 #define PCI_DEVICE_ID_INTEL_ICH7_3 0x27c1 +#define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0 +#define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd #define PCI_DEVICE_ID_INTEL_ICH7_5 0x27c4 #define PCI_DEVICE_ID_INTEL_ICH7_6 0x27c5 #define PCI_DEVICE_ID_INTEL_ICH7_7 0x27c8 -- cgit v0.10.2 From 2f1b381825411fd3d5c8323dd1be77438e19e192 Mon Sep 17 00:00:00 2001 From: Jason Gaston Date: Sun, 1 May 2005 08:58:50 -0700 Subject: [PATCH] hda_intel: Intel ESB2 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the Intel ESB2 HD Audio DID to the hda_intel.c audio driver. Signed-off-by:  Jason Gaston Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d89647a..959953c 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -64,7 +64,8 @@ MODULE_PARM_DESC(model, "Use the given board model."); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH6M}," - "{Intel, ICH7}}"); + "{Intel, ICH7}," + "{Intel, ESB2}}"); MODULE_DESCRIPTION("Intel HDA driver"); #define SFX "hda-intel: " @@ -1422,6 +1423,7 @@ static void __devexit azx_remove(struct pci_dev *pci) static struct pci_device_id azx_ids[] = { { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */ { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */ + { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); -- cgit v0.10.2 From 3c3b73b6f50a47601b1897deb9c6b4b5ecadf591 Mon Sep 17 00:00:00 2001 From: Zwane Mwaikambo Date: Sun, 1 May 2005 08:58:51 -0700 Subject: [PATCH] cpuid x87 bit on AMD falsely marked as PNI http://bugme.osdl.org/show_bug.cgi?id=4426 vendor_id : AuthenticAMD cpu family : 6 model : 10 model name : AMD Athlon(tm) XP stepping : 0 cpu MHz : 2204.807 cpuid level : 1 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 mmx fxsr sse pni syscall mmxext 3dnowext 3dnow bogomips : 4358.14 We're marking bit 0 of extended function 0x80000001 cpuid as PNI support on AMD processors, when it actually denotes x87 FPU present. Patch for i386 and x86_64 below. Signed-off-by: Zwane Mwaikambo Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c index 4f28eba..7323c19 100644 --- a/arch/i386/kernel/cpu/proc.c +++ b/arch/i386/kernel/cpu/proc.c @@ -25,7 +25,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe", /* AMD-defined */ - "pni", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL, NULL, "fxsr_opt", NULL, NULL, NULL, "lm", "3dnowext", "3dnow", diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 2959ce7..2129cf9 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -1076,7 +1076,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL, /* AMD-defined */ - "pni", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL, NULL, "fxsr_opt", NULL, NULL, NULL, "lm", "3dnowext", "3dnow", -- cgit v0.10.2 From be9e68703c53fece406bc2e40976a5cfe2a8e77f Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sun, 1 May 2005 08:58:51 -0700 Subject: [PATCH] x86_64: interrupt handling fix - Initialize workmask correctly on interrupt signal handling - Readd missing cli's in the interrupt return path. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index 3233a15..1086b5f 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -296,6 +296,7 @@ int_very_careful: call syscall_trace_leave popq %rdi andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi + cli jmp int_restore_rest int_signal: @@ -307,6 +308,7 @@ int_signal: 1: movl $_TIF_NEED_RESCHED,%edi int_restore_rest: RESTORE_REST + cli jmp int_with_check CFI_ENDPROC @@ -490,7 +492,8 @@ retint_signal: call do_notify_resume RESTORE_REST cli - GET_THREAD_INFO(%rcx) + GET_THREAD_INFO(%rcx) + movl $_TIF_WORK_MASK,%edi jmp retint_check #ifdef CONFIG_PREEMPT -- cgit v0.10.2 From f9ba70535dc12d9eb57d466a2ecd749e16eca866 Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Sun, 1 May 2005 08:58:51 -0700 Subject: [PATCH] Increase number of e820 entries hard limit from 32 to 128 The specifications that talk about E820 map doesn't have an upper limit on the number of e820 entries. But, today's kernel has a hard limit of 32. With increase in memory size, we are seeing the number of E820 entries reaching close to 32. Patch below bumps the number upto 128. The patch changes the location of EDDBUF in zero-page (as it comes after E820). As, EDDBUF is not used by boot loaders, this patch should not have any effect on bootloader-setup code interface. Patch covers both i386 and x86-64. Tested on: * grub booting bzImage * lilo booting bzImage with EDID info enabled * pxeboot of bzImage Side-effect: bss increases by ~ 2K and init.data increases by ~7.5K on all systems, due to increase in size of static arrays. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/i386/zero-page.txt b/Documentation/i386/zero-page.txt index 67c053a..df28c74 100644 --- a/Documentation/i386/zero-page.txt +++ b/Documentation/i386/zero-page.txt @@ -79,6 +79,6 @@ Offset Type Description 0x22c unsigned long ramdisk_max 0x230 16 bytes trampoline 0x290 - 0x2cf EDD_MBR_SIG_BUFFER (edd.S) -0x2d0 - 0x600 E820MAP -0x600 - 0x7ff EDDBUF (edd.S) for disk signature read sector -0x600 - 0x7eb EDDBUF (edd.S) for edd data +0x2d0 - 0xd00 E820MAP +0xd00 - 0xeff EDDBUF (edd.S) for disk signature read sector +0xd00 - 0xeeb EDDBUF (edd.S) for edd data diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index a934ab3..caa1fde 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -164,7 +164,7 @@ ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff trampoline: call start_of_setup .align 16 # The offset at this point is 0x240 - .space (0x7ff-0x240+1) # E820 & EDD space (ending at 0x7ff) + .space (0xeff-0x240+1) # E820 & EDD space (ending at 0xeff) # End of setup header ##################################################### start_of_setup: @@ -333,9 +333,9 @@ jmpe820: # sizeof(e820rec). # good820: - movb (E820NR), %al # up to 32 entries + movb (E820NR), %al # up to 128 entries cmpb $E820MAX, %al - jnl bail820 + jae bail820 incb (E820NR) movw %di, %ax diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S index 3e838be..75d4d2a 100644 --- a/arch/x86_64/boot/setup.S +++ b/arch/x86_64/boot/setup.S @@ -160,7 +160,7 @@ ramdisk_max: .long 0xffffffff trampoline: call start_of_setup .align 16 # The offset at this point is 0x240 - .space (0x7ff-0x240+1) # E820 & EDD space (ending at 0x7ff) + .space (0xeff-0x240+1) # E820 & EDD space (ending at 0xeff) # End of setup header ##################################################### start_of_setup: @@ -412,9 +412,9 @@ jmpe820: # sizeof(e820rec). # good820: - movb (E820NR), %al # up to 32 entries + movb (E820NR), %al # up to 128 entries cmpb $E820MAX, %al - jnl bail820 + jae bail820 incb (E820NR) movw %di, %ax diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c index 6cad46c..77df2cc 100644 --- a/arch/x86_64/kernel/head64.c +++ b/arch/x86_64/kernel/head64.c @@ -29,8 +29,6 @@ static void __init clear_bss(void) (unsigned long) __bss_end - (unsigned long) __bss_start); } -extern char x86_boot_params[2048]; - #define NEW_CL_POINTER 0x228 /* Relative to real mode data */ #define OLD_CL_MAGIC_ADDR 0x90020 #define OLD_CL_MAGIC 0xA33F @@ -44,7 +42,7 @@ static void __init copy_bootdata(char *real_mode_data) int new_data; char * command_line; - memcpy(x86_boot_params, real_mode_data, 2048); + memcpy(x86_boot_params, real_mode_data, BOOT_PARAM_SIZE); new_data = *(int *) (x86_boot_params + NEW_CL_POINTER); if (!new_data) { if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) { diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index b5305b0..678b7ac 100644 --- a/arch/x86_64/kernel/setup64.c +++ b/arch/x86_64/kernel/setup64.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,7 @@ #include #include -char x86_boot_params[2048] __initdata = {0,}; +char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,}; cpumask_t cpu_initialized __initdata = CPU_MASK_NONE; diff --git a/include/asm-i386/e820.h b/include/asm-i386/e820.h index 5c285ae..edf65be 100644 --- a/include/asm-i386/e820.h +++ b/include/asm-i386/e820.h @@ -13,7 +13,7 @@ #define __E820_HEADER #define E820MAP 0x2d0 /* our map */ -#define E820MAX 32 /* number of entries in E820MAP */ +#define E820MAX 128 /* number of entries in E820MAP */ #define E820NR 0x1e8 /* # entries in E820MAP */ #define E820_RAM 1 diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h index 8814b54..7a32184 100644 --- a/include/asm-i386/setup.h +++ b/include/asm-i386/setup.h @@ -16,7 +16,7 @@ #define MAXMEM_PFN PFN_DOWN(MAXMEM) #define MAX_NONPAE_PFN (1 << 20) -#define PARAM_SIZE 2048 +#define PARAM_SIZE 4096 #define COMMAND_LINE_SIZE 256 #define OLD_CL_MAGIC_ADDR 0x90020 diff --git a/include/asm-x86_64/bootsetup.h b/include/asm-x86_64/bootsetup.h index b570a48..b829f7b 100644 --- a/include/asm-x86_64/bootsetup.h +++ b/include/asm-x86_64/bootsetup.h @@ -2,7 +2,8 @@ #ifndef _X86_64_BOOTSETUP_H #define _X86_64_BOOTSETUP_H 1 -extern char x86_boot_params[2048]; +#define BOOT_PARAM_SIZE 4096 +extern char x86_boot_params[BOOT_PARAM_SIZE]; /* * This is set up by the setup-routine at boot-time diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h index 08f83a4..8e94edf 100644 --- a/include/asm-x86_64/e820.h +++ b/include/asm-x86_64/e820.h @@ -14,7 +14,7 @@ #include #define E820MAP 0x2d0 /* our map */ -#define E820MAX 32 /* number of entries in E820MAP */ +#define E820MAX 128 /* number of entries in E820MAP */ #define E820NR 0x1e8 /* # entries in E820MAP */ #define E820_RAM 1 diff --git a/include/linux/edd.h b/include/linux/edd.h index c6e6747..162512b 100644 --- a/include/linux/edd.h +++ b/include/linux/edd.h @@ -32,7 +32,7 @@ #define EDDNR 0x1e9 /* addr of number of edd_info structs at EDDBUF in boot_params - treat this as 1 byte */ -#define EDDBUF 0x600 /* addr of edd_info structs in boot_params */ +#define EDDBUF 0xd00 /* addr of edd_info structs in boot_params */ #define EDDMAXNR 6 /* number of edd_info structs starting at EDDBUF */ #define EDDEXTSIZE 8 /* change these if you muck with the structures */ #define EDDPARMSIZE 74 -- cgit v0.10.2 From ad6714230f2269d5d7db2cd1900fe7bfc7aa76dc Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Sun, 1 May 2005 08:58:52 -0700 Subject: [PATCH] Linux 2.6.x VM86 interrupt emulation fixes Patch solves VM86 interrupt emulation deadlock on SMP systems. The VM86 interrupt emulation has been heavily tested and works well on UP systems after last update, but it seems to deadlock when we have used it on SMP/HT boxes now. It seems, that disable_irq() cannot be called from interrupts, because it waits until disabled interrupt handler finishes (/kernel/irq/manage.c:synchronize_irq():while(IRQ_INPROGRESS);). This blocks one CPU after another. Solved by use disable_irq_nosync. There is the second problem. If IRQ source is fast, it is possible, that interrupt is sometimes processed and re-enabled by the second CPU, before it is disabled by the first one, but negative IRQ disable depths are not allowed. The spinlocking and disabling IRQs over call to disable_irq_nosync/enable_irq is the only solution found reliable till now. Signed-off-by: Michal Sojka Signed-off-by: Pavel Pisa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index d16cd37..d3b4c54 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -717,12 +717,12 @@ static irqreturn_t irq_handler(int intno, void *dev_id, struct pt_regs * regs) irqbits |= irq_bit; if (vm86_irqs[intno].sig) send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1); - spin_unlock_irqrestore(&irqbits_lock, flags); /* * IRQ will be re-enabled when user asks for the irq (whether * polling or as a result of the signal) */ - disable_irq(intno); + disable_irq_nosync(intno); + spin_unlock_irqrestore(&irqbits_lock, flags); return IRQ_HANDLED; out: @@ -754,17 +754,20 @@ static inline int get_and_reset_irq(int irqnumber) { int bit; unsigned long flags; + int ret = 0; if (invalid_vm86_irq(irqnumber)) return 0; if (vm86_irqs[irqnumber].tsk != current) return 0; spin_lock_irqsave(&irqbits_lock, flags); bit = irqbits & (1 << irqnumber); irqbits &= ~bit; + if (bit) { + enable_irq(irqnumber); + ret = 1; + } + spin_unlock_irqrestore(&irqbits_lock, flags); - if (!bit) - return 0; - enable_irq(irqnumber); - return 1; + return ret; } -- cgit v0.10.2 From 8059b2a292d59b6d94f9e3af93bf711f161c9476 Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Sun, 1 May 2005 08:58:52 -0700 Subject: [PATCH] x86-64: Handle empty E820 regions correctly Brings sanitize_e820_map() in x86-64 in sync with that of i386. x86_64 version was missing the changes from this patch. http://linux.bkbits.net:8080/linux-2.6/cset@3e5e4083Y3HevldZl5KCy94V4DcZww?nav=index.html|src/|src/arch|src/arch/i386|src/arch/i386/kernel|related/arch/i386/kernel/setup.c Signed-off-by: Venkatesh Pallipadi Acked-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index 56516ac..7c154df 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -2,6 +2,12 @@ * Handle the memory map. * The functions here do the job until bootmem takes over. * $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $ + * + * Getting sanitize_e820_map() in sync with i386 version by applying change: + * - Provisions for empty E820 memory regions (reported by certain BIOSes). + * Alex Achenbach , December 2002. + * Venkatesh Pallipadi + * */ #include #include @@ -277,7 +283,7 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) int chgidx, still_changing; int overlap_entries; int new_bios_entry; - int old_nr, new_nr; + int old_nr, new_nr, chg_nr; int i; /* @@ -331,20 +337,24 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) for (i=0; i < 2*old_nr; i++) change_point[i] = &change_point_list[i]; - /* record all known change-points (starting and ending addresses) */ + /* record all known change-points (starting and ending addresses), + omitting those that are for empty memory regions */ chgidx = 0; for (i=0; i < old_nr; i++) { - change_point[chgidx]->addr = biosmap[i].addr; - change_point[chgidx++]->pbios = &biosmap[i]; - change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; - change_point[chgidx++]->pbios = &biosmap[i]; + if (biosmap[i].size != 0) { + change_point[chgidx]->addr = biosmap[i].addr; + change_point[chgidx++]->pbios = &biosmap[i]; + change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; + change_point[chgidx++]->pbios = &biosmap[i]; + } } + chg_nr = chgidx; /* sort change-point list by memory addresses (low -> high) */ still_changing = 1; while (still_changing) { still_changing = 0; - for (i=1; i < 2*old_nr; i++) { + for (i=1; i < chg_nr; i++) { /* if > , swap */ /* or, if current= & last=, swap */ if ((change_point[i]->addr < change_point[i-1]->addr) || @@ -367,7 +377,7 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) last_type = 0; /* start with undefined memory type */ last_addr = 0; /* start with 0 as last starting address */ /* loop through change-points, determining affect on the new bios map */ - for (chgidx=0; chgidx < 2*old_nr; chgidx++) + for (chgidx=0; chgidx < chg_nr; chgidx++) { /* keep track of all overlapping bios entries */ if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) -- cgit v0.10.2 From 429e9c5eeb66fc272c15568849ad0b23689a4a06 Mon Sep 17 00:00:00 2001 From: Alexander Nyberg Date: Sun, 1 May 2005 08:58:52 -0700 Subject: [PATCH] x86_64: saved_command_line overflow fix This strcpy can run off the end of saved_command_line, and we don't need it any more anyway. Signed-off-by: Alexander Nyberg Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c index 77df2cc..0f8c78d 100644 --- a/arch/x86_64/kernel/head64.c +++ b/arch/x86_64/kernel/head64.c @@ -91,9 +91,6 @@ void __init x86_64_start_kernel(char * real_mode_data) #ifdef CONFIG_SMP cpu_set(0, cpu_online_map); #endif - /* default console: */ - if (!strstr(saved_command_line, "console=")) - strcat(saved_command_line, " console=tty0"); s = strstr(saved_command_line, "earlyprintk="); if (s != NULL) setup_early_printk(s); -- cgit v0.10.2 From 31df7b7fc6182b6c4e5c3b77084d0c026b3ac613 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Sun, 1 May 2005 08:58:52 -0700 Subject: [PATCH] hp100: fix card names Those cards really need A in their names. Otherwise it is pretty hard to find anything about them on the net. Signed-off-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index acb1701..b3a898c 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -13,8 +13,8 @@ ** This driver has only been tested with ** -- HP J2585B 10/100 Mbit/s PCI Busmaster ** -- HP J2585A 10/100 Mbit/s PCI -** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC -** -- HP J2973 10 Mbit/s PCI 10base-T +** -- HP J2970A 10 Mbit/s PCI Combo 10base-T/BNC +** -- HP J2973A 10 Mbit/s PCI 10base-T ** -- HP J2573 10/100 ISA ** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA ** -- Compex FreedomLine 100/VG 10/100 Mbit/s ISA / EISA / PCI -- cgit v0.10.2 From 92eac95287d75f220a8bbef6646f51a6497c4b4c Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sun, 1 May 2005 08:58:53 -0700 Subject: [PATCH] uml: fix oops related to exception table Paolo 'Blaisorblade' Giarrusso Prevent the kernel from oopsing during the extable sorting, as it can do now, because the extable is in the readonly section of the binary. Jeff says: The exception table turned RO in 2.6.11-rc3-mm1 for some reason. Moving it causes it to land in the writable data section of the binary. Paolo says: This patch fixes a oops on startup, which can be easily triggered by compiling with CONFIG_MODE_TT disabled, and STATIC_LINK either disabled or enabled. The resulting kernel will always Oops on startup, after printing this simple output: I've verified, by binary search on the BitKeeper repository (synced up as of 2.6.12-rc2), starting from the range 2.6.11-2.6.12-rc1, that this bug shows up on BitKeeper revisions in the range [@1.1994.11.168,+inf), i.e. starting from this: [PATCH] lib/sort: Replace insertion sort in exception tables Since UML does not use the exception table, it's likely that insertion sort didn't happen to write anything on the table. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-um/common.lds.S b/include/asm-um/common.lds.S index a3d6aab..1010153 100644 --- a/include/asm-um/common.lds.S +++ b/include/asm-um/common.lds.S @@ -8,11 +8,6 @@ _sdata = .; PROVIDE (sdata = .); - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - RODATA .unprotected : { *(.unprotected) } @@ -20,6 +15,10 @@ PROVIDE (_unprotected_end = .); . = ALIGN(4096); + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + __uml_setup_start = .; .uml.setup.init : { *(.uml.setup.init) } __uml_setup_end = .; -- cgit v0.10.2 From 8e7a4f69e4ed328aa09ce48601073052557fa85d Mon Sep 17 00:00:00 2001 From: "blaisorblade@yahoo.it" Date: Sun, 1 May 2005 08:58:53 -0700 Subject: [PATCH] uml: add nfsd syscall when nfsd is modular This trick is useless, because sys_ni.c will handle this problem by itself, like it does even on UML for other syscalls. Also, it does not provide the NFSD syscall when NFSD is compiled as a module, which is a big problem. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c index 7fc06c8..b671a31 100644 --- a/arch/um/kernel/sys_call_table.c +++ b/arch/um/kernel/sys_call_table.c @@ -14,12 +14,6 @@ #include "sysdep/syscalls.h" #include "kern_util.h" -#ifdef CONFIG_NFSD -#define NFSSERVCTL sys_nfsservctl -#else -#define NFSSERVCTL sys_ni_syscall -#endif - #define LAST_GENERIC_SYSCALL __NR_keyctl #if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL @@ -189,7 +183,7 @@ syscall_handler_t *sys_call_table[] = { [ __NR_getresuid ] = (syscall_handler_t *) sys_getresuid16, [ __NR_query_module ] = (syscall_handler_t *) sys_ni_syscall, [ __NR_poll ] = (syscall_handler_t *) sys_poll, - [ __NR_nfsservctl ] = (syscall_handler_t *) NFSSERVCTL, + [ __NR_nfsservctl ] = (syscall_handler_t *) sys_nfsservctl, [ __NR_setresgid ] = (syscall_handler_t *) sys_setresgid16, [ __NR_getresgid ] = (syscall_handler_t *) sys_getresgid16, [ __NR_prctl ] = (syscall_handler_t *) sys_prctl, -- cgit v0.10.2 From 6aec3072833283a5e2ecf07318bd383a67321657 Mon Sep 17 00:00:00 2001 From: Andree Leidenfrost Date: Sun, 1 May 2005 08:58:53 -0700 Subject: [PATCH] uml: fix handling of no fpx_regs Paolo 'Blaisorblade' Giarrusso Fix the error path, which is triggered when the processor misses the fpx regs (i.e. the "fxsr" cpuinfo feature). For instance by VIA C3 Samuel2. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c index 148645b..9a0ad09 100644 --- a/arch/um/os-Linux/sys-i386/registers.c +++ b/arch/um/os-Linux/sys-i386/registers.c @@ -105,14 +105,15 @@ void init_registers(int pid) panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", err); + errno = 0; err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs); if(!err) return; + if(errno != EIO) + panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", + errno); have_fpx_regs = 0; - if(err != EIO) - panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", - err); err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs); if(err) -- cgit v0.10.2 From b05d85a87d9711f5f5f2eb05c79038d5d5ff1f44 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 1 May 2005 08:58:54 -0700 Subject: [PATCH] uml: workaround old problematic sed behaviour Old versions of sed from 1998 (predating the first release of gcc 2.95, but still in use by debian stable) don't understand the single-line version of the sed append command. Since newer versions of sed still understand the... ahem, "vintage" form of the command, change our code to use that. Signed-off-by: Rob Landley Acked-by: Ian McDonald Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index dc796c1..280d300 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -53,6 +53,7 @@ quiet_cmd_quote2 = QUOTE $@ cmd_quote2 = sed -e '/CONFIG/{' \ -e 's/"CONFIG"\;/""/' \ -e 'r $(obj)/config.tmp' \ - -e 'a""\;' \ + -e 'a \' \ + -e '""\;' \ -e '}' \ $< > $@ -- cgit v0.10.2 From c45166be3cc666ce88fe623ad79276c943e74eff Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:58:54 -0700 Subject: [PATCH] uml: support AES i586 crypto driver We want to make possible, for the user, to enable the i586 AES implementation. This requires a restructure. - Add a CONFIG_UML_X86 to notify that we are building a UML for i386. - Rename CONFIG_64_BIT to CONFIG_64BIT as is used for all other archs - Tell crypto/Kconfig that UML_X86 is as good as X86 - Tell it that it must exclude not X86_64 but 64BIT, which will give the same results. - Tell kbuild to descend down into arch/i386/crypto/ to build what's needed. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 9a23df1..c529218 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -244,6 +244,7 @@ config KERNEL_HALF_GIGS config HIGHMEM bool "Highmem support" + depends on !64BIT config KERNEL_STACK_ORDER int "Kernel stack size order" diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig_i386 index 203c242..e41f374 100644 --- a/arch/um/Kconfig_i386 +++ b/arch/um/Kconfig_i386 @@ -1,4 +1,8 @@ -config 64_BIT +config UML_X86 + bool + default y + +config 64BIT bool default n diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64 index 768dc66..fd8d7e8 100644 --- a/arch/um/Kconfig_x86_64 +++ b/arch/um/Kconfig_x86_64 @@ -1,4 +1,8 @@ -config 64_BIT +config UML_X86 + bool + default y + +config 64BIT bool default y diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index 97b223b..f9e3c0f 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 @@ -1,4 +1,4 @@ -SUBARCH_CORE := arch/um/sys-i386/ +SUBARCH_CORE := arch/um/sys-i386/ arch/i386/crypto/ TOP_ADDR := $(CONFIG_TOP_ADDR) diff --git a/arch/um/defconfig b/arch/um/defconfig index fc3075c..4067c3a 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc1-bk1 -# Sun Mar 20 16:53:00 2005 +# Linux kernel version: 2.6.12-rc3-skas3-v9-pre2 +# Sun Apr 24 19:46:10 2005 # CONFIG_GENERIC_HARDIRQS=y CONFIG_UML=y @@ -15,7 +15,8 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y # CONFIG_MODE_TT=y CONFIG_MODE_SKAS=y -# CONFIG_64_BIT is not set +CONFIG_UML_X86=y +# CONFIG_64BIT is not set CONFIG_TOP_ADDR=0xc0000000 # CONFIG_3_LEVEL_PGTABLES is not set CONFIG_ARCH_HAS_SC_SIGNALS=y @@ -41,6 +42,7 @@ CONFIG_UML_REAL_TIME_CLOCK=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -158,7 +160,6 @@ CONFIG_UML_NET_SLIRP=y # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -412,6 +413,5 @@ CONFIG_DEBUG_INFO=y # CONFIG_DEBUG_FS is not set CONFIG_FRAME_POINTER=y CONFIG_PT_PROXY=y -# CONFIG_GPROF is not set # CONFIG_GCOV is not set # CONFIG_SYSCALL_DEBUG is not set diff --git a/crypto/Kconfig b/crypto/Kconfig index 536754f..90d6089 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -146,7 +146,7 @@ config CRYPTO_SERPENT config CRYPTO_AES tristate "AES cipher algorithms" - depends on CRYPTO && !(X86 && !X86_64) + depends on CRYPTO && !((X86 || UML_X86) && !64BIT) help AES cipher algorithms (FIPS-197). AES uses the Rijndael algorithm. @@ -166,7 +166,7 @@ config CRYPTO_AES config CRYPTO_AES_586 tristate "AES cipher algorithms (i586)" - depends on CRYPTO && (X86 && !X86_64) + depends on CRYPTO && ((X86 || UML_X86) && !64BIT) help AES cipher algorithms (FIPS-197). AES uses the Rijndael algorithm. diff --git a/include/asm-um/elf.h b/include/asm-um/elf.h index b3a7258..7908f8f 100644 --- a/include/asm-um/elf.h +++ b/include/asm-um/elf.h @@ -13,7 +13,7 @@ extern long elf_aux_hwcap; #define elf_check_arch(x) (1) -#ifdef CONFIG_64_BIT +#ifdef CONFIG_64BIT #define ELF_CLASS ELFCLASS64 #else #define ELF_CLASS ELFCLASS32 diff --git a/include/asm-um/page.h b/include/asm-um/page.h index 3620a08..102eb3d 100644 --- a/include/asm-um/page.h +++ b/include/asm-um/page.h @@ -27,7 +27,7 @@ struct page; #define clear_user_page(page, vaddr, pg) clear_page(page) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) -#if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64_BIT) +#if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64BIT) typedef struct { unsigned long pte_low, pte_high; } pte_t; typedef struct { unsigned long long pmd; } pmd_t; diff --git a/include/asm-um/pgtable-3level.h b/include/asm-um/pgtable-3level.h index bdbc3f9..d309f3a 100644 --- a/include/asm-um/pgtable-3level.h +++ b/include/asm-um/pgtable-3level.h @@ -145,7 +145,7 @@ static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot) */ #define PTE_FILE_MAX_BITS 32 -#ifdef CONFIG_64_BIT +#ifdef CONFIG_64BIT #define pte_to_pgoff(p) ((p).pte >> 32) -- cgit v0.10.2 From c16993d9009b4311f0e6088af38844eabc8b5e5b Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:58:54 -0700 Subject: [PATCH] uml: inline empty proc Cleanup: make an inline of this empty proc. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 1d719d5..7a94369 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -161,10 +161,6 @@ void *get_current(void) return(current); } -void prepare_to_copy(struct task_struct *tsk) -{ -} - int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index 038ba6f..4d94049 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h @@ -89,7 +89,11 @@ extern struct task_struct *alloc_task_struct(void); extern void release_thread(struct task_struct *); extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern void dump_thread(struct pt_regs *regs, struct user *u); -extern void prepare_to_copy(struct task_struct *tsk); + +static inline void prepare_to_copy(struct task_struct *tsk) +{ +} + extern unsigned long thread_saved_pc(struct task_struct *t); -- cgit v0.10.2 From e9c527163d31da9f616e989a90429729525c5233 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:58:54 -0700 Subject: [PATCH] uml: move va_copy conditional def GCC 2.95 uses __va_copy instead of va_copy. Handle it inside compiler.h instead of in a casual file, and avoid the risk that this breaks with a newer compiler (which it could do). Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 7575ec4..f7da9d0 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include "linux/compiler.h" #include "linux/stddef.h" #include "linux/kernel.h" #include "linux/string.h" @@ -61,8 +62,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) void *arg; int *res; - /* Some old gccs recognize __va_copy, but not va_copy */ - __va_copy(args, *(va_list *)arg_ptr); + va_copy(args, *(va_list *)arg_ptr); addr = va_arg(args, unsigned long); len = va_arg(args, int); is_write = va_arg(args, int); diff --git a/include/linux/compiler-gcc2.h b/include/linux/compiler-gcc2.h index 5a35915..ebed1766 100644 --- a/include/linux/compiler-gcc2.h +++ b/include/linux/compiler-gcc2.h @@ -22,3 +22,8 @@ # define __attribute_pure__ __attribute__((pure)) # define __attribute_const__ __attribute__((__const__)) #endif + +/* GCC 2.95.x/2.96 recognize __va_copy, but not va_copy. Actually later GCC's + * define both va_copy and __va_copy, but the latter may go away, so limit this + * to this header */ +#define va_copy __va_copy -- cgit v0.10.2 From 5e7b83ffc67e15791d9bf8b2a18e4f5fd0eb69b8 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:58:55 -0700 Subject: [PATCH] uml: fix syscall table by including $(SUBARCH)'s one, for i386 Split the i386 entry.S files into entry.S and syscall_table.S which is included in the previous one (so actually there is no difference between them) and use the syscall_table.S in the UML build, instead of tracking by hand the syscall table changes (which is inherently error-prone). We must only insert the right #defines to inject the changes we need from the i386 syscall table (for instance some different function names); also, we don't implement some i386 syscalls, as ioperm(), nor some TLS-related ones (yet to provide). Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 25bf758..a991d4e 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -652,296 +652,6 @@ ENTRY(spurious_interrupt_bug) pushl $do_spurious_interrupt_bug jmp error_code -.data -ENTRY(sys_call_table) - .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ - .long sys_exit - .long sys_fork - .long sys_read - .long sys_write - .long sys_open /* 5 */ - .long sys_close - .long sys_waitpid - .long sys_creat - .long sys_link - .long sys_unlink /* 10 */ - .long sys_execve - .long sys_chdir - .long sys_time - .long sys_mknod - .long sys_chmod /* 15 */ - .long sys_lchown16 - .long sys_ni_syscall /* old break syscall holder */ - .long sys_stat - .long sys_lseek - .long sys_getpid /* 20 */ - .long sys_mount - .long sys_oldumount - .long sys_setuid16 - .long sys_getuid16 - .long sys_stime /* 25 */ - .long sys_ptrace - .long sys_alarm - .long sys_fstat - .long sys_pause - .long sys_utime /* 30 */ - .long sys_ni_syscall /* old stty syscall holder */ - .long sys_ni_syscall /* old gtty syscall holder */ - .long sys_access - .long sys_nice - .long sys_ni_syscall /* 35 - old ftime syscall holder */ - .long sys_sync - .long sys_kill - .long sys_rename - .long sys_mkdir - .long sys_rmdir /* 40 */ - .long sys_dup - .long sys_pipe - .long sys_times - .long sys_ni_syscall /* old prof syscall holder */ - .long sys_brk /* 45 */ - .long sys_setgid16 - .long sys_getgid16 - .long sys_signal - .long sys_geteuid16 - .long sys_getegid16 /* 50 */ - .long sys_acct - .long sys_umount /* recycled never used phys() */ - .long sys_ni_syscall /* old lock syscall holder */ - .long sys_ioctl - .long sys_fcntl /* 55 */ - .long sys_ni_syscall /* old mpx syscall holder */ - .long sys_setpgid - .long sys_ni_syscall /* old ulimit syscall holder */ - .long sys_olduname - .long sys_umask /* 60 */ - .long sys_chroot - .long sys_ustat - .long sys_dup2 - .long sys_getppid - .long sys_getpgrp /* 65 */ - .long sys_setsid - .long sys_sigaction - .long sys_sgetmask - .long sys_ssetmask - .long sys_setreuid16 /* 70 */ - .long sys_setregid16 - .long sys_sigsuspend - .long sys_sigpending - .long sys_sethostname - .long sys_setrlimit /* 75 */ - .long sys_old_getrlimit - .long sys_getrusage - .long sys_gettimeofday - .long sys_settimeofday - .long sys_getgroups16 /* 80 */ - .long sys_setgroups16 - .long old_select - .long sys_symlink - .long sys_lstat - .long sys_readlink /* 85 */ - .long sys_uselib - .long sys_swapon - .long sys_reboot - .long old_readdir - .long old_mmap /* 90 */ - .long sys_munmap - .long sys_truncate - .long sys_ftruncate - .long sys_fchmod - .long sys_fchown16 /* 95 */ - .long sys_getpriority - .long sys_setpriority - .long sys_ni_syscall /* old profil syscall holder */ - .long sys_statfs - .long sys_fstatfs /* 100 */ - .long sys_ioperm - .long sys_socketcall - .long sys_syslog - .long sys_setitimer - .long sys_getitimer /* 105 */ - .long sys_newstat - .long sys_newlstat - .long sys_newfstat - .long sys_uname - .long sys_iopl /* 110 */ - .long sys_vhangup - .long sys_ni_syscall /* old "idle" system call */ - .long sys_vm86old - .long sys_wait4 - .long sys_swapoff /* 115 */ - .long sys_sysinfo - .long sys_ipc - .long sys_fsync - .long sys_sigreturn - .long sys_clone /* 120 */ - .long sys_setdomainname - .long sys_newuname - .long sys_modify_ldt - .long sys_adjtimex - .long sys_mprotect /* 125 */ - .long sys_sigprocmask - .long sys_ni_syscall /* old "create_module" */ - .long sys_init_module - .long sys_delete_module - .long sys_ni_syscall /* 130: old "get_kernel_syms" */ - .long sys_quotactl - .long sys_getpgid - .long sys_fchdir - .long sys_bdflush - .long sys_sysfs /* 135 */ - .long sys_personality - .long sys_ni_syscall /* reserved for afs_syscall */ - .long sys_setfsuid16 - .long sys_setfsgid16 - .long sys_llseek /* 140 */ - .long sys_getdents - .long sys_select - .long sys_flock - .long sys_msync - .long sys_readv /* 145 */ - .long sys_writev - .long sys_getsid - .long sys_fdatasync - .long sys_sysctl - .long sys_mlock /* 150 */ - .long sys_munlock - .long sys_mlockall - .long sys_munlockall - .long sys_sched_setparam - .long sys_sched_getparam /* 155 */ - .long sys_sched_setscheduler - .long sys_sched_getscheduler - .long sys_sched_yield - .long sys_sched_get_priority_max - .long sys_sched_get_priority_min /* 160 */ - .long sys_sched_rr_get_interval - .long sys_nanosleep - .long sys_mremap - .long sys_setresuid16 - .long sys_getresuid16 /* 165 */ - .long sys_vm86 - .long sys_ni_syscall /* Old sys_query_module */ - .long sys_poll - .long sys_nfsservctl - .long sys_setresgid16 /* 170 */ - .long sys_getresgid16 - .long sys_prctl - .long sys_rt_sigreturn - .long sys_rt_sigaction - .long sys_rt_sigprocmask /* 175 */ - .long sys_rt_sigpending - .long sys_rt_sigtimedwait - .long sys_rt_sigqueueinfo - .long sys_rt_sigsuspend - .long sys_pread64 /* 180 */ - .long sys_pwrite64 - .long sys_chown16 - .long sys_getcwd - .long sys_capget - .long sys_capset /* 185 */ - .long sys_sigaltstack - .long sys_sendfile - .long sys_ni_syscall /* reserved for streams1 */ - .long sys_ni_syscall /* reserved for streams2 */ - .long sys_vfork /* 190 */ - .long sys_getrlimit - .long sys_mmap2 - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ - .long sys_lstat64 - .long sys_fstat64 - .long sys_lchown - .long sys_getuid - .long sys_getgid /* 200 */ - .long sys_geteuid - .long sys_getegid - .long sys_setreuid - .long sys_setregid - .long sys_getgroups /* 205 */ - .long sys_setgroups - .long sys_fchown - .long sys_setresuid - .long sys_getresuid - .long sys_setresgid /* 210 */ - .long sys_getresgid - .long sys_chown - .long sys_setuid - .long sys_setgid - .long sys_setfsuid /* 215 */ - .long sys_setfsgid - .long sys_pivot_root - .long sys_mincore - .long sys_madvise - .long sys_getdents64 /* 220 */ - .long sys_fcntl64 - .long sys_ni_syscall /* reserved for TUX */ - .long sys_ni_syscall - .long sys_gettid - .long sys_readahead /* 225 */ - .long sys_setxattr - .long sys_lsetxattr - .long sys_fsetxattr - .long sys_getxattr - .long sys_lgetxattr /* 230 */ - .long sys_fgetxattr - .long sys_listxattr - .long sys_llistxattr - .long sys_flistxattr - .long sys_removexattr /* 235 */ - .long sys_lremovexattr - .long sys_fremovexattr - .long sys_tkill - .long sys_sendfile64 - .long sys_futex /* 240 */ - .long sys_sched_setaffinity - .long sys_sched_getaffinity - .long sys_set_thread_area - .long sys_get_thread_area - .long sys_io_setup /* 245 */ - .long sys_io_destroy - .long sys_io_getevents - .long sys_io_submit - .long sys_io_cancel - .long sys_fadvise64 /* 250 */ - .long sys_ni_syscall - .long sys_exit_group - .long sys_lookup_dcookie - .long sys_epoll_create - .long sys_epoll_ctl /* 255 */ - .long sys_epoll_wait - .long sys_remap_file_pages - .long sys_set_tid_address - .long sys_timer_create - .long sys_timer_settime /* 260 */ - .long sys_timer_gettime - .long sys_timer_getoverrun - .long sys_timer_delete - .long sys_clock_settime - .long sys_clock_gettime /* 265 */ - .long sys_clock_getres - .long sys_clock_nanosleep - .long sys_statfs64 - .long sys_fstatfs64 - .long sys_tgkill /* 270 */ - .long sys_utimes - .long sys_fadvise64_64 - .long sys_ni_syscall /* sys_vserver */ - .long sys_mbind - .long sys_get_mempolicy - .long sys_set_mempolicy - .long sys_mq_open - .long sys_mq_unlink - .long sys_mq_timedsend - .long sys_mq_timedreceive /* 280 */ - .long sys_mq_notify - .long sys_mq_getsetattr - .long sys_ni_syscall /* reserved for kexec */ - .long sys_waitid - .long sys_ni_syscall /* 285 */ /* available */ - .long sys_add_key - .long sys_request_key - .long sys_keyctl +#include "syscall_table.S" syscall_table_size=(.-sys_call_table) diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S new file mode 100644 index 0000000..6cd1ed3 --- /dev/null +++ b/arch/i386/kernel/syscall_table.S @@ -0,0 +1,291 @@ +.data +ENTRY(sys_call_table) + .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ + .long sys_exit + .long sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_waitpid + .long sys_creat + .long sys_link + .long sys_unlink /* 10 */ + .long sys_execve + .long sys_chdir + .long sys_time + .long sys_mknod + .long sys_chmod /* 15 */ + .long sys_lchown16 + .long sys_ni_syscall /* old break syscall holder */ + .long sys_stat + .long sys_lseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_oldumount + .long sys_setuid16 + .long sys_getuid16 + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_fstat + .long sys_pause + .long sys_utime /* 30 */ + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ + .long sys_access + .long sys_nice + .long sys_ni_syscall /* 35 - old ftime syscall holder */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ + .long sys_setgid16 + .long sys_getgid16 + .long sys_signal + .long sys_geteuid16 + .long sys_getegid16 /* 50 */ + .long sys_acct + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_setpgid + .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_olduname + .long sys_umask /* 60 */ + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_sigaction + .long sys_sgetmask + .long sys_ssetmask + .long sys_setreuid16 /* 70 */ + .long sys_setregid16 + .long sys_sigsuspend + .long sys_sigpending + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_old_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups16 /* 80 */ + .long sys_setgroups16 + .long old_select + .long sys_symlink + .long sys_lstat + .long sys_readlink /* 85 */ + .long sys_uselib + .long sys_swapon + .long sys_reboot + .long old_readdir + .long old_mmap /* 90 */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown16 /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* old profil syscall holder */ + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_ioperm + .long sys_socketcall + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_uname + .long sys_iopl /* 110 */ + .long sys_vhangup + .long sys_ni_syscall /* old "idle" system call */ + .long sys_vm86old + .long sys_wait4 + .long sys_swapoff /* 115 */ + .long sys_sysinfo + .long sys_ipc + .long sys_fsync + .long sys_sigreturn + .long sys_clone /* 120 */ + .long sys_setdomainname + .long sys_newuname + .long sys_modify_ldt + .long sys_adjtimex + .long sys_mprotect /* 125 */ + .long sys_sigprocmask + .long sys_ni_syscall /* old "create_module" */ + .long sys_init_module + .long sys_delete_module + .long sys_ni_syscall /* 130: old "get_kernel_syms" */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush + .long sys_sysfs /* 135 */ + .long sys_personality + .long sys_ni_syscall /* reserved for afs_syscall */ + .long sys_setfsuid16 + .long sys_setfsgid16 + .long sys_llseek /* 140 */ + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_msync + .long sys_readv /* 145 */ + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl + .long sys_mlock /* 150 */ + .long sys_munlock + .long sys_mlockall + .long sys_munlockall + .long sys_sched_setparam + .long sys_sched_getparam /* 155 */ + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max + .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_mremap + .long sys_setresuid16 + .long sys_getresuid16 /* 165 */ + .long sys_vm86 + .long sys_ni_syscall /* Old sys_query_module */ + .long sys_poll + .long sys_nfsservctl + .long sys_setresgid16 /* 170 */ + .long sys_getresgid16 + .long sys_prctl + .long sys_rt_sigreturn + .long sys_rt_sigaction + .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend + .long sys_pread64 /* 180 */ + .long sys_pwrite64 + .long sys_chown16 + .long sys_getcwd + .long sys_capget + .long sys_capset /* 185 */ + .long sys_sigaltstack + .long sys_sendfile + .long sys_ni_syscall /* reserved for streams1 */ + .long sys_ni_syscall /* reserved for streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ + .long sys_lstat64 + .long sys_fstat64 + .long sys_lchown + .long sys_getuid + .long sys_getgid /* 200 */ + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid + .long sys_getgroups /* 205 */ + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid + .long sys_setresgid /* 210 */ + .long sys_getresgid + .long sys_chown + .long sys_setuid + .long sys_setgid + .long sys_setfsuid /* 215 */ + .long sys_setfsgid + .long sys_pivot_root + .long sys_mincore + .long sys_madvise + .long sys_getdents64 /* 220 */ + .long sys_fcntl64 + .long sys_ni_syscall /* reserved for TUX */ + .long sys_ni_syscall + .long sys_gettid + .long sys_readahead /* 225 */ + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr + .long sys_getxattr + .long sys_lgetxattr /* 230 */ + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr + .long sys_flistxattr + .long sys_removexattr /* 235 */ + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_tkill + .long sys_sendfile64 + .long sys_futex /* 240 */ + .long sys_sched_setaffinity + .long sys_sched_getaffinity + .long sys_set_thread_area + .long sys_get_thread_area + .long sys_io_setup /* 245 */ + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel + .long sys_fadvise64 /* 250 */ + .long sys_ni_syscall + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl /* 255 */ + .long sys_epoll_wait + .long sys_remap_file_pages + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 260 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 265 */ + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 + .long sys_tgkill /* 270 */ + .long sys_utimes + .long sys_fadvise64_64 + .long sys_ni_syscall /* sys_vserver */ + .long sys_mbind + .long sys_get_mempolicy + .long sys_set_mempolicy + .long sys_mq_open + .long sys_mq_unlink + .long sys_mq_timedsend + .long sys_mq_timedreceive /* 280 */ + .long sys_mq_notify + .long sys_mq_getsetattr + .long sys_ni_syscall /* reserved for kexec */ + .long sys_waitid + .long sys_ni_syscall /* 285 */ /* available */ + .long sys_add_key + .long sys_request_key + .long sys_keyctl diff --git a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h index 5db81ec..be0a3e3 100644 --- a/arch/um/include/sysdep-i386/syscalls.h +++ b/arch/um/include/sysdep-i386/syscalls.h @@ -22,102 +22,3 @@ extern syscall_handler_t old_mmap_i386; extern long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff); - -/* On i386 they choose a meaningless naming.*/ -#define __NR_kexec_load __NR_sys_kexec_load - -#define ARCH_SYSCALLS \ - [ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid, \ - [ __NR_break ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_oldstat ] = (syscall_handler_t *) sys_stat, \ - [ __NR_umount ] = (syscall_handler_t *) sys_oldumount, \ - [ __NR_stime ] = um_stime, \ - [ __NR_oldfstat ] = (syscall_handler_t *) sys_fstat, \ - [ __NR_stty ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_gtty ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_nice ] = (syscall_handler_t *) sys_nice, \ - [ __NR_ftime ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_prof ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_signal ] = (syscall_handler_t *) sys_signal, \ - [ __NR_lock ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_mpx ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_ulimit ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_oldolduname ] = (syscall_handler_t *) sys_olduname, \ - [ __NR_sigaction ] = (syscall_handler_t *) sys_sigaction, \ - [ __NR_sgetmask ] = (syscall_handler_t *) sys_sgetmask, \ - [ __NR_ssetmask ] = (syscall_handler_t *) sys_ssetmask, \ - [ __NR_sigsuspend ] = (syscall_handler_t *) sys_sigsuspend, \ - [ __NR_sigpending ] = (syscall_handler_t *) sys_sigpending, \ - [ __NR_oldlstat ] = (syscall_handler_t *) sys_lstat, \ - [ __NR_readdir ] = old_readdir, \ - [ __NR_profil ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_socketcall ] = (syscall_handler_t *) sys_socketcall, \ - [ __NR_olduname ] = (syscall_handler_t *) sys_uname, \ - [ __NR_iopl ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_idle ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_ipc ] = (syscall_handler_t *) sys_ipc, \ - [ __NR_sigreturn ] = (syscall_handler_t *) sys_sigreturn, \ - [ __NR_sigprocmask ] = (syscall_handler_t *) sys_sigprocmask, \ - [ __NR_bdflush ] = (syscall_handler_t *) sys_bdflush, \ - [ __NR__llseek ] = (syscall_handler_t *) sys_llseek, \ - [ __NR__newselect ] = (syscall_handler_t *) sys_select, \ - [ __NR_vm86 ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_mmap ] = (syscall_handler_t *) old_mmap_i386, \ - [ __NR_ugetrlimit ] = (syscall_handler_t *) sys_getrlimit, \ - [ __NR_mmap2 ] = (syscall_handler_t *) sys_mmap2, \ - [ __NR_truncate64 ] = (syscall_handler_t *) sys_truncate64, \ - [ __NR_ftruncate64 ] = (syscall_handler_t *) sys_ftruncate64, \ - [ __NR_stat64 ] = (syscall_handler_t *) sys_stat64, \ - [ __NR_lstat64 ] = (syscall_handler_t *) sys_lstat64, \ - [ __NR_fstat64 ] = (syscall_handler_t *) sys_fstat64, \ - [ __NR_fcntl64 ] = (syscall_handler_t *) sys_fcntl64, \ - [ __NR_sendfile64 ] = (syscall_handler_t *) sys_sendfile64, \ - [ __NR_statfs64 ] = (syscall_handler_t *) sys_statfs64, \ - [ __NR_fstatfs64 ] = (syscall_handler_t *) sys_fstatfs64, \ - [ __NR_fadvise64_64 ] = (syscall_handler_t *) sys_fadvise64_64, \ - [ __NR_select ] = (syscall_handler_t *) old_select, \ - [ __NR_vm86old ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_modify_ldt ] = (syscall_handler_t *) sys_modify_ldt, \ - [ __NR_lchown32 ] = (syscall_handler_t *) sys_lchown, \ - [ __NR_getuid32 ] = (syscall_handler_t *) sys_getuid, \ - [ __NR_getgid32 ] = (syscall_handler_t *) sys_getgid, \ - [ __NR_geteuid32 ] = (syscall_handler_t *) sys_geteuid, \ - [ __NR_getegid32 ] = (syscall_handler_t *) sys_getegid, \ - [ __NR_setreuid32 ] = (syscall_handler_t *) sys_setreuid, \ - [ __NR_setregid32 ] = (syscall_handler_t *) sys_setregid, \ - [ __NR_getgroups32 ] = (syscall_handler_t *) sys_getgroups, \ - [ __NR_setgroups32 ] = (syscall_handler_t *) sys_setgroups, \ - [ __NR_fchown32 ] = (syscall_handler_t *) sys_fchown, \ - [ __NR_setresuid32 ] = (syscall_handler_t *) sys_setresuid, \ - [ __NR_getresuid32 ] = (syscall_handler_t *) sys_getresuid, \ - [ __NR_setresgid32 ] = (syscall_handler_t *) sys_setresgid, \ - [ __NR_getresgid32 ] = (syscall_handler_t *) sys_getresgid, \ - [ __NR_chown32 ] = (syscall_handler_t *) sys_chown, \ - [ __NR_setuid32 ] = (syscall_handler_t *) sys_setuid, \ - [ __NR_setgid32 ] = (syscall_handler_t *) sys_setgid, \ - [ __NR_setfsuid32 ] = (syscall_handler_t *) sys_setfsuid, \ - [ __NR_setfsgid32 ] = (syscall_handler_t *) sys_setfsgid, \ - [ __NR_pivot_root ] = (syscall_handler_t *) sys_pivot_root, \ - [ __NR_mincore ] = (syscall_handler_t *) sys_mincore, \ - [ __NR_madvise ] = (syscall_handler_t *) sys_madvise, \ - [ 222 ] = (syscall_handler_t *) sys_ni_syscall, \ - [ 223 ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_set_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_get_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \ - [ 251 ] = (syscall_handler_t *) sys_ni_syscall, \ - [ 285 ] = (syscall_handler_t *) sys_ni_syscall, - -/* 222 doesn't yet have a name in include/asm-i386/unistd.h */ - -#define LAST_ARCH_SYSCALL 285 - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h index b187a41..65a01e3 100644 --- a/arch/um/include/sysdep-x86_64/syscalls.h +++ b/arch/um/include/sysdep-x86_64/syscalls.h @@ -78,14 +78,3 @@ extern syscall_handler_t sys_arch_prctl; #define NR_syscalls 1024 #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 280d300..246f0e7 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -10,7 +10,7 @@ obj-y = checksum.o config.o exec_kern.o exitcode.o \ helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \ physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \ sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ - syscall_kern.o sysrq.o sys_call_table.o tempfile.o time.o time_kern.o \ + syscall_kern.o sysrq.o tempfile.o time.o time_kern.o \ tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o umid.o \ user_util.o diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c deleted file mode 100644 index b671a31..0000000 --- a/arch/um/kernel/sys_call_table.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Copyright 2003 PathScale, Inc. - * Licensed under the GPL - */ - -#include "linux/config.h" -#include "linux/unistd.h" -#include "linux/sys.h" -#include "linux/swap.h" -#include "linux/syscalls.h" -#include "linux/sysctl.h" -#include "asm/signal.h" -#include "sysdep/syscalls.h" -#include "kern_util.h" - -#define LAST_GENERIC_SYSCALL __NR_keyctl - -#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL -#define LAST_SYSCALL LAST_GENERIC_SYSCALL -#else -#define LAST_SYSCALL LAST_ARCH_SYSCALL -#endif - -extern syscall_handler_t sys_fork; -extern syscall_handler_t sys_execve; -extern syscall_handler_t um_time; -extern syscall_handler_t um_stime; -extern syscall_handler_t sys_pipe; -extern syscall_handler_t sys_olduname; -extern syscall_handler_t sys_sigaction; -extern syscall_handler_t sys_sigsuspend; -extern syscall_handler_t old_readdir; -extern syscall_handler_t sys_uname; -extern syscall_handler_t sys_ipc; -extern syscall_handler_t sys_sigreturn; -extern syscall_handler_t sys_clone; -extern syscall_handler_t sys_rt_sigreturn; -extern syscall_handler_t sys_sigaltstack; -extern syscall_handler_t sys_vfork; -extern syscall_handler_t old_select; -extern syscall_handler_t sys_modify_ldt; -extern syscall_handler_t sys_rt_sigsuspend; -extern syscall_handler_t sys_mbind; -extern syscall_handler_t sys_get_mempolicy; -extern syscall_handler_t sys_set_mempolicy; -extern syscall_handler_t sys_sys_setaltroot; - -syscall_handler_t *sys_call_table[] = { - [ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall, - [ __NR_exit ] = (syscall_handler_t *) sys_exit, - [ __NR_fork ] = (syscall_handler_t *) sys_fork, - [ __NR_read ] = (syscall_handler_t *) sys_read, - [ __NR_write ] = (syscall_handler_t *) sys_write, - - /* These three are declared differently in asm/unistd.h */ - [ __NR_open ] = (syscall_handler_t *) sys_open, - [ __NR_close ] = (syscall_handler_t *) sys_close, - [ __NR_creat ] = (syscall_handler_t *) sys_creat, - [ __NR_link ] = (syscall_handler_t *) sys_link, - [ __NR_unlink ] = (syscall_handler_t *) sys_unlink, - [ __NR_execve ] = (syscall_handler_t *) sys_execve, - - /* declared differently in kern_util.h */ - [ __NR_chdir ] = (syscall_handler_t *) sys_chdir, - [ __NR_time ] = um_time, - [ __NR_mknod ] = (syscall_handler_t *) sys_mknod, - [ __NR_chmod ] = (syscall_handler_t *) sys_chmod, - [ __NR_lchown ] = (syscall_handler_t *) sys_lchown16, - [ __NR_lseek ] = (syscall_handler_t *) sys_lseek, - [ __NR_getpid ] = (syscall_handler_t *) sys_getpid, - [ __NR_mount ] = (syscall_handler_t *) sys_mount, - [ __NR_setuid ] = (syscall_handler_t *) sys_setuid16, - [ __NR_getuid ] = (syscall_handler_t *) sys_getuid16, - [ __NR_ptrace ] = (syscall_handler_t *) sys_ptrace, - [ __NR_alarm ] = (syscall_handler_t *) sys_alarm, - [ __NR_pause ] = (syscall_handler_t *) sys_pause, - [ __NR_utime ] = (syscall_handler_t *) sys_utime, - [ __NR_access ] = (syscall_handler_t *) sys_access, - [ __NR_sync ] = (syscall_handler_t *) sys_sync, - [ __NR_kill ] = (syscall_handler_t *) sys_kill, - [ __NR_rename ] = (syscall_handler_t *) sys_rename, - [ __NR_mkdir ] = (syscall_handler_t *) sys_mkdir, - [ __NR_rmdir ] = (syscall_handler_t *) sys_rmdir, - - /* Declared differently in asm/unistd.h */ - [ __NR_dup ] = (syscall_handler_t *) sys_dup, - [ __NR_pipe ] = (syscall_handler_t *) sys_pipe, - [ __NR_times ] = (syscall_handler_t *) sys_times, - [ __NR_brk ] = (syscall_handler_t *) sys_brk, - [ __NR_setgid ] = (syscall_handler_t *) sys_setgid16, - [ __NR_getgid ] = (syscall_handler_t *) sys_getgid16, - [ __NR_geteuid ] = (syscall_handler_t *) sys_geteuid16, - [ __NR_getegid ] = (syscall_handler_t *) sys_getegid16, - [ __NR_acct ] = (syscall_handler_t *) sys_acct, - [ __NR_umount2 ] = (syscall_handler_t *) sys_umount, - [ __NR_ioctl ] = (syscall_handler_t *) sys_ioctl, - [ __NR_fcntl ] = (syscall_handler_t *) sys_fcntl, - [ __NR_setpgid ] = (syscall_handler_t *) sys_setpgid, - [ __NR_umask ] = (syscall_handler_t *) sys_umask, - [ __NR_chroot ] = (syscall_handler_t *) sys_chroot, - [ __NR_ustat ] = (syscall_handler_t *) sys_ustat, - [ __NR_dup2 ] = (syscall_handler_t *) sys_dup2, - [ __NR_getppid ] = (syscall_handler_t *) sys_getppid, - [ __NR_getpgrp ] = (syscall_handler_t *) sys_getpgrp, - [ __NR_setsid ] = (syscall_handler_t *) sys_setsid, - [ __NR_setreuid ] = (syscall_handler_t *) sys_setreuid16, - [ __NR_setregid ] = (syscall_handler_t *) sys_setregid16, - [ __NR_sethostname ] = (syscall_handler_t *) sys_sethostname, - [ __NR_setrlimit ] = (syscall_handler_t *) sys_setrlimit, - [ __NR_getrlimit ] = (syscall_handler_t *) sys_old_getrlimit, - [ __NR_getrusage ] = (syscall_handler_t *) sys_getrusage, - [ __NR_gettimeofday ] = (syscall_handler_t *) sys_gettimeofday, - [ __NR_settimeofday ] = (syscall_handler_t *) sys_settimeofday, - [ __NR_getgroups ] = (syscall_handler_t *) sys_getgroups16, - [ __NR_setgroups ] = (syscall_handler_t *) sys_setgroups16, - [ __NR_symlink ] = (syscall_handler_t *) sys_symlink, - [ __NR_readlink ] = (syscall_handler_t *) sys_readlink, - [ __NR_uselib ] = (syscall_handler_t *) sys_uselib, - [ __NR_swapon ] = (syscall_handler_t *) sys_swapon, - [ __NR_reboot ] = (syscall_handler_t *) sys_reboot, - [ __NR_munmap ] = (syscall_handler_t *) sys_munmap, - [ __NR_truncate ] = (syscall_handler_t *) sys_truncate, - [ __NR_ftruncate ] = (syscall_handler_t *) sys_ftruncate, - [ __NR_fchmod ] = (syscall_handler_t *) sys_fchmod, - [ __NR_fchown ] = (syscall_handler_t *) sys_fchown16, - [ __NR_getpriority ] = (syscall_handler_t *) sys_getpriority, - [ __NR_setpriority ] = (syscall_handler_t *) sys_setpriority, - [ __NR_statfs ] = (syscall_handler_t *) sys_statfs, - [ __NR_fstatfs ] = (syscall_handler_t *) sys_fstatfs, - [ __NR_ioperm ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_syslog ] = (syscall_handler_t *) sys_syslog, - [ __NR_setitimer ] = (syscall_handler_t *) sys_setitimer, - [ __NR_getitimer ] = (syscall_handler_t *) sys_getitimer, - [ __NR_stat ] = (syscall_handler_t *) sys_newstat, - [ __NR_lstat ] = (syscall_handler_t *) sys_newlstat, - [ __NR_fstat ] = (syscall_handler_t *) sys_newfstat, - [ __NR_vhangup ] = (syscall_handler_t *) sys_vhangup, - [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4, - [ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff, - [ __NR_sysinfo ] = (syscall_handler_t *) sys_sysinfo, - [ __NR_fsync ] = (syscall_handler_t *) sys_fsync, - [ __NR_clone ] = (syscall_handler_t *) sys_clone, - [ __NR_setdomainname ] = (syscall_handler_t *) sys_setdomainname, - [ __NR_uname ] = (syscall_handler_t *) sys_newuname, - [ __NR_adjtimex ] = (syscall_handler_t *) sys_adjtimex, - [ __NR_mprotect ] = (syscall_handler_t *) sys_mprotect, - [ __NR_create_module ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_init_module ] = (syscall_handler_t *) sys_init_module, - [ __NR_delete_module ] = (syscall_handler_t *) sys_delete_module, - [ __NR_get_kernel_syms ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_quotactl ] = (syscall_handler_t *) sys_quotactl, - [ __NR_getpgid ] = (syscall_handler_t *) sys_getpgid, - [ __NR_fchdir ] = (syscall_handler_t *) sys_fchdir, - [ __NR_sysfs ] = (syscall_handler_t *) sys_sysfs, - [ __NR_personality ] = (syscall_handler_t *) sys_personality, - [ __NR_afs_syscall ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_setfsuid ] = (syscall_handler_t *) sys_setfsuid16, - [ __NR_setfsgid ] = (syscall_handler_t *) sys_setfsgid16, - [ __NR_getdents ] = (syscall_handler_t *) sys_getdents, - [ __NR_flock ] = (syscall_handler_t *) sys_flock, - [ __NR_msync ] = (syscall_handler_t *) sys_msync, - [ __NR_readv ] = (syscall_handler_t *) sys_readv, - [ __NR_writev ] = (syscall_handler_t *) sys_writev, - [ __NR_getsid ] = (syscall_handler_t *) sys_getsid, - [ __NR_fdatasync ] = (syscall_handler_t *) sys_fdatasync, - [ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl, - [ __NR_mlock ] = (syscall_handler_t *) sys_mlock, - [ __NR_munlock ] = (syscall_handler_t *) sys_munlock, - [ __NR_mlockall ] = (syscall_handler_t *) sys_mlockall, - [ __NR_munlockall ] = (syscall_handler_t *) sys_munlockall, - [ __NR_sched_setparam ] = (syscall_handler_t *) sys_sched_setparam, - [ __NR_sched_getparam ] = (syscall_handler_t *) sys_sched_getparam, - [ __NR_sched_setscheduler ] = (syscall_handler_t *) sys_sched_setscheduler, - [ __NR_sched_getscheduler ] = (syscall_handler_t *) sys_sched_getscheduler, - [ __NR_sched_yield ] = (syscall_handler_t *) yield, - [ __NR_sched_get_priority_max ] = (syscall_handler_t *) sys_sched_get_priority_max, - [ __NR_sched_get_priority_min ] = (syscall_handler_t *) sys_sched_get_priority_min, - [ __NR_sched_rr_get_interval ] = (syscall_handler_t *) sys_sched_rr_get_interval, - [ __NR_nanosleep ] = (syscall_handler_t *) sys_nanosleep, - [ __NR_mremap ] = (syscall_handler_t *) sys_mremap, - [ __NR_setresuid ] = (syscall_handler_t *) sys_setresuid16, - [ __NR_getresuid ] = (syscall_handler_t *) sys_getresuid16, - [ __NR_query_module ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_poll ] = (syscall_handler_t *) sys_poll, - [ __NR_nfsservctl ] = (syscall_handler_t *) sys_nfsservctl, - [ __NR_setresgid ] = (syscall_handler_t *) sys_setresgid16, - [ __NR_getresgid ] = (syscall_handler_t *) sys_getresgid16, - [ __NR_prctl ] = (syscall_handler_t *) sys_prctl, - [ __NR_rt_sigreturn ] = (syscall_handler_t *) sys_rt_sigreturn, - [ __NR_rt_sigaction ] = (syscall_handler_t *) sys_rt_sigaction, - [ __NR_rt_sigprocmask ] = (syscall_handler_t *) sys_rt_sigprocmask, - [ __NR_rt_sigpending ] = (syscall_handler_t *) sys_rt_sigpending, - [ __NR_rt_sigtimedwait ] = (syscall_handler_t *) sys_rt_sigtimedwait, - [ __NR_rt_sigqueueinfo ] = (syscall_handler_t *) sys_rt_sigqueueinfo, - [ __NR_rt_sigsuspend ] = (syscall_handler_t *) sys_rt_sigsuspend, - [ __NR_pread64 ] = (syscall_handler_t *) sys_pread64, - [ __NR_pwrite64 ] = (syscall_handler_t *) sys_pwrite64, - [ __NR_chown ] = (syscall_handler_t *) sys_chown16, - [ __NR_getcwd ] = (syscall_handler_t *) sys_getcwd, - [ __NR_capget ] = (syscall_handler_t *) sys_capget, - [ __NR_capset ] = (syscall_handler_t *) sys_capset, - [ __NR_sigaltstack ] = (syscall_handler_t *) sys_sigaltstack, - [ __NR_sendfile ] = (syscall_handler_t *) sys_sendfile, - [ __NR_getpmsg ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_putpmsg ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_vfork ] = (syscall_handler_t *) sys_vfork, - [ __NR_getdents64 ] = (syscall_handler_t *) sys_getdents64, - [ __NR_gettid ] = (syscall_handler_t *) sys_gettid, - [ __NR_readahead ] = (syscall_handler_t *) sys_readahead, - [ __NR_setxattr ] = (syscall_handler_t *) sys_setxattr, - [ __NR_lsetxattr ] = (syscall_handler_t *) sys_lsetxattr, - [ __NR_fsetxattr ] = (syscall_handler_t *) sys_fsetxattr, - [ __NR_getxattr ] = (syscall_handler_t *) sys_getxattr, - [ __NR_lgetxattr ] = (syscall_handler_t *) sys_lgetxattr, - [ __NR_fgetxattr ] = (syscall_handler_t *) sys_fgetxattr, - [ __NR_listxattr ] = (syscall_handler_t *) sys_listxattr, - [ __NR_llistxattr ] = (syscall_handler_t *) sys_llistxattr, - [ __NR_flistxattr ] = (syscall_handler_t *) sys_flistxattr, - [ __NR_removexattr ] = (syscall_handler_t *) sys_removexattr, - [ __NR_lremovexattr ] = (syscall_handler_t *) sys_lremovexattr, - [ __NR_fremovexattr ] = (syscall_handler_t *) sys_fremovexattr, - [ __NR_tkill ] = (syscall_handler_t *) sys_tkill, - [ __NR_futex ] = (syscall_handler_t *) sys_futex, - [ __NR_sched_setaffinity ] = (syscall_handler_t *) sys_sched_setaffinity, - [ __NR_sched_getaffinity ] = (syscall_handler_t *) sys_sched_getaffinity, - [ __NR_io_setup ] = (syscall_handler_t *) sys_io_setup, - [ __NR_io_destroy ] = (syscall_handler_t *) sys_io_destroy, - [ __NR_io_getevents ] = (syscall_handler_t *) sys_io_getevents, - [ __NR_io_submit ] = (syscall_handler_t *) sys_io_submit, - [ __NR_io_cancel ] = (syscall_handler_t *) sys_io_cancel, - [ __NR_exit_group ] = (syscall_handler_t *) sys_exit_group, - [ __NR_lookup_dcookie ] = (syscall_handler_t *) sys_lookup_dcookie, - [ __NR_epoll_create ] = (syscall_handler_t *) sys_epoll_create, - [ __NR_epoll_ctl ] = (syscall_handler_t *) sys_epoll_ctl, - [ __NR_epoll_wait ] = (syscall_handler_t *) sys_epoll_wait, - [ __NR_remap_file_pages ] = (syscall_handler_t *) sys_remap_file_pages, - [ __NR_set_tid_address ] = (syscall_handler_t *) sys_set_tid_address, - [ __NR_timer_create ] = (syscall_handler_t *) sys_timer_create, - [ __NR_timer_settime ] = (syscall_handler_t *) sys_timer_settime, - [ __NR_timer_gettime ] = (syscall_handler_t *) sys_timer_gettime, - [ __NR_timer_getoverrun ] = (syscall_handler_t *) sys_timer_getoverrun, - [ __NR_timer_delete ] = (syscall_handler_t *) sys_timer_delete, - [ __NR_clock_settime ] = (syscall_handler_t *) sys_clock_settime, - [ __NR_clock_gettime ] = (syscall_handler_t *) sys_clock_gettime, - [ __NR_clock_getres ] = (syscall_handler_t *) sys_clock_getres, - [ __NR_clock_nanosleep ] = (syscall_handler_t *) sys_clock_nanosleep, - [ __NR_tgkill ] = (syscall_handler_t *) sys_tgkill, - [ __NR_utimes ] = (syscall_handler_t *) sys_utimes, - [ __NR_fadvise64 ] = (syscall_handler_t *) sys_fadvise64, - [ __NR_vserver ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_mbind ] = (syscall_handler_t *) sys_mbind, - [ __NR_get_mempolicy ] = (syscall_handler_t *) sys_get_mempolicy, - [ __NR_set_mempolicy ] = (syscall_handler_t *) sys_set_mempolicy, - [ __NR_mq_open ] = (syscall_handler_t *) sys_mq_open, - [ __NR_mq_unlink ] = (syscall_handler_t *) sys_mq_unlink, - [ __NR_mq_timedsend ] = (syscall_handler_t *) sys_mq_timedsend, - [ __NR_mq_timedreceive ] = (syscall_handler_t *) sys_mq_timedreceive, - [ __NR_mq_notify ] = (syscall_handler_t *) sys_mq_notify, - [ __NR_mq_getsetattr ] = (syscall_handler_t *) sys_mq_getsetattr, - [ __NR_kexec_load ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_waitid ] = (syscall_handler_t *) sys_waitid, - [ __NR_add_key ] = (syscall_handler_t *) sys_add_key, - [ __NR_request_key ] = (syscall_handler_t *) sys_request_key, - [ __NR_keyctl ] = (syscall_handler_t *) sys_keyctl, - - ARCH_SYSCALLS - [ LAST_SYSCALL + 1 ... NR_syscalls ] = - (syscall_handler_t *) sys_ni_syscall -}; diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 71b47e6..950781e 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,5 +1,6 @@ obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ - ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o + ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \ + sys_call_table.o obj-$(CONFIG_HIGHMEM) += highmem.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S new file mode 100644 index 0000000..ad75c27 --- /dev/null +++ b/arch/um/sys-i386/sys_call_table.S @@ -0,0 +1,16 @@ +#include +/* Steal i386 syscall table for our purposes, but with some slight changes.*/ + +#define sys_iopl sys_ni_syscall +#define sys_ioperm sys_ni_syscall + +#define sys_vm86old sys_ni_syscall +#define sys_vm86 sys_ni_syscall +#define sys_set_thread_area sys_ni_syscall +#define sys_get_thread_area sys_ni_syscall + +#define sys_stime um_stime +#define sys_time um_time +#define old_mmap old_mmap_i386 + +#include "../../i386/kernel/syscall_table.S" diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 2129e31..274158e 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -6,7 +6,7 @@ lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \ ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \ - syscalls.o sysrq.o thunk.o + syscalls.o sysrq.o thunk.o sys_call_table.o USER_OBJS := ptrace_user.o sigcontext.o diff --git a/arch/um/sys-x86_64/sys_call_table.c b/arch/um/sys-x86_64/sys_call_table.c new file mode 100644 index 0000000..3f5efbf --- /dev/null +++ b/arch/um/sys-x86_64/sys_call_table.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. + * Licensed under the GPL + */ + +#include "linux/config.h" +#include "linux/unistd.h" +#include "linux/sys.h" +#include "linux/swap.h" +#include "linux/syscalls.h" +#include "linux/sysctl.h" +#include "asm/signal.h" +#include "sysdep/syscalls.h" +#include "kern_util.h" + +#ifdef CONFIG_NFSD +#define NFSSERVCTL sys_nfsservctl +#else +#define NFSSERVCTL sys_ni_syscall +#endif + +#define LAST_GENERIC_SYSCALL __NR_keyctl + +#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL +#define LAST_SYSCALL LAST_GENERIC_SYSCALL +#else +#define LAST_SYSCALL LAST_ARCH_SYSCALL +#endif + +extern syscall_handler_t sys_fork; +extern syscall_handler_t sys_execve; +extern syscall_handler_t um_time; +extern syscall_handler_t um_stime; +extern syscall_handler_t sys_pipe; +extern syscall_handler_t sys_olduname; +extern syscall_handler_t sys_sigaction; +extern syscall_handler_t sys_sigsuspend; +extern syscall_handler_t old_readdir; +extern syscall_handler_t sys_uname; +extern syscall_handler_t sys_ipc; +extern syscall_handler_t sys_sigreturn; +extern syscall_handler_t sys_clone; +extern syscall_handler_t sys_rt_sigreturn; +extern syscall_handler_t sys_sigaltstack; +extern syscall_handler_t sys_vfork; +extern syscall_handler_t old_select; +extern syscall_handler_t sys_modify_ldt; +extern syscall_handler_t sys_rt_sigsuspend; +extern syscall_handler_t sys_mbind; +extern syscall_handler_t sys_get_mempolicy; +extern syscall_handler_t sys_set_mempolicy; +extern syscall_handler_t sys_sys_setaltroot; + +syscall_handler_t *sys_call_table[] = { + [ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall, + [ __NR_exit ] = (syscall_handler_t *) sys_exit, + [ __NR_fork ] = (syscall_handler_t *) sys_fork, + [ __NR_read ] = (syscall_handler_t *) sys_read, + [ __NR_write ] = (syscall_handler_t *) sys_write, + + /* These three are declared differently in asm/unistd.h */ + [ __NR_open ] = (syscall_handler_t *) sys_open, + [ __NR_close ] = (syscall_handler_t *) sys_close, + [ __NR_creat ] = (syscall_handler_t *) sys_creat, + [ __NR_link ] = (syscall_handler_t *) sys_link, + [ __NR_unlink ] = (syscall_handler_t *) sys_unlink, + [ __NR_execve ] = (syscall_handler_t *) sys_execve, + + /* declared differently in kern_util.h */ + [ __NR_chdir ] = (syscall_handler_t *) sys_chdir, + [ __NR_time ] = um_time, + [ __NR_mknod ] = (syscall_handler_t *) sys_mknod, + [ __NR_chmod ] = (syscall_handler_t *) sys_chmod, + [ __NR_lchown ] = (syscall_handler_t *) sys_lchown16, + [ __NR_lseek ] = (syscall_handler_t *) sys_lseek, + [ __NR_getpid ] = (syscall_handler_t *) sys_getpid, + [ __NR_mount ] = (syscall_handler_t *) sys_mount, + [ __NR_setuid ] = (syscall_handler_t *) sys_setuid16, + [ __NR_getuid ] = (syscall_handler_t *) sys_getuid16, + [ __NR_ptrace ] = (syscall_handler_t *) sys_ptrace, + [ __NR_alarm ] = (syscall_handler_t *) sys_alarm, + [ __NR_pause ] = (syscall_handler_t *) sys_pause, + [ __NR_utime ] = (syscall_handler_t *) sys_utime, + [ __NR_access ] = (syscall_handler_t *) sys_access, + [ __NR_sync ] = (syscall_handler_t *) sys_sync, + [ __NR_kill ] = (syscall_handler_t *) sys_kill, + [ __NR_rename ] = (syscall_handler_t *) sys_rename, + [ __NR_mkdir ] = (syscall_handler_t *) sys_mkdir, + [ __NR_rmdir ] = (syscall_handler_t *) sys_rmdir, + + /* Declared differently in asm/unistd.h */ + [ __NR_dup ] = (syscall_handler_t *) sys_dup, + [ __NR_pipe ] = (syscall_handler_t *) sys_pipe, + [ __NR_times ] = (syscall_handler_t *) sys_times, + [ __NR_brk ] = (syscall_handler_t *) sys_brk, + [ __NR_setgid ] = (syscall_handler_t *) sys_setgid16, + [ __NR_getgid ] = (syscall_handler_t *) sys_getgid16, + [ __NR_geteuid ] = (syscall_handler_t *) sys_geteuid16, + [ __NR_getegid ] = (syscall_handler_t *) sys_getegid16, + [ __NR_acct ] = (syscall_handler_t *) sys_acct, + [ __NR_umount2 ] = (syscall_handler_t *) sys_umount, + [ __NR_ioctl ] = (syscall_handler_t *) sys_ioctl, + [ __NR_fcntl ] = (syscall_handler_t *) sys_fcntl, + [ __NR_setpgid ] = (syscall_handler_t *) sys_setpgid, + [ __NR_umask ] = (syscall_handler_t *) sys_umask, + [ __NR_chroot ] = (syscall_handler_t *) sys_chroot, + [ __NR_ustat ] = (syscall_handler_t *) sys_ustat, + [ __NR_dup2 ] = (syscall_handler_t *) sys_dup2, + [ __NR_getppid ] = (syscall_handler_t *) sys_getppid, + [ __NR_getpgrp ] = (syscall_handler_t *) sys_getpgrp, + [ __NR_setsid ] = (syscall_handler_t *) sys_setsid, + [ __NR_setreuid ] = (syscall_handler_t *) sys_setreuid16, + [ __NR_setregid ] = (syscall_handler_t *) sys_setregid16, + [ __NR_sethostname ] = (syscall_handler_t *) sys_sethostname, + [ __NR_setrlimit ] = (syscall_handler_t *) sys_setrlimit, + [ __NR_getrlimit ] = (syscall_handler_t *) sys_old_getrlimit, + [ __NR_getrusage ] = (syscall_handler_t *) sys_getrusage, + [ __NR_gettimeofday ] = (syscall_handler_t *) sys_gettimeofday, + [ __NR_settimeofday ] = (syscall_handler_t *) sys_settimeofday, + [ __NR_getgroups ] = (syscall_handler_t *) sys_getgroups16, + [ __NR_setgroups ] = (syscall_handler_t *) sys_setgroups16, + [ __NR_symlink ] = (syscall_handler_t *) sys_symlink, + [ __NR_readlink ] = (syscall_handler_t *) sys_readlink, + [ __NR_uselib ] = (syscall_handler_t *) sys_uselib, + [ __NR_swapon ] = (syscall_handler_t *) sys_swapon, + [ __NR_reboot ] = (syscall_handler_t *) sys_reboot, + [ __NR_munmap ] = (syscall_handler_t *) sys_munmap, + [ __NR_truncate ] = (syscall_handler_t *) sys_truncate, + [ __NR_ftruncate ] = (syscall_handler_t *) sys_ftruncate, + [ __NR_fchmod ] = (syscall_handler_t *) sys_fchmod, + [ __NR_fchown ] = (syscall_handler_t *) sys_fchown16, + [ __NR_getpriority ] = (syscall_handler_t *) sys_getpriority, + [ __NR_setpriority ] = (syscall_handler_t *) sys_setpriority, + [ __NR_statfs ] = (syscall_handler_t *) sys_statfs, + [ __NR_fstatfs ] = (syscall_handler_t *) sys_fstatfs, + [ __NR_ioperm ] = (syscall_handler_t *) sys_ni_syscall, + [ __NR_syslog ] = (syscall_handler_t *) sys_syslog, + [ __NR_setitimer ] = (syscall_handler_t *) sys_setitimer, + [ __NR_getitimer ] = (syscall_handler_t *) sys_getitimer, + [ __NR_stat ] = (syscall_handler_t *) sys_newstat, + [ __NR_lstat ] = (syscall_handler_t *) sys_newlstat, + [ __NR_fstat ] = (syscall_handler_t *) sys_newfstat, + [ __NR_vhangup ] = (syscall_handler_t *) sys_vhangup, + [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4, + [ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff, + [ __NR_sysinfo ] = (syscall_handler_t *) sys_sysinfo, + [ __NR_fsync ] = (syscall_handler_t *) sys_fsync, + [ __NR_clone ] = (syscall_handler_t *) sys_clone, + [ __NR_setdomainname ] = (syscall_handler_t *) sys_setdomainname, + [ __NR_uname ] = (syscall_handler_t *) sys_newuname, + [ __NR_adjtimex ] = (syscall_handler_t *) sys_adjtimex, + [ __NR_mprotect ] = (syscall_handler_t *) sys_mprotect, + [ __NR_create_module ] = (syscall_handler_t *) sys_ni_syscall, + [ __NR_init_module ] = (syscall_handler_t *) sys_init_module, + [ __NR_delete_module ] = (syscall_handler_t *) sys_delete_module, + [ __NR_get_kernel_syms ] = (syscall_handler_t *) sys_ni_syscall, + [ __NR_quotactl ] = (syscall_handler_t *) sys_quotactl, + [ __NR_getpgid ] = (syscall_handler_t *) sys_getpgid, + [ __NR_fchdir ] = (syscall_handler_t *) sys_fchdir, + [ __NR_sysfs ] = (syscall_handler_t *) sys_sysfs, + [ __NR_personality ] = (syscall_handler_t *) sys_personality, + [ __NR_afs_syscall ] = (syscall_handler_t *) sys_ni_syscall, + [ __NR_setfsuid ] = (syscall_handler_t *) sys_setfsuid16, + [ __NR_setfsgid ] = (syscall_handler_t *) sys_setfsgid16, + [ __NR_getdents ] = (syscall_handler_t *) sys_getdents, + [ __NR_flock ] = (syscall_handler_t *) sys_flock, + [ __NR_msync ] = (syscall_handler_t *) sys_msync, + [ __NR_readv ] = (syscall_handler_t *) sys_readv, + [ __NR_writev ] = (syscall_handler_t *) sys_writev, + [ __NR_getsid ] = (syscall_handler_t *) sys_getsid, + [ __NR_fdatasync ] = (syscall_handler_t *) sys_fdatasync, + [ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl, + [ __NR_mlock ] = (syscall_handler_t *) sys_mlock, + [ __NR_munlock ] = (syscall_handler_t *) sys_munlock, + [ __NR_mlockall ] = (syscall_handler_t *) sys_mlockall, + [ __NR_munlockall ] = (syscall_handler_t *) sys_munlockall, + [ __NR_sched_setparam ] = (syscall_handler_t *) sys_sched_setparam, + [ __NR_sched_getparam ] = (syscall_handler_t *) sys_sched_getparam, + [ __NR_sched_setscheduler ] = (syscall_handler_t *) sys_sched_setscheduler, + [ __NR_sched_getscheduler ] = (syscall_handler_t *) sys_sched_getscheduler, + [ __NR_sched_yield ] = (syscall_handler_t *) yield, + [ __NR_sched_get_priority_max ] = (syscall_handler_t *) sys_sched_get_priority_max, + [ __NR_sched_get_priority_min ] = (syscall_handler_t *) sys_sched_get_priority_min, + [ __NR_sched_rr_get_interval ] = (syscall_handler_t *) sys_sched_rr_get_interval, + [ __NR_nanosleep ] = (syscall_handler_t *) sys_nanosleep, + [ __NR_mremap ] = (syscall_handler_t *) sys_mremap, + [ __NR_setresuid ] = (syscall_handler_t *) sys_setresuid16, + [ __NR_getresuid ] = (syscall_handler_t *) sys_getresuid16, + [ __NR_query_module ] = (syscall_handler_t *) sys_ni_syscall, + [ __NR_poll ] = (syscall_handler_t *) sys_poll, + [ __NR_nfsservctl ] = (syscall_handler_t *) NFSSERVCTL, + [ __NR_setresgid ] = (syscall_handler_t *) sys_setresgid16, + [ __NR_getresgid ] = (syscall_handler_t *) sys_getresgid16, + [ __NR_prctl ] = (syscall_handler_t *) sys_prctl, + [ __NR_rt_sigreturn ] = (syscall_handler_t *) sys_rt_sigreturn, + [ __NR_rt_sigaction ] = (syscall_handler_t *) sys_rt_sigaction, + [ __NR_rt_sigprocmask ] = (syscall_handler_t *) sys_rt_sigprocmask, + [ __NR_rt_sigpending ] = (syscall_handler_t *) sys_rt_sigpending, + [ __NR_rt_sigtimedwait ] = (syscall_handler_t *) sys_rt_sigtimedwait, + [ __NR_rt_sigqueueinfo ] = (syscall_handler_t *) sys_rt_sigqueueinfo, + [ __NR_rt_sigsuspend ] = (syscall_handler_t *) sys_rt_sigsuspend, + [ __NR_pread64 ] = (syscall_handler_t *) sys_pread64, + [ __NR_pwrite64 ] = (syscall_handler_t *) sys_pwrite64, + [ __NR_chown ] = (syscall_handler_t *) sys_chown16, + [ __NR_getcwd ] = (syscall_handler_t *) sys_getcwd, + [ __NR_capget ] = (syscall_handler_t *) sys_capget, + [ __NR_capset ] = (syscall_handler_t *) sys_capset, + [ __NR_sigaltstack ] = (syscall_handler_t *) sys_sigaltstack, + [ __NR_sendfile ] = (syscall_handler_t *) sys_sendfile, + [ __NR_getpmsg ] = (syscall_handler_t *) sys_ni_syscall, + [ __NR_putpmsg ] = (syscall_handler_t *) sys_ni_syscall, + [ __NR_vfork ] = (syscall_handler_t *) sys_vfork, + [ __NR_getdents64 ] = (syscall_handler_t *) sys_getdents64, + [ __NR_gettid ] = (syscall_handler_t *) sys_gettid, + [ __NR_readahead ] = (syscall_handler_t *) sys_readahead, + [ __NR_setxattr ] = (syscall_handler_t *) sys_setxattr, + [ __NR_lsetxattr ] = (syscall_handler_t *) sys_lsetxattr, + [ __NR_fsetxattr ] = (syscall_handler_t *) sys_fsetxattr, + [ __NR_getxattr ] = (syscall_handler_t *) sys_getxattr, + [ __NR_lgetxattr ] = (syscall_handler_t *) sys_lgetxattr, + [ __NR_fgetxattr ] = (syscall_handler_t *) sys_fgetxattr, + [ __NR_listxattr ] = (syscall_handler_t *) sys_listxattr, + [ __NR_llistxattr ] = (syscall_handler_t *) sys_llistxattr, + [ __NR_flistxattr ] = (syscall_handler_t *) sys_flistxattr, + [ __NR_removexattr ] = (syscall_handler_t *) sys_removexattr, + [ __NR_lremovexattr ] = (syscall_handler_t *) sys_lremovexattr, + [ __NR_fremovexattr ] = (syscall_handler_t *) sys_fremovexattr, + [ __NR_tkill ] = (syscall_handler_t *) sys_tkill, + [ __NR_futex ] = (syscall_handler_t *) sys_futex, + [ __NR_sched_setaffinity ] = (syscall_handler_t *) sys_sched_setaffinity, + [ __NR_sched_getaffinity ] = (syscall_handler_t *) sys_sched_getaffinity, + [ __NR_io_setup ] = (syscall_handler_t *) sys_io_setup, + [ __NR_io_destroy ] = (syscall_handler_t *) sys_io_destroy, + [ __NR_io_getevents ] = (syscall_handler_t *) sys_io_getevents, + [ __NR_io_submit ] = (syscall_handler_t *) sys_io_submit, + [ __NR_io_cancel ] = (syscall_handler_t *) sys_io_cancel, + [ __NR_exit_group ] = (syscall_handler_t *) sys_exit_group, + [ __NR_lookup_dcookie ] = (syscall_handler_t *) sys_lookup_dcookie, + [ __NR_epoll_create ] = (syscall_handler_t *) sys_epoll_create, + [ __NR_epoll_ctl ] = (syscall_handler_t *) sys_epoll_ctl, + [ __NR_epoll_wait ] = (syscall_handler_t *) sys_epoll_wait, + [ __NR_remap_file_pages ] = (syscall_handler_t *) sys_remap_file_pages, + [ __NR_set_tid_address ] = (syscall_handler_t *) sys_set_tid_address, + [ __NR_timer_create ] = (syscall_handler_t *) sys_timer_create, + [ __NR_timer_settime ] = (syscall_handler_t *) sys_timer_settime, + [ __NR_timer_gettime ] = (syscall_handler_t *) sys_timer_gettime, + [ __NR_timer_getoverrun ] = (syscall_handler_t *) sys_timer_getoverrun, + [ __NR_timer_delete ] = (syscall_handler_t *) sys_timer_delete, + [ __NR_clock_settime ] = (syscall_handler_t *) sys_clock_settime, + [ __NR_clock_gettime ] = (syscall_handler_t *) sys_clock_gettime, + [ __NR_clock_getres ] = (syscall_handler_t *) sys_clock_getres, + [ __NR_clock_nanosleep ] = (syscall_handler_t *) sys_clock_nanosleep, + [ __NR_tgkill ] = (syscall_handler_t *) sys_tgkill, + [ __NR_utimes ] = (syscall_handler_t *) sys_utimes, + [ __NR_fadvise64 ] = (syscall_handler_t *) sys_fadvise64, + [ __NR_vserver ] = (syscall_handler_t *) sys_ni_syscall, + [ __NR_mbind ] = (syscall_handler_t *) sys_mbind, + [ __NR_get_mempolicy ] = (syscall_handler_t *) sys_get_mempolicy, + [ __NR_set_mempolicy ] = (syscall_handler_t *) sys_set_mempolicy, + [ __NR_mq_open ] = (syscall_handler_t *) sys_mq_open, + [ __NR_mq_unlink ] = (syscall_handler_t *) sys_mq_unlink, + [ __NR_mq_timedsend ] = (syscall_handler_t *) sys_mq_timedsend, + [ __NR_mq_timedreceive ] = (syscall_handler_t *) sys_mq_timedreceive, + [ __NR_mq_notify ] = (syscall_handler_t *) sys_mq_notify, + [ __NR_mq_getsetattr ] = (syscall_handler_t *) sys_mq_getsetattr, + [ __NR_kexec_load ] = (syscall_handler_t *) sys_ni_syscall, + [ __NR_waitid ] = (syscall_handler_t *) sys_waitid, + [ __NR_add_key ] = (syscall_handler_t *) sys_add_key, + [ __NR_request_key ] = (syscall_handler_t *) sys_request_key, + [ __NR_keyctl ] = (syscall_handler_t *) sys_keyctl, + + ARCH_SYSCALLS + [ LAST_SYSCALL + 1 ... NR_syscalls ] = + (syscall_handler_t *) sys_ni_syscall +}; -- cgit v0.10.2 From ddcd6b175793839e51fdd55debb670a9f512c448 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:58:55 -0700 Subject: [PATCH] uml: quick fix syscall table for x86_64 Fix the moved syscall table for the x86_64 SUBARCH: - redirect __NR_chown and such to versions aware of 32-bit UIDs, - avoid the useless hack for sys_nfsservctl, - use sys_sendfile64 in the table rather than sys_sendfile. - __NR_uselib is sys_ni_syscall on x86_64 (which does not support A.OUT). - __NR_getrlimit is sys_getrlimit, not sys_old_getrlimit Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/sys-x86_64/sys_call_table.c b/arch/um/sys-x86_64/sys_call_table.c index 3f5efbf..a31e0df 100644 --- a/arch/um/sys-x86_64/sys_call_table.c +++ b/arch/um/sys-x86_64/sys_call_table.c @@ -14,12 +14,6 @@ #include "sysdep/syscalls.h" #include "kern_util.h" -#ifdef CONFIG_NFSD -#define NFSSERVCTL sys_nfsservctl -#else -#define NFSSERVCTL sys_ni_syscall -#endif - #define LAST_GENERIC_SYSCALL __NR_keyctl #if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL @@ -52,6 +46,7 @@ extern syscall_handler_t sys_get_mempolicy; extern syscall_handler_t sys_set_mempolicy; extern syscall_handler_t sys_sys_setaltroot; +/* On X86-64 all syscalls are aware of 32-bit [ug]ids, so I had to fix this!*/ syscall_handler_t *sys_call_table[] = { [ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall, [ __NR_exit ] = (syscall_handler_t *) sys_exit, @@ -72,12 +67,12 @@ syscall_handler_t *sys_call_table[] = { [ __NR_time ] = um_time, [ __NR_mknod ] = (syscall_handler_t *) sys_mknod, [ __NR_chmod ] = (syscall_handler_t *) sys_chmod, - [ __NR_lchown ] = (syscall_handler_t *) sys_lchown16, + [ __NR_lchown ] = (syscall_handler_t *) sys_lchown, [ __NR_lseek ] = (syscall_handler_t *) sys_lseek, [ __NR_getpid ] = (syscall_handler_t *) sys_getpid, [ __NR_mount ] = (syscall_handler_t *) sys_mount, - [ __NR_setuid ] = (syscall_handler_t *) sys_setuid16, - [ __NR_getuid ] = (syscall_handler_t *) sys_getuid16, + [ __NR_setuid ] = (syscall_handler_t *) sys_setuid, + [ __NR_getuid ] = (syscall_handler_t *) sys_getuid, [ __NR_ptrace ] = (syscall_handler_t *) sys_ptrace, [ __NR_alarm ] = (syscall_handler_t *) sys_alarm, [ __NR_pause ] = (syscall_handler_t *) sys_pause, @@ -94,10 +89,10 @@ syscall_handler_t *sys_call_table[] = { [ __NR_pipe ] = (syscall_handler_t *) sys_pipe, [ __NR_times ] = (syscall_handler_t *) sys_times, [ __NR_brk ] = (syscall_handler_t *) sys_brk, - [ __NR_setgid ] = (syscall_handler_t *) sys_setgid16, - [ __NR_getgid ] = (syscall_handler_t *) sys_getgid16, - [ __NR_geteuid ] = (syscall_handler_t *) sys_geteuid16, - [ __NR_getegid ] = (syscall_handler_t *) sys_getegid16, + [ __NR_setgid ] = (syscall_handler_t *) sys_setgid, + [ __NR_getgid ] = (syscall_handler_t *) sys_getgid, + [ __NR_geteuid ] = (syscall_handler_t *) sys_geteuid, + [ __NR_getegid ] = (syscall_handler_t *) sys_getegid, [ __NR_acct ] = (syscall_handler_t *) sys_acct, [ __NR_umount2 ] = (syscall_handler_t *) sys_umount, [ __NR_ioctl ] = (syscall_handler_t *) sys_ioctl, @@ -110,26 +105,26 @@ syscall_handler_t *sys_call_table[] = { [ __NR_getppid ] = (syscall_handler_t *) sys_getppid, [ __NR_getpgrp ] = (syscall_handler_t *) sys_getpgrp, [ __NR_setsid ] = (syscall_handler_t *) sys_setsid, - [ __NR_setreuid ] = (syscall_handler_t *) sys_setreuid16, - [ __NR_setregid ] = (syscall_handler_t *) sys_setregid16, + [ __NR_setreuid ] = (syscall_handler_t *) sys_setreuid, + [ __NR_setregid ] = (syscall_handler_t *) sys_setregid, [ __NR_sethostname ] = (syscall_handler_t *) sys_sethostname, [ __NR_setrlimit ] = (syscall_handler_t *) sys_setrlimit, - [ __NR_getrlimit ] = (syscall_handler_t *) sys_old_getrlimit, + [ __NR_getrlimit ] = (syscall_handler_t *) sys_getrlimit, [ __NR_getrusage ] = (syscall_handler_t *) sys_getrusage, [ __NR_gettimeofday ] = (syscall_handler_t *) sys_gettimeofday, [ __NR_settimeofday ] = (syscall_handler_t *) sys_settimeofday, - [ __NR_getgroups ] = (syscall_handler_t *) sys_getgroups16, - [ __NR_setgroups ] = (syscall_handler_t *) sys_setgroups16, + [ __NR_getgroups ] = (syscall_handler_t *) sys_getgroups, + [ __NR_setgroups ] = (syscall_handler_t *) sys_setgroups, [ __NR_symlink ] = (syscall_handler_t *) sys_symlink, [ __NR_readlink ] = (syscall_handler_t *) sys_readlink, - [ __NR_uselib ] = (syscall_handler_t *) sys_uselib, + [ __NR_uselib ] = (syscall_handler_t *) sys_ni_syscall, [ __NR_swapon ] = (syscall_handler_t *) sys_swapon, [ __NR_reboot ] = (syscall_handler_t *) sys_reboot, [ __NR_munmap ] = (syscall_handler_t *) sys_munmap, [ __NR_truncate ] = (syscall_handler_t *) sys_truncate, [ __NR_ftruncate ] = (syscall_handler_t *) sys_ftruncate, [ __NR_fchmod ] = (syscall_handler_t *) sys_fchmod, - [ __NR_fchown ] = (syscall_handler_t *) sys_fchown16, + [ __NR_fchown ] = (syscall_handler_t *) sys_fchown, [ __NR_getpriority ] = (syscall_handler_t *) sys_getpriority, [ __NR_setpriority ] = (syscall_handler_t *) sys_setpriority, [ __NR_statfs ] = (syscall_handler_t *) sys_statfs, @@ -161,8 +156,8 @@ syscall_handler_t *sys_call_table[] = { [ __NR_sysfs ] = (syscall_handler_t *) sys_sysfs, [ __NR_personality ] = (syscall_handler_t *) sys_personality, [ __NR_afs_syscall ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_setfsuid ] = (syscall_handler_t *) sys_setfsuid16, - [ __NR_setfsgid ] = (syscall_handler_t *) sys_setfsgid16, + [ __NR_setfsuid ] = (syscall_handler_t *) sys_setfsuid, + [ __NR_setfsgid ] = (syscall_handler_t *) sys_setfsgid, [ __NR_getdents ] = (syscall_handler_t *) sys_getdents, [ __NR_flock ] = (syscall_handler_t *) sys_flock, [ __NR_msync ] = (syscall_handler_t *) sys_msync, @@ -185,13 +180,13 @@ syscall_handler_t *sys_call_table[] = { [ __NR_sched_rr_get_interval ] = (syscall_handler_t *) sys_sched_rr_get_interval, [ __NR_nanosleep ] = (syscall_handler_t *) sys_nanosleep, [ __NR_mremap ] = (syscall_handler_t *) sys_mremap, - [ __NR_setresuid ] = (syscall_handler_t *) sys_setresuid16, - [ __NR_getresuid ] = (syscall_handler_t *) sys_getresuid16, + [ __NR_setresuid ] = (syscall_handler_t *) sys_setresuid, + [ __NR_getresuid ] = (syscall_handler_t *) sys_getresuid, [ __NR_query_module ] = (syscall_handler_t *) sys_ni_syscall, [ __NR_poll ] = (syscall_handler_t *) sys_poll, - [ __NR_nfsservctl ] = (syscall_handler_t *) NFSSERVCTL, - [ __NR_setresgid ] = (syscall_handler_t *) sys_setresgid16, - [ __NR_getresgid ] = (syscall_handler_t *) sys_getresgid16, + [ __NR_nfsservctl ] = (syscall_handler_t *) sys_nfsservctl, + [ __NR_setresgid ] = (syscall_handler_t *) sys_setresgid, + [ __NR_getresgid ] = (syscall_handler_t *) sys_getresgid, [ __NR_prctl ] = (syscall_handler_t *) sys_prctl, [ __NR_rt_sigreturn ] = (syscall_handler_t *) sys_rt_sigreturn, [ __NR_rt_sigaction ] = (syscall_handler_t *) sys_rt_sigaction, @@ -202,12 +197,12 @@ syscall_handler_t *sys_call_table[] = { [ __NR_rt_sigsuspend ] = (syscall_handler_t *) sys_rt_sigsuspend, [ __NR_pread64 ] = (syscall_handler_t *) sys_pread64, [ __NR_pwrite64 ] = (syscall_handler_t *) sys_pwrite64, - [ __NR_chown ] = (syscall_handler_t *) sys_chown16, + [ __NR_chown ] = (syscall_handler_t *) sys_chown, [ __NR_getcwd ] = (syscall_handler_t *) sys_getcwd, [ __NR_capget ] = (syscall_handler_t *) sys_capget, [ __NR_capset ] = (syscall_handler_t *) sys_capset, [ __NR_sigaltstack ] = (syscall_handler_t *) sys_sigaltstack, - [ __NR_sendfile ] = (syscall_handler_t *) sys_sendfile, + [ __NR_sendfile ] = (syscall_handler_t *) sys_sendfile64, [ __NR_getpmsg ] = (syscall_handler_t *) sys_ni_syscall, [ __NR_putpmsg ] = (syscall_handler_t *) sys_ni_syscall, [ __NR_vfork ] = (syscall_handler_t *) sys_vfork, -- cgit v0.10.2 From 80f9507886076de0cadfdf2b87701e68156829c2 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:58:55 -0700 Subject: [PATCH] uml: fix syscall table by including $(SUBARCH)'s one, for x86-64 Reuse asm-x86-64/unistd.h to build our syscall table, like x86-64 already does. Like for i386, we must add some #defines for all the (right!) changes UML does to x86-64 syscall table. Note: I noted a bogus: [ __NR_sched_yield ] = (syscall_handler_t *) yield, while doing this patch (which could only be a workaround for some strange bug, but I would ignore this possibility). I'm changing this without notice. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h index 65a01e3..b56b335 100644 --- a/arch/um/include/sysdep-x86_64/syscalls.h +++ b/arch/um/include/sysdep-x86_64/syscalls.h @@ -30,51 +30,6 @@ extern syscall_handler_t wrap_sys_shmat; extern syscall_handler_t sys_modify_ldt; extern syscall_handler_t sys_arch_prctl; -#define ARCH_SYSCALLS \ - [ __NR_mmap ] = (syscall_handler_t *) old_mmap, \ - [ __NR_select ] = (syscall_handler_t *) sys_select, \ - [ __NR_mincore ] = (syscall_handler_t *) sys_mincore, \ - [ __NR_madvise ] = (syscall_handler_t *) sys_madvise, \ - [ __NR_shmget ] = (syscall_handler_t *) sys_shmget, \ - [ __NR_shmat ] = (syscall_handler_t *) wrap_sys_shmat, \ - [ __NR_shmctl ] = (syscall_handler_t *) sys_shmctl, \ - [ __NR_semop ] = (syscall_handler_t *) sys_semop, \ - [ __NR_semget ] = (syscall_handler_t *) sys_semget, \ - [ __NR_semctl ] = (syscall_handler_t *) sys_semctl, \ - [ __NR_shmdt ] = (syscall_handler_t *) sys_shmdt, \ - [ __NR_msgget ] = (syscall_handler_t *) sys_msgget, \ - [ __NR_msgsnd ] = (syscall_handler_t *) sys_msgsnd, \ - [ __NR_msgrcv ] = (syscall_handler_t *) sys_msgrcv, \ - [ __NR_msgctl ] = (syscall_handler_t *) sys_msgctl, \ - [ __NR_pivot_root ] = (syscall_handler_t *) sys_pivot_root, \ - [ __NR_tuxcall ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_security ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_epoll_ctl_old ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_epoll_wait_old ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_modify_ldt ] = (syscall_handler_t *) sys_modify_ldt, \ - [ __NR_arch_prctl ] = (syscall_handler_t *) sys_arch_prctl, \ - [ __NR_socket ] = (syscall_handler_t *) sys_socket, \ - [ __NR_connect ] = (syscall_handler_t *) sys_connect, \ - [ __NR_accept ] = (syscall_handler_t *) sys_accept, \ - [ __NR_recvfrom ] = (syscall_handler_t *) sys_recvfrom, \ - [ __NR_recvmsg ] = (syscall_handler_t *) sys_recvmsg, \ - [ __NR_sendmsg ] = (syscall_handler_t *) sys_sendmsg, \ - [ __NR_bind ] = (syscall_handler_t *) sys_bind, \ - [ __NR_listen ] = (syscall_handler_t *) sys_listen, \ - [ __NR_getsockname ] = (syscall_handler_t *) sys_getsockname, \ - [ __NR_getpeername ] = (syscall_handler_t *) sys_getpeername, \ - [ __NR_socketpair ] = (syscall_handler_t *) sys_socketpair, \ - [ __NR_sendto ] = (syscall_handler_t *) sys_sendto, \ - [ __NR_shutdown ] = (syscall_handler_t *) sys_shutdown, \ - [ __NR_setsockopt ] = (syscall_handler_t *) sys_setsockopt, \ - [ __NR_getsockopt ] = (syscall_handler_t *) sys_getsockopt, \ - [ __NR_iopl ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_set_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_get_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \ - [ __NR_semtimedop ] = (syscall_handler_t *) sys_semtimedop, \ - [ 251 ] = (syscall_handler_t *) sys_ni_syscall, - -#define LAST_ARCH_SYSCALL 251 -#define NR_syscalls 1024 +#define NR_syscalls (__NR_syscall_max + 1) #endif diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 274158e..d7ed2f7 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -6,7 +6,7 @@ lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \ ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \ - syscalls.o sysrq.o thunk.o sys_call_table.o + syscalls.o sysrq.o thunk.o syscall_table.o USER_OBJS := ptrace_user.o sigcontext.o diff --git a/arch/um/sys-x86_64/sys_call_table.c b/arch/um/sys-x86_64/sys_call_table.c deleted file mode 100644 index a31e0df..0000000 --- a/arch/um/sys-x86_64/sys_call_table.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Copyright 2003 PathScale, Inc. - * Licensed under the GPL - */ - -#include "linux/config.h" -#include "linux/unistd.h" -#include "linux/sys.h" -#include "linux/swap.h" -#include "linux/syscalls.h" -#include "linux/sysctl.h" -#include "asm/signal.h" -#include "sysdep/syscalls.h" -#include "kern_util.h" - -#define LAST_GENERIC_SYSCALL __NR_keyctl - -#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL -#define LAST_SYSCALL LAST_GENERIC_SYSCALL -#else -#define LAST_SYSCALL LAST_ARCH_SYSCALL -#endif - -extern syscall_handler_t sys_fork; -extern syscall_handler_t sys_execve; -extern syscall_handler_t um_time; -extern syscall_handler_t um_stime; -extern syscall_handler_t sys_pipe; -extern syscall_handler_t sys_olduname; -extern syscall_handler_t sys_sigaction; -extern syscall_handler_t sys_sigsuspend; -extern syscall_handler_t old_readdir; -extern syscall_handler_t sys_uname; -extern syscall_handler_t sys_ipc; -extern syscall_handler_t sys_sigreturn; -extern syscall_handler_t sys_clone; -extern syscall_handler_t sys_rt_sigreturn; -extern syscall_handler_t sys_sigaltstack; -extern syscall_handler_t sys_vfork; -extern syscall_handler_t old_select; -extern syscall_handler_t sys_modify_ldt; -extern syscall_handler_t sys_rt_sigsuspend; -extern syscall_handler_t sys_mbind; -extern syscall_handler_t sys_get_mempolicy; -extern syscall_handler_t sys_set_mempolicy; -extern syscall_handler_t sys_sys_setaltroot; - -/* On X86-64 all syscalls are aware of 32-bit [ug]ids, so I had to fix this!*/ -syscall_handler_t *sys_call_table[] = { - [ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall, - [ __NR_exit ] = (syscall_handler_t *) sys_exit, - [ __NR_fork ] = (syscall_handler_t *) sys_fork, - [ __NR_read ] = (syscall_handler_t *) sys_read, - [ __NR_write ] = (syscall_handler_t *) sys_write, - - /* These three are declared differently in asm/unistd.h */ - [ __NR_open ] = (syscall_handler_t *) sys_open, - [ __NR_close ] = (syscall_handler_t *) sys_close, - [ __NR_creat ] = (syscall_handler_t *) sys_creat, - [ __NR_link ] = (syscall_handler_t *) sys_link, - [ __NR_unlink ] = (syscall_handler_t *) sys_unlink, - [ __NR_execve ] = (syscall_handler_t *) sys_execve, - - /* declared differently in kern_util.h */ - [ __NR_chdir ] = (syscall_handler_t *) sys_chdir, - [ __NR_time ] = um_time, - [ __NR_mknod ] = (syscall_handler_t *) sys_mknod, - [ __NR_chmod ] = (syscall_handler_t *) sys_chmod, - [ __NR_lchown ] = (syscall_handler_t *) sys_lchown, - [ __NR_lseek ] = (syscall_handler_t *) sys_lseek, - [ __NR_getpid ] = (syscall_handler_t *) sys_getpid, - [ __NR_mount ] = (syscall_handler_t *) sys_mount, - [ __NR_setuid ] = (syscall_handler_t *) sys_setuid, - [ __NR_getuid ] = (syscall_handler_t *) sys_getuid, - [ __NR_ptrace ] = (syscall_handler_t *) sys_ptrace, - [ __NR_alarm ] = (syscall_handler_t *) sys_alarm, - [ __NR_pause ] = (syscall_handler_t *) sys_pause, - [ __NR_utime ] = (syscall_handler_t *) sys_utime, - [ __NR_access ] = (syscall_handler_t *) sys_access, - [ __NR_sync ] = (syscall_handler_t *) sys_sync, - [ __NR_kill ] = (syscall_handler_t *) sys_kill, - [ __NR_rename ] = (syscall_handler_t *) sys_rename, - [ __NR_mkdir ] = (syscall_handler_t *) sys_mkdir, - [ __NR_rmdir ] = (syscall_handler_t *) sys_rmdir, - - /* Declared differently in asm/unistd.h */ - [ __NR_dup ] = (syscall_handler_t *) sys_dup, - [ __NR_pipe ] = (syscall_handler_t *) sys_pipe, - [ __NR_times ] = (syscall_handler_t *) sys_times, - [ __NR_brk ] = (syscall_handler_t *) sys_brk, - [ __NR_setgid ] = (syscall_handler_t *) sys_setgid, - [ __NR_getgid ] = (syscall_handler_t *) sys_getgid, - [ __NR_geteuid ] = (syscall_handler_t *) sys_geteuid, - [ __NR_getegid ] = (syscall_handler_t *) sys_getegid, - [ __NR_acct ] = (syscall_handler_t *) sys_acct, - [ __NR_umount2 ] = (syscall_handler_t *) sys_umount, - [ __NR_ioctl ] = (syscall_handler_t *) sys_ioctl, - [ __NR_fcntl ] = (syscall_handler_t *) sys_fcntl, - [ __NR_setpgid ] = (syscall_handler_t *) sys_setpgid, - [ __NR_umask ] = (syscall_handler_t *) sys_umask, - [ __NR_chroot ] = (syscall_handler_t *) sys_chroot, - [ __NR_ustat ] = (syscall_handler_t *) sys_ustat, - [ __NR_dup2 ] = (syscall_handler_t *) sys_dup2, - [ __NR_getppid ] = (syscall_handler_t *) sys_getppid, - [ __NR_getpgrp ] = (syscall_handler_t *) sys_getpgrp, - [ __NR_setsid ] = (syscall_handler_t *) sys_setsid, - [ __NR_setreuid ] = (syscall_handler_t *) sys_setreuid, - [ __NR_setregid ] = (syscall_handler_t *) sys_setregid, - [ __NR_sethostname ] = (syscall_handler_t *) sys_sethostname, - [ __NR_setrlimit ] = (syscall_handler_t *) sys_setrlimit, - [ __NR_getrlimit ] = (syscall_handler_t *) sys_getrlimit, - [ __NR_getrusage ] = (syscall_handler_t *) sys_getrusage, - [ __NR_gettimeofday ] = (syscall_handler_t *) sys_gettimeofday, - [ __NR_settimeofday ] = (syscall_handler_t *) sys_settimeofday, - [ __NR_getgroups ] = (syscall_handler_t *) sys_getgroups, - [ __NR_setgroups ] = (syscall_handler_t *) sys_setgroups, - [ __NR_symlink ] = (syscall_handler_t *) sys_symlink, - [ __NR_readlink ] = (syscall_handler_t *) sys_readlink, - [ __NR_uselib ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_swapon ] = (syscall_handler_t *) sys_swapon, - [ __NR_reboot ] = (syscall_handler_t *) sys_reboot, - [ __NR_munmap ] = (syscall_handler_t *) sys_munmap, - [ __NR_truncate ] = (syscall_handler_t *) sys_truncate, - [ __NR_ftruncate ] = (syscall_handler_t *) sys_ftruncate, - [ __NR_fchmod ] = (syscall_handler_t *) sys_fchmod, - [ __NR_fchown ] = (syscall_handler_t *) sys_fchown, - [ __NR_getpriority ] = (syscall_handler_t *) sys_getpriority, - [ __NR_setpriority ] = (syscall_handler_t *) sys_setpriority, - [ __NR_statfs ] = (syscall_handler_t *) sys_statfs, - [ __NR_fstatfs ] = (syscall_handler_t *) sys_fstatfs, - [ __NR_ioperm ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_syslog ] = (syscall_handler_t *) sys_syslog, - [ __NR_setitimer ] = (syscall_handler_t *) sys_setitimer, - [ __NR_getitimer ] = (syscall_handler_t *) sys_getitimer, - [ __NR_stat ] = (syscall_handler_t *) sys_newstat, - [ __NR_lstat ] = (syscall_handler_t *) sys_newlstat, - [ __NR_fstat ] = (syscall_handler_t *) sys_newfstat, - [ __NR_vhangup ] = (syscall_handler_t *) sys_vhangup, - [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4, - [ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff, - [ __NR_sysinfo ] = (syscall_handler_t *) sys_sysinfo, - [ __NR_fsync ] = (syscall_handler_t *) sys_fsync, - [ __NR_clone ] = (syscall_handler_t *) sys_clone, - [ __NR_setdomainname ] = (syscall_handler_t *) sys_setdomainname, - [ __NR_uname ] = (syscall_handler_t *) sys_newuname, - [ __NR_adjtimex ] = (syscall_handler_t *) sys_adjtimex, - [ __NR_mprotect ] = (syscall_handler_t *) sys_mprotect, - [ __NR_create_module ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_init_module ] = (syscall_handler_t *) sys_init_module, - [ __NR_delete_module ] = (syscall_handler_t *) sys_delete_module, - [ __NR_get_kernel_syms ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_quotactl ] = (syscall_handler_t *) sys_quotactl, - [ __NR_getpgid ] = (syscall_handler_t *) sys_getpgid, - [ __NR_fchdir ] = (syscall_handler_t *) sys_fchdir, - [ __NR_sysfs ] = (syscall_handler_t *) sys_sysfs, - [ __NR_personality ] = (syscall_handler_t *) sys_personality, - [ __NR_afs_syscall ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_setfsuid ] = (syscall_handler_t *) sys_setfsuid, - [ __NR_setfsgid ] = (syscall_handler_t *) sys_setfsgid, - [ __NR_getdents ] = (syscall_handler_t *) sys_getdents, - [ __NR_flock ] = (syscall_handler_t *) sys_flock, - [ __NR_msync ] = (syscall_handler_t *) sys_msync, - [ __NR_readv ] = (syscall_handler_t *) sys_readv, - [ __NR_writev ] = (syscall_handler_t *) sys_writev, - [ __NR_getsid ] = (syscall_handler_t *) sys_getsid, - [ __NR_fdatasync ] = (syscall_handler_t *) sys_fdatasync, - [ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl, - [ __NR_mlock ] = (syscall_handler_t *) sys_mlock, - [ __NR_munlock ] = (syscall_handler_t *) sys_munlock, - [ __NR_mlockall ] = (syscall_handler_t *) sys_mlockall, - [ __NR_munlockall ] = (syscall_handler_t *) sys_munlockall, - [ __NR_sched_setparam ] = (syscall_handler_t *) sys_sched_setparam, - [ __NR_sched_getparam ] = (syscall_handler_t *) sys_sched_getparam, - [ __NR_sched_setscheduler ] = (syscall_handler_t *) sys_sched_setscheduler, - [ __NR_sched_getscheduler ] = (syscall_handler_t *) sys_sched_getscheduler, - [ __NR_sched_yield ] = (syscall_handler_t *) yield, - [ __NR_sched_get_priority_max ] = (syscall_handler_t *) sys_sched_get_priority_max, - [ __NR_sched_get_priority_min ] = (syscall_handler_t *) sys_sched_get_priority_min, - [ __NR_sched_rr_get_interval ] = (syscall_handler_t *) sys_sched_rr_get_interval, - [ __NR_nanosleep ] = (syscall_handler_t *) sys_nanosleep, - [ __NR_mremap ] = (syscall_handler_t *) sys_mremap, - [ __NR_setresuid ] = (syscall_handler_t *) sys_setresuid, - [ __NR_getresuid ] = (syscall_handler_t *) sys_getresuid, - [ __NR_query_module ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_poll ] = (syscall_handler_t *) sys_poll, - [ __NR_nfsservctl ] = (syscall_handler_t *) sys_nfsservctl, - [ __NR_setresgid ] = (syscall_handler_t *) sys_setresgid, - [ __NR_getresgid ] = (syscall_handler_t *) sys_getresgid, - [ __NR_prctl ] = (syscall_handler_t *) sys_prctl, - [ __NR_rt_sigreturn ] = (syscall_handler_t *) sys_rt_sigreturn, - [ __NR_rt_sigaction ] = (syscall_handler_t *) sys_rt_sigaction, - [ __NR_rt_sigprocmask ] = (syscall_handler_t *) sys_rt_sigprocmask, - [ __NR_rt_sigpending ] = (syscall_handler_t *) sys_rt_sigpending, - [ __NR_rt_sigtimedwait ] = (syscall_handler_t *) sys_rt_sigtimedwait, - [ __NR_rt_sigqueueinfo ] = (syscall_handler_t *) sys_rt_sigqueueinfo, - [ __NR_rt_sigsuspend ] = (syscall_handler_t *) sys_rt_sigsuspend, - [ __NR_pread64 ] = (syscall_handler_t *) sys_pread64, - [ __NR_pwrite64 ] = (syscall_handler_t *) sys_pwrite64, - [ __NR_chown ] = (syscall_handler_t *) sys_chown, - [ __NR_getcwd ] = (syscall_handler_t *) sys_getcwd, - [ __NR_capget ] = (syscall_handler_t *) sys_capget, - [ __NR_capset ] = (syscall_handler_t *) sys_capset, - [ __NR_sigaltstack ] = (syscall_handler_t *) sys_sigaltstack, - [ __NR_sendfile ] = (syscall_handler_t *) sys_sendfile64, - [ __NR_getpmsg ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_putpmsg ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_vfork ] = (syscall_handler_t *) sys_vfork, - [ __NR_getdents64 ] = (syscall_handler_t *) sys_getdents64, - [ __NR_gettid ] = (syscall_handler_t *) sys_gettid, - [ __NR_readahead ] = (syscall_handler_t *) sys_readahead, - [ __NR_setxattr ] = (syscall_handler_t *) sys_setxattr, - [ __NR_lsetxattr ] = (syscall_handler_t *) sys_lsetxattr, - [ __NR_fsetxattr ] = (syscall_handler_t *) sys_fsetxattr, - [ __NR_getxattr ] = (syscall_handler_t *) sys_getxattr, - [ __NR_lgetxattr ] = (syscall_handler_t *) sys_lgetxattr, - [ __NR_fgetxattr ] = (syscall_handler_t *) sys_fgetxattr, - [ __NR_listxattr ] = (syscall_handler_t *) sys_listxattr, - [ __NR_llistxattr ] = (syscall_handler_t *) sys_llistxattr, - [ __NR_flistxattr ] = (syscall_handler_t *) sys_flistxattr, - [ __NR_removexattr ] = (syscall_handler_t *) sys_removexattr, - [ __NR_lremovexattr ] = (syscall_handler_t *) sys_lremovexattr, - [ __NR_fremovexattr ] = (syscall_handler_t *) sys_fremovexattr, - [ __NR_tkill ] = (syscall_handler_t *) sys_tkill, - [ __NR_futex ] = (syscall_handler_t *) sys_futex, - [ __NR_sched_setaffinity ] = (syscall_handler_t *) sys_sched_setaffinity, - [ __NR_sched_getaffinity ] = (syscall_handler_t *) sys_sched_getaffinity, - [ __NR_io_setup ] = (syscall_handler_t *) sys_io_setup, - [ __NR_io_destroy ] = (syscall_handler_t *) sys_io_destroy, - [ __NR_io_getevents ] = (syscall_handler_t *) sys_io_getevents, - [ __NR_io_submit ] = (syscall_handler_t *) sys_io_submit, - [ __NR_io_cancel ] = (syscall_handler_t *) sys_io_cancel, - [ __NR_exit_group ] = (syscall_handler_t *) sys_exit_group, - [ __NR_lookup_dcookie ] = (syscall_handler_t *) sys_lookup_dcookie, - [ __NR_epoll_create ] = (syscall_handler_t *) sys_epoll_create, - [ __NR_epoll_ctl ] = (syscall_handler_t *) sys_epoll_ctl, - [ __NR_epoll_wait ] = (syscall_handler_t *) sys_epoll_wait, - [ __NR_remap_file_pages ] = (syscall_handler_t *) sys_remap_file_pages, - [ __NR_set_tid_address ] = (syscall_handler_t *) sys_set_tid_address, - [ __NR_timer_create ] = (syscall_handler_t *) sys_timer_create, - [ __NR_timer_settime ] = (syscall_handler_t *) sys_timer_settime, - [ __NR_timer_gettime ] = (syscall_handler_t *) sys_timer_gettime, - [ __NR_timer_getoverrun ] = (syscall_handler_t *) sys_timer_getoverrun, - [ __NR_timer_delete ] = (syscall_handler_t *) sys_timer_delete, - [ __NR_clock_settime ] = (syscall_handler_t *) sys_clock_settime, - [ __NR_clock_gettime ] = (syscall_handler_t *) sys_clock_gettime, - [ __NR_clock_getres ] = (syscall_handler_t *) sys_clock_getres, - [ __NR_clock_nanosleep ] = (syscall_handler_t *) sys_clock_nanosleep, - [ __NR_tgkill ] = (syscall_handler_t *) sys_tgkill, - [ __NR_utimes ] = (syscall_handler_t *) sys_utimes, - [ __NR_fadvise64 ] = (syscall_handler_t *) sys_fadvise64, - [ __NR_vserver ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_mbind ] = (syscall_handler_t *) sys_mbind, - [ __NR_get_mempolicy ] = (syscall_handler_t *) sys_get_mempolicy, - [ __NR_set_mempolicy ] = (syscall_handler_t *) sys_set_mempolicy, - [ __NR_mq_open ] = (syscall_handler_t *) sys_mq_open, - [ __NR_mq_unlink ] = (syscall_handler_t *) sys_mq_unlink, - [ __NR_mq_timedsend ] = (syscall_handler_t *) sys_mq_timedsend, - [ __NR_mq_timedreceive ] = (syscall_handler_t *) sys_mq_timedreceive, - [ __NR_mq_notify ] = (syscall_handler_t *) sys_mq_notify, - [ __NR_mq_getsetattr ] = (syscall_handler_t *) sys_mq_getsetattr, - [ __NR_kexec_load ] = (syscall_handler_t *) sys_ni_syscall, - [ __NR_waitid ] = (syscall_handler_t *) sys_waitid, - [ __NR_add_key ] = (syscall_handler_t *) sys_add_key, - [ __NR_request_key ] = (syscall_handler_t *) sys_request_key, - [ __NR_keyctl ] = (syscall_handler_t *) sys_keyctl, - - ARCH_SYSCALLS - [ LAST_SYSCALL + 1 ... NR_syscalls ] = - (syscall_handler_t *) sys_ni_syscall -}; diff --git a/arch/um/sys-x86_64/syscall_table.c b/arch/um/sys-x86_64/syscall_table.c new file mode 100644 index 0000000..34b2e84 --- /dev/null +++ b/arch/um/sys-x86_64/syscall_table.c @@ -0,0 +1,59 @@ +/* System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c + * with some changes for UML. */ + +#include +#include +#include +#include + +#define __NO_STUBS + +/* Below you can see, in terms of #define's, the differences between the x86-64 + * and the UML syscall table. */ + +/* Not going to be implemented by UML, since we have no hardware. */ +#define stub_iopl sys_ni_syscall +#define sys_ioperm sys_ni_syscall + +/* The UML TLS problem. Note that x86_64 does not implement this, so the below + * is needed only for the ia32 compatibility. */ +/*#define sys_set_thread_area sys_ni_syscall +#define sys_get_thread_area sys_ni_syscall*/ + +/* For __NR_time. The x86-64 name hopefully will change from sys_time64 to + * sys_time (since the current situation is bogus). I've sent a patch to cleanup + * this. Remove below the obsoleted line. */ +#define sys_time64 um_time +#define sys_time um_time + +/* On UML we call it this way ("old" means it's not mmap2) */ +#define sys_mmap old_mmap +/* On x86-64 sys_uname is actually sys_newuname plus a compatibility trick. + * See arch/x86_64/kernel/sys_x86_64.c */ +#define sys_uname sys_uname64 + +#define stub_clone sys_clone +#define stub_fork sys_fork +#define stub_vfork sys_vfork +#define stub_execve sys_execve +#define stub_rt_sigsuspend sys_rt_sigsuspend +#define stub_sigaltstack sys_sigaltstack +#define stub_rt_sigreturn sys_rt_sigreturn + +#define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ; +#undef _ASM_X86_64_UNISTD_H_ +#include + +#undef __SYSCALL +#define __SYSCALL(nr, sym) [ nr ] = sym, +#undef _ASM_X86_64_UNISTD_H_ + +typedef void (*sys_call_ptr_t)(void); + +extern void sys_ni_syscall(void); + +sys_call_ptr_t sys_call_table[__NR_syscall_max+1] __cacheline_aligned = { + /* Smells like a like a compiler bug -- it doesn't work when the & below is removed. */ + [0 ... __NR_syscall_max] = &sys_ni_syscall, +#include +}; diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index 68205a0..15768c9 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c @@ -14,6 +14,7 @@ #include "asm/prctl.h" /* XXX This should get the constants from libc */ #include "choose-mode.h" +/* XXX: copied from x86-64: arch/x86_64/kernel/sys_x86_64.c */ asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg) { unsigned long raddr; @@ -21,6 +22,17 @@ asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg) return do_shmat(shmid, shmaddr, shmflg, &raddr) ?: (long) raddr; } +asmlinkage long sys_uname64(struct new_utsname __user * name) +{ + int err; + down_read(&uts_sem); + err = copy_to_user(name, &system_utsname, sizeof (*name)); + up_read(&uts_sem); + if (personality(current->personality) == PER_LINUX32) + err |= copy_to_user(&name->machine, "i686", 5); + return err ? -EFAULT : 0; +} + #ifdef CONFIG_MODE_TT extern int modify_ldt(int func, void *ptr, unsigned long bytecount); -- cgit v0.10.2 From b97b77cca627b2e3e6d0015e2e14b1d1c12de0c8 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:58:56 -0700 Subject: [PATCH] uml: redo console locking Fix some console locking problems (including scheduling in atomic) and various reorderings and cleanup in that code. Not yet ready for 2.6.12 probably. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 1f77deb..0150038 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -22,7 +22,7 @@ #ifdef CONFIG_NOCONFIG_CHAN static void *not_configged_init(char *str, int device, struct chan_opts *opts) { - printk(KERN_ERR "Using a channel type which is configured out of " + printf(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(NULL); } @@ -30,27 +30,27 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts) static int not_configged_open(int input, int output, int primary, void *data, char **dev_out) { - printk(KERN_ERR "Using a channel type which is configured out of " + printf(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-ENODEV); } static void not_configged_close(int fd, void *data) { - printk(KERN_ERR "Using a channel type which is configured out of " + printf(KERN_ERR "Using a channel type which is configured out of " "UML\n"); } static int not_configged_read(int fd, char *c_out, void *data) { - printk(KERN_ERR "Using a channel type which is configured out of " + printf(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-EIO); } static int not_configged_write(int fd, const char *buf, int len, void *data) { - printk(KERN_ERR "Using a channel type which is configured out of " + printf(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-EIO); } @@ -58,7 +58,7 @@ static int not_configged_write(int fd, const char *buf, int len, void *data) static int not_configged_console_write(int fd, const char *buf, int len, void *data) { - printk(KERN_ERR "Using a channel type which is configured out of " + printf(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-EIO); } @@ -66,14 +66,14 @@ static int not_configged_console_write(int fd, const char *buf, int len, static int not_configged_window_size(int fd, void *data, unsigned short *rows, unsigned short *cols) { - printk(KERN_ERR "Using a channel type which is configured out of " + printf(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-ENODEV); } static void not_configged_free(void *data) { - printk(KERN_ERR "Using a channel type which is configured out of " + printf(KERN_ERR "Using a channel type which is configured out of " "UML\n"); } diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 6924f27..d0f9712 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -39,19 +39,69 @@ static void line_timer_cb(void *arg) line_interrupt(line->driver->read_irq, arg, NULL); } -static int write_room(struct line *dev) +/* Returns the free space inside the ring buffer of this line. + * + * Should be called while holding line->lock (this does not modify datas). + */ +static int write_room(struct line *line) { int n; - if (dev->buffer == NULL) - return (LINE_BUFSIZE - 1); + if (line->buffer == NULL) + return LINE_BUFSIZE - 1; + + /* This is for the case where the buffer is wrapped! */ + n = line->head - line->tail; - n = dev->head - dev->tail; if (n <= 0) - n = LINE_BUFSIZE + n; - return (n - 1); + n = LINE_BUFSIZE + n; /* The other case */ + return n - 1; +} + +int line_write_room(struct tty_struct *tty) +{ + struct line *line = tty->driver_data; + unsigned long flags; + int room; + + if (tty->stopped) + return 0; + + spin_lock_irqsave(&line->lock, flags); + room = write_room(line); + spin_unlock_irqrestore(&line->lock, flags); + + /*XXX: Warning to remove */ + if (0 == room) + printk(KERN_DEBUG "%s: %s: no room left in buffer\n", + __FUNCTION__,tty->name); + return room; } +int line_chars_in_buffer(struct tty_struct *tty) +{ + struct line *line = tty->driver_data; + unsigned long flags; + int ret; + + spin_lock_irqsave(&line->lock, flags); + + /*write_room subtracts 1 for the needed NULL, so we readd it.*/ + ret = LINE_BUFSIZE - (write_room(line) + 1); + spin_unlock_irqrestore(&line->lock, flags); + + return ret; +} + +/* + * This copies the content of buf into the circular buffer associated with + * this line. + * The return value is the number of characters actually copied, i.e. the ones + * for which there was space: this function is not supposed to ever flush out + * the circular buffer. + * + * Must be called while holding line->lock! + */ static int buffer_data(struct line *line, const char *buf, int len) { int end, room; @@ -70,48 +120,95 @@ static int buffer_data(struct line *line, const char *buf, int len) len = (len > room) ? room : len; end = line->buffer + LINE_BUFSIZE - line->tail; - if(len < end){ + + if (len < end){ memcpy(line->tail, buf, len); line->tail += len; - } - else { + } else { + /* The circular buffer is wrapping */ memcpy(line->tail, buf, end); buf += end; memcpy(line->buffer, buf, len - end); line->tail = line->buffer + len - end; } - return(len); + return len; } +/* + * Flushes the ring buffer to the output channels. That is, write_chan is + * called, passing it line->head as buffer, and an appropriate count. + * + * On exit, returns 1 when the buffer is empty, + * 0 when the buffer is not empty on exit, + * and -errno when an error occurred. + * + * Must be called while holding line->lock!*/ static int flush_buffer(struct line *line) { int n, count; if ((line->buffer == NULL) || (line->head == line->tail)) - return(1); + return 1; if (line->tail < line->head) { + /* line->buffer + LINE_BUFSIZE is the end of the buffer! */ count = line->buffer + LINE_BUFSIZE - line->head; + n = write_chan(&line->chan_list, line->head, count, line->driver->write_irq); if (n < 0) - return(n); - if (n == count) + return n; + if (n == count) { + /* We have flushed from ->head to buffer end, now we + * must flush only from the beginning to ->tail.*/ line->head = line->buffer; - else { + } else { line->head += n; - return(0); + return 0; } } count = line->tail - line->head; n = write_chan(&line->chan_list, line->head, count, line->driver->write_irq); - if(n < 0) return(n); + + if(n < 0) + return n; line->head += n; - return(line->head == line->tail); + return line->head == line->tail; +} + +void line_flush_buffer(struct tty_struct *tty) +{ + struct line *line = tty->driver_data; + unsigned long flags; + int err; + + /*XXX: copied from line_write, verify if it is correct!*/ + if(tty->stopped) + return; + //return 0; + + spin_lock_irqsave(&line->lock, flags); + err = flush_buffer(line); + /*if (err == 1) + err = 0;*/ + spin_unlock_irqrestore(&line->lock, flags); + //return err; +} + +/* We map both ->flush_chars and ->put_char (which go in pair) onto ->flush_buffer + * and ->write. Hope it's not that bad.*/ +void line_flush_chars(struct tty_struct *tty) +{ + line_flush_buffer(tty); +} + +void line_put_char(struct tty_struct *tty, unsigned char ch) +{ + line_write(tty, &ch, sizeof(ch)); } int line_write(struct tty_struct *tty, const unsigned char *buf, int len) @@ -120,38 +217,31 @@ int line_write(struct tty_struct *tty, const unsigned char *buf, int len) unsigned long flags; int n, err, ret = 0; - if(tty->stopped) return 0; + if(tty->stopped) + return 0; - down(&line->sem); - if(line->head != line->tail){ - local_irq_save(flags); + spin_lock_irqsave(&line->lock, flags); + if (line->head != line->tail) { ret = buffer_data(line, buf, len); err = flush_buffer(line); - local_irq_restore(flags); - if(err <= 0 && (err != -EAGAIN || !ret)) + if (err <= 0 && (err != -EAGAIN || !ret)) ret = err; - } - else { + } else { n = write_chan(&line->chan_list, buf, len, line->driver->write_irq); - if(n < 0){ + if (n < 0) { ret = n; goto out_up; } len -= n; ret += n; - if(len > 0) + if (len > 0) ret += buffer_data(line, buf + n, len); } - out_up: - up(&line->sem); - return(ret); -} - -void line_put_char(struct tty_struct *tty, unsigned char ch) -{ - line_write(tty, &ch, sizeof(ch)); +out_up: + spin_unlock_irqrestore(&line->lock, flags); + return ret; } void line_set_termios(struct tty_struct *tty, struct termios * old) @@ -159,11 +249,6 @@ void line_set_termios(struct tty_struct *tty, struct termios * old) /* nothing */ } -int line_chars_in_buffer(struct tty_struct *tty) -{ - return 0; -} - static struct { int cmd; char *level; @@ -250,7 +335,7 @@ int line_ioctl(struct tty_struct *tty, struct file * file, ret = -ENOIOCTLCMD; break; } - return(ret); + return ret; } static irqreturn_t line_write_interrupt(int irq, void *data, @@ -260,18 +345,23 @@ static irqreturn_t line_write_interrupt(int irq, void *data, struct line *line = tty->driver_data; int err; + /* Interrupts are enabled here because we registered the interrupt with + * SA_INTERRUPT (see line_setup_irq).*/ + + spin_lock_irq(&line->lock); err = flush_buffer(line); - if(err == 0) - return(IRQ_NONE); - else if(err < 0){ + if (err == 0) { + return IRQ_NONE; + } else if(err < 0) { line->head = line->buffer; line->tail = line->buffer; } + spin_unlock_irq(&line->lock); if(tty == NULL) - return(IRQ_NONE); + return IRQ_NONE; - if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && + if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && (tty->ldisc.write_wakeup != NULL)) (tty->ldisc.write_wakeup)(tty); @@ -281,9 +371,9 @@ static irqreturn_t line_write_interrupt(int irq, void *data, * writes. */ - if(waitqueue_active(&tty->write_wait)) + if (waitqueue_active(&tty->write_wait)) wake_up_interruptible(&tty->write_wait); - return(IRQ_HANDLED); + return IRQ_HANDLED; } int line_setup_irq(int fd, int input, int output, struct tty_struct *tty) @@ -292,15 +382,18 @@ int line_setup_irq(int fd, int input, int output, struct tty_struct *tty) struct line_driver *driver = line->driver; int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM; - if(input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, + if (input) + err = um_request_irq(driver->read_irq, fd, IRQ_READ, line_interrupt, flags, driver->read_irq_name, tty); - if(err) return(err); - if(output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, + if (err) + return err; + if (output) + err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, line_write_interrupt, flags, driver->write_irq_name, tty); line->have_irq = 1; - return(err); + return err; } void line_disable(struct tty_struct *tty, int current_irq) @@ -336,7 +429,9 @@ int line_open(struct line *lines, struct tty_struct *tty, line = &lines[tty->index]; tty->driver_data = line; - down(&line->sem); + /* The IRQ which takes this lock is not yet enabled and won't be run + * before the end, so we don't need to use spin_lock_irq.*/ + spin_lock(&line->lock); if (tty->count == 1) { if (!line->valid) { err = -ENODEV; @@ -349,6 +444,7 @@ int line_open(struct line *lines, struct tty_struct *tty, err = open_chan(&line->chan_list); if(err) goto out; } + /* Here the interrupt is registered.*/ enable_chan(&line->chan_list, tty); INIT_WORK(&line->task, line_timer_cb, tty); } @@ -362,21 +458,27 @@ int line_open(struct line *lines, struct tty_struct *tty, line->count++; out: - up(&line->sem); - return(err); + spin_unlock(&line->lock); + return err; } void line_close(struct tty_struct *tty, struct file * filp) { struct line *line = tty->driver_data; - down(&line->sem); + /* XXX: I assume this should be called in process context, not with interrupt + * disabled!*/ + spin_lock_irq(&line->lock); + + /* We ignore the error anyway! */ + flush_buffer(line); + line->count--; if (tty->count == 1) { line_disable(tty, -1); tty->driver_data = NULL; } - up(&line->sem); + spin_unlock_irq(&line->lock); } void close_lines(struct line *lines, int nlines) @@ -387,31 +489,41 @@ void close_lines(struct line *lines, int nlines) close_chan(&lines[i].chan_list); } -int line_setup(struct line *lines, int num, char *init, int all_allowed) +/* Common setup code for both startup command line and mconsole initialization. + * @lines contains the the array (of size @num) to modify; + * @init is the setup string; + * @all_allowed is a boolean saying if we can setup the whole @lines + * at once. For instance, it will be usually true for startup init. (where we + * can use con=xterm) and false for mconsole.*/ + +int line_setup(struct line *lines, unsigned int num, char *init, int all_allowed) { int i, n; char *end; - if(*init == '=') n = -1; - else { + if(*init == '=') { + /* We said con=/ssl= instead of con#=, so we are configuring all + * consoles at once.*/ + n = -1; + } else { n = simple_strtoul(init, &end, 0); if(*end != '='){ printk(KERN_ERR "line_setup failed to parse \"%s\"\n", init); - return(0); + return 0; } init = end; } init++; - if((n >= 0) && (n >= num)){ + + if (n >= (signed int) num) { printk("line_setup - %d out of range ((0 ... %d) allowed)\n", n, num - 1); - return(0); - } - else if (n >= 0){ + return 0; + } else if (n >= 0){ if (lines[n].count > 0) { printk("line_setup - device %d is open\n", n); - return(0); + return 0; } if (lines[n].init_pri <= INIT_ONE){ lines[n].init_pri = INIT_ONE; @@ -422,13 +534,11 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) lines[n].valid = 1; } } - } - else if(!all_allowed){ + } else if(!all_allowed){ printk("line_setup - can't configure all devices from " "mconsole\n"); - return(0); - } - else { + return 0; + } else { for(i = 0; i < num; i++){ if(lines[i].init_pri <= INIT_ALL){ lines[i].init_pri = INIT_ALL; @@ -440,21 +550,21 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) } } } - return(1); + return 1; } -int line_config(struct line *lines, int num, char *str) +int line_config(struct line *lines, unsigned int num, char *str) { char *new = uml_strdup(str); if(new == NULL){ printk("line_config - uml_strdup failed\n"); - return(-ENOMEM); + return -ENOMEM; } - return(!line_setup(lines, num, new, 0)); + return !line_setup(lines, num, new, 0); } -int line_get_config(char *name, struct line *lines, int num, char *str, +int line_get_config(char *name, struct line *lines, unsigned int num, char *str, int size, char **error_out) { struct line *line; @@ -464,47 +574,33 @@ int line_get_config(char *name, struct line *lines, int num, char *str, dev = simple_strtoul(name, &end, 0); if((*end != '\0') || (end == name)){ *error_out = "line_get_config failed to parse device number"; - return(0); + return 0; } if((dev < 0) || (dev >= num)){ - *error_out = "device number of of range"; - return(0); + *error_out = "device number out of range"; + return 0; } line = &lines[dev]; - down(&line->sem); + spin_lock(&line->lock); if(!line->valid) CONFIG_CHUNK(str, size, n, "none", 1); else if(line->count == 0) CONFIG_CHUNK(str, size, n, line->init_str, 1); else n = chan_config_string(&line->chan_list, str, size, error_out); - up(&line->sem); + spin_unlock(&line->lock); - return(n); + return n; } -int line_remove(struct line *lines, int num, char *str) +int line_remove(struct line *lines, unsigned int num, char *str) { char config[sizeof("conxxxx=none\0")]; sprintf(config, "%s=none", str); - return(!line_setup(lines, num, config, 0)); -} - -int line_write_room(struct tty_struct *tty) -{ - struct line *dev = tty->driver_data; - int room; - - if (tty->stopped) - return 0; - room = write_room(dev); - if (0 == room) - printk(KERN_DEBUG "%s: %s: no room left in buffer\n", - __FUNCTION__,tty->name); - return room; + return !line_setup(lines, num, config, 0); } struct tty_driver *line_register_devfs(struct lines *set, @@ -553,7 +649,7 @@ void lines_init(struct line *lines, int nlines) for(i = 0; i < nlines; i++){ line = &lines[i]; INIT_LIST_HEAD(&line->chan_list); - sema_init(&line->sem, 1); + spin_lock_init(&line->lock); if(line->init_str != NULL){ line->init_str = uml_strdup(line->init_str); if(line->init_str == NULL) @@ -587,7 +683,7 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) "errno = %d\n", -err); printk("fd %d is losing SIGWINCH support\n", winch->tty_fd); - return(IRQ_HANDLED); + return IRQ_HANDLED; } goto out; } @@ -603,7 +699,7 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) out: if(winch->fd != -1) reactivate_fd(winch->fd, WINCH_IRQ); - return(IRQ_HANDLED); + return IRQ_HANDLED; } DECLARE_MUTEX(winch_handler_sem); @@ -625,7 +721,7 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) .pid = pid, .tty = tty }); list_add(&winch->list, &winch_handlers); - if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, + if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "winch", winch) < 0) printk("register_winch_irq - failed to register IRQ\n"); @@ -656,26 +752,16 @@ char *add_xterm_umid(char *base) int len; umid = get_umid(1); - if(umid == NULL) return(base); + if(umid == NULL) + return base; len = strlen(base) + strlen(" ()") + strlen(umid) + 1; title = kmalloc(len, GFP_KERNEL); if(title == NULL){ printk("Failed to allocate buffer for xterm title\n"); - return(base); + return base; } snprintf(title, len, "%s (%s)", base, umid); - return(title); + return title; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index c5839c3..a2bac42 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -107,11 +107,6 @@ int ssl_open(struct tty_struct *tty, struct file *filp) } #if 0 -static int ssl_chars_in_buffer(struct tty_struct *tty) -{ - return(0); -} - static void ssl_flush_buffer(struct tty_struct *tty) { return; @@ -149,11 +144,11 @@ static struct tty_operations ssl_ops = { .put_char = line_put_char, .write_room = line_write_room, .chars_in_buffer = line_chars_in_buffer, + .flush_buffer = line_flush_buffer, + .flush_chars = line_flush_chars, .set_termios = line_set_termios, .ioctl = line_ioctl, #if 0 - .flush_chars = ssl_flush_chars, - .flush_buffer = ssl_flush_buffer, .throttle = ssl_throttle, .unthrottle = ssl_unthrottle, .stop = ssl_stop, @@ -171,10 +166,11 @@ static void ssl_console_write(struct console *c, const char *string, unsigned len) { struct line *line = &serial_lines[c->index]; + unsigned long flags; - down(&line->sem); + spin_lock_irqsave(&line->lock, flags); console_write_chan(&line->chan_list, string, len); - up(&line->sem); + spin_unlock_irqrestore(&line->lock, flags); } static struct tty_driver *ssl_console_device(struct console *c, int *index) @@ -238,14 +234,3 @@ static int ssl_chan_setup(char *str) __setup("ssl", ssl_chan_setup); __channel_help(ssl_chan_setup, "ssl"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index e604d7c..361d0be 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -116,8 +116,11 @@ static struct tty_operations console_ops = { .open = con_open, .close = line_close, .write = line_write, + .put_char = line_put_char, .write_room = line_write_room, .chars_in_buffer = line_chars_in_buffer, + .flush_buffer = line_flush_buffer, + .flush_chars = line_flush_chars, .set_termios = line_set_termios, .ioctl = line_ioctl, }; @@ -126,10 +129,11 @@ static void uml_console_write(struct console *console, const char *string, unsigned len) { struct line *line = &vts[console->index]; + unsigned long flags; - down(&line->sem); + spin_lock_irqsave(&line->lock, flags); console_write_chan(&line->chan_list, string, len); - up(&line->sem); + spin_unlock_irqrestore(&line->lock, flags); } static struct tty_driver *uml_console_device(struct console *c, int *index) @@ -192,14 +196,3 @@ static int console_chan_setup(char *str) } __setup("con", console_chan_setup); __channel_help(console_chan_setup, "con"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 6d81ecc..4c5e92c 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -10,7 +10,7 @@ #include "linux/workqueue.h" #include "linux/tty.h" #include "linux/interrupt.h" -#include "asm/semaphore.h" +#include "linux/spinlock.h" #include "chan_user.h" #include "mconsole_kern.h" @@ -37,10 +37,18 @@ struct line { struct list_head chan_list; int valid; int count; - struct semaphore sem; + /*This lock is actually, mostly, local to*/ + spinlock_t lock; + + /* Yes, this is a real circular buffer. + * XXX: And this should become a struct kfifo! + * + * buffer points to a buffer allocated on demand, of length + * LINE_BUFSIZE, head to the start of the ring, tail to the end.*/ char *buffer; char *head; char *tail; + int sigio; struct work_struct task; struct line_driver *driver; @@ -52,7 +60,6 @@ struct line { init_pri : INIT_STATIC, \ chan_list : { }, \ valid : 1, \ - sem : { }, \ buffer : NULL, \ head : NULL, \ tail : NULL, \ @@ -69,15 +76,18 @@ struct lines { extern void line_close(struct tty_struct *tty, struct file * filp); extern int line_open(struct line *lines, struct tty_struct *tty, struct chan_opts *opts); -extern int line_setup(struct line *lines, int num, char *init, +extern int line_setup(struct line *lines, unsigned int sizeof_lines, char *init, int all_allowed); extern int line_write(struct tty_struct *tty, const unsigned char *buf, int len); extern void line_put_char(struct tty_struct *tty, unsigned char ch); extern void line_set_termios(struct tty_struct *tty, struct termios * old); extern int line_chars_in_buffer(struct tty_struct *tty); +extern void line_flush_buffer(struct tty_struct *tty); +extern void line_flush_chars(struct tty_struct *tty); extern int line_write_room(struct tty_struct *tty); extern int line_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); + extern char *add_xterm_umid(char *base); extern int line_setup_irq(int fd, int input, int output, struct tty_struct *tty); extern void line_close_chan(struct line *line); @@ -89,20 +99,10 @@ extern struct tty_driver * line_register_devfs(struct lines *set, int nlines); extern void lines_init(struct line *lines, int nlines); extern void close_lines(struct line *lines, int nlines); -extern int line_config(struct line *lines, int num, char *str); -extern int line_remove(struct line *lines, int num, char *str); -extern int line_get_config(char *dev, struct line *lines, int num, char *str, + +extern int line_config(struct line *lines, unsigned int sizeof_lines, char *str); +extern int line_remove(struct line *lines, unsigned int sizeof_lines, char *str); +extern int line_get_config(char *dev, struct line *lines, unsigned int sizeof_lines, char *str, int size, char **error_out); #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ -- cgit v0.10.2 From ffa0aea681a5f3c8aecbb86f1cfd3486043805de Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:58:56 -0700 Subject: [PATCH] uml - hostfs: avoid buffers Use this: .set_page_dirty = __set_page_dirty_nobuffers, We already dropped the inclusion of , and we don't have a backing block device for this FS. "Without having looked at it, I'm sure that hostfs does not use buffer_heads. So setting your ->set_page_dirty a_op to point at __set_page_dirty_nobuffers() is a reasonable thing to do - it'll provide a slight speedup." This speedup is one less spinlock held and one less conditional branch, which isn't bad. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index a88ad29..e6c63d9 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -521,7 +521,7 @@ int hostfs_commit_write(struct file *file, struct page *page, unsigned from, static struct address_space_operations hostfs_aops = { .writepage = hostfs_writepage, .readpage = hostfs_readpage, -/* .set_page_dirty = __set_page_dirty_nobuffers, */ + .set_page_dirty = __set_page_dirty_nobuffers, .prepare_write = hostfs_prepare_write, .commit_write = hostfs_commit_write }; -- cgit v0.10.2 From acef2e55d2a1b59bb5610cacc546c1d1b5de2dc9 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:58:56 -0700 Subject: [PATCH] uml: commentary about forking flag Add some commentary about UML internals, for a strange trick. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index 4d94049..b953b1a 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h @@ -17,6 +17,10 @@ struct task_struct; struct mm_struct; struct thread_struct { + /* This flag is set to 1 before calling do_fork (and analyzed in + * copy_thread) to mark that we are begin called from userspace (fork / + * vfork / clone), and reset to 0 after. It is left to 0 when called + * from kernelspace (i.e. kernel_thread() or fork_idle(), as of 2.6.11). */ int forking; int nsyscalls; struct pt_regs regs; -- cgit v0.10.2 From 2c49be99ede1e3685a9817a564b4b1678d48e1b9 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:58:57 -0700 Subject: [PATCH] uml ubd: handle readonly status Use the set_disk_ro() API when the backing file is read-only, to mark the disk read-only, during the ->open(). The current hack does not work when doing a mount -o remount. Also, mark explicitly the code paths which should no more be triggerable (I've removed the WARN_ON(1) things). They should actually become BUG()s probably but I'll avoid that since I'm not so sure the change works so well. I gave it only some limited testing. Signed-off-by: Paolo 'Blaisorblade' Giarrusso CC: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 4d8b165..9a56ff9 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -156,6 +156,7 @@ static struct gendisk *fake_gendisk[MAX_DEV]; static struct openflags global_openflags = OPEN_FLAGS; struct cow { + /* This is the backing file, actually */ char *file; int fd; unsigned long *bitmap; @@ -927,10 +928,14 @@ static int ubd_open(struct inode *inode, struct file *filp) } } dev->count++; - if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){ + set_disk_ro(disk, !dev->openflags.w); + + /* This should no more be needed. And it didn't work anyway to exclude + * read-write remounting of filesystems.*/ + /*if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){ if(--dev->count == 0) ubd_close(dev); err = -EROFS; - } + }*/ out: return(err); } @@ -1096,6 +1101,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) if(req->rq_status == RQ_INACTIVE) return(1); + /* This should be impossible now */ if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ printk("Write attempted on readonly ubd device %s\n", disk->disk_name); @@ -1243,6 +1249,7 @@ static int ubd_check_remapped(int fd, unsigned long address, int is_write, /* It's a write to a ubd device */ + /* This should be impossible now */ if(!dev->openflags.w){ /* It's a write access on a read-only device - probably * shouldn't happen. If the kernel is trying to change @@ -1605,8 +1612,7 @@ void do_io(struct io_thread_req *req) } } while((n < len) && (n != 0)); if (n < len) memset(&buf[n], 0, len - n); - } - else { + } else { n = os_write_file(req->fds[bit], buf, len); if(n != len){ printk("do_io - write failed err = %d " -- cgit v0.10.2 From b2c6678c858c5e54d95b996754adfb319cf65735 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sun, 1 May 2005 08:58:57 -0700 Subject: [PATCH] s390: regenerate defconfig Regenerate the default configuration for s390. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 1358b42..07fd041 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11 -# Wed Mar 2 16:57:55 2005 +# Linux kernel version: 2.6.12-rc3 +# Fri Apr 22 15:30:58 2005 # CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y @@ -15,6 +15,7 @@ CONFIG_UID16=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -26,24 +27,25 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=17 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +# CONFIG_CPUSETS is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y CONFIG_CC_ALIGN_FUNCTIONS=0 CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -261,7 +263,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y CONFIG_NET_KEY=y CONFIG_INET=y @@ -329,6 +330,7 @@ CONFIG_NET_SCH_DSMARK=m CONFIG_NET_QOS=y CONFIG_NET_ESTIMATOR=y CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set CONFIG_NET_CLS_TCINDEX=m CONFIG_NET_CLS_ROUTE4=m CONFIG_NET_CLS_ROUTE=y @@ -338,6 +340,7 @@ CONFIG_NET_CLS_U32=m # CONFIG_NET_CLS_IND is not set CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m +# CONFIG_NET_EMATCH is not set # CONFIG_NET_CLS_ACT is not set CONFIG_NET_CLS_POLICE=y @@ -393,6 +396,8 @@ CONFIG_CTC=m CONFIG_IUCV=m # CONFIG_NETIUCV is not set # CONFIG_SMSGIUCV is not set +# CONFIG_CLAW is not set +# CONFIG_MPC is not set CONFIG_QETH=y # @@ -532,10 +537,13 @@ CONFIG_MSDOS_PARTITION=y # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=17 # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set @@ -560,6 +568,7 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set # CONFIG_CRYPTO_DES is not set # CONFIG_CRYPTO_DES_Z990 is not set # CONFIG_CRYPTO_BLOWFISH is not set -- cgit v0.10.2 From 4b7e0706620e3947dc1685dfdbc1413404afb545 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sun, 1 May 2005 08:58:57 -0700 Subject: [PATCH] s390: idle timer setup Fix overflow in calculation of the new tod value in stop_hz_timer and fix wrong virtual timer list idle time in case the virtual timer is already expired in stop_cpu_timer. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 061e811..8ca4856 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -244,7 +244,7 @@ int sysctl_hz_timer = 1; */ static inline void stop_hz_timer(void) { - __u64 timer; + __u64 timer, todval; if (sysctl_hz_timer != 0) return; @@ -265,8 +265,14 @@ static inline void stop_hz_timer(void) * for the next event. */ timer = (__u64) (next_timer_interrupt() - jiffies) + jiffies_64; - timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY; - asm volatile ("SCKC %0" : : "m" (timer)); + todval = -1ULL; + /* Be careful about overflows. */ + if (timer < (-1ULL / CLK_TICKS_PER_JIFFY)) { + timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY; + if (timer >= jiffies_timer_cc) + todval = timer; + } + asm volatile ("SCKC %0" : : "m" (todval)); } /* diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index bb6cf02..fa07265 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -122,12 +122,17 @@ static void start_cpu_timer(void) struct vtimer_queue *vt_list; vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); - set_vtimer(vt_list->idle); + + /* CPU timer interrupt is pending, don't reprogramm it */ + if (vt_list->idle & 1LL<<63) + return; + + if (!list_empty(&vt_list->list)) + set_vtimer(vt_list->idle); } static void stop_cpu_timer(void) { - __u64 done; struct vtimer_queue *vt_list; vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); @@ -138,21 +143,17 @@ static void stop_cpu_timer(void) goto fire; } - /* store progress */ - asm volatile ("STPT %0" : "=m" (done)); + /* store the actual expire value */ + asm volatile ("STPT %0" : "=m" (vt_list->idle)); /* - * If done is negative we do not stop the CPU timer - * because we will get instantly an interrupt that - * will start the CPU timer again. + * If the CPU timer is negative we don't reprogramm + * it because we will get instantly an interrupt. */ - if (done & 1LL<<63) + if (vt_list->idle & 1LL<<63) return; - else - vt_list->offset += vt_list->to_expire - done; - /* save the actual expire value */ - vt_list->idle = done; + vt_list->offset += vt_list->to_expire - vt_list->idle; /* * We cannot halt the CPU timer, we just write a value that -- cgit v0.10.2 From c9e3735359ac2d74ee61c6f1e5724f4a6db570bf Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Sun, 1 May 2005 08:58:57 -0700 Subject: [PATCH] s390: fix memory holes and cleanup setup_arch The memory setup didn't take care of memory holes and this makes the memory management think there would be more memory available than there is in reality. That causes the OOM killer to kill processes even if there is enough memory left that can be written to the swap space. The patch fixes this by using free_area_init_node with an array of memory holes instead of free_area_init. Further the patch cleans up the code in setup.c by splitting setup_arch into smaller pieces. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index c879c40..f0679be 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -60,6 +60,8 @@ struct { #define CHUNK_READ_WRITE 0 #define CHUNK_READ_ONLY 1 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ +unsigned long __initdata zholes_size[MAX_NR_ZONES]; +static unsigned long __initdata memory_end; /* * Setup options @@ -78,11 +80,15 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, }; static struct resource code_resource = { .name = "Kernel code", + .start = (unsigned long) &_text, + .end = (unsigned long) &_etext - 1, .flags = IORESOURCE_BUSY | IORESOURCE_MEM, }; static struct resource data_resource = { .name = "Kernel data", + .start = (unsigned long) &_etext, + .end = (unsigned long) &_edata - 1, .flags = IORESOURCE_BUSY | IORESOURCE_MEM, }; @@ -310,90 +316,50 @@ void machine_power_off(void) EXPORT_SYMBOL(machine_power_off); -/* - * Setup function called from init/main.c just after the banner - * was printed. - */ -extern char _pstart, _pend, _stext; - -void __init setup_arch(char **cmdline_p) +static void __init +add_memory_hole(unsigned long start, unsigned long end) { - unsigned long bootmap_size; - unsigned long memory_start, memory_end; - char c = ' ', cn, *to = command_line, *from = COMMAND_LINE; - unsigned long start_pfn, end_pfn; - static unsigned int smptrap=0; - unsigned long delay = 0; - struct _lowcore *lc; - int i; + unsigned long dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT; + + if (end <= dma_pfn) + zholes_size[ZONE_DMA] += end - start + 1; + else if (start > dma_pfn) + zholes_size[ZONE_NORMAL] += end - start + 1; + else { + zholes_size[ZONE_DMA] += dma_pfn - start + 1; + zholes_size[ZONE_NORMAL] += end - dma_pfn; + } +} - if (smptrap) - return; - smptrap=1; +static void __init +parse_cmdline_early(char **cmdline_p) +{ + char c = ' ', cn, *to = command_line, *from = COMMAND_LINE; + unsigned long delay = 0; - /* - * print what head.S has found out about the machine - */ -#ifndef CONFIG_ARCH_S390X - printk((MACHINE_IS_VM) ? - "We are running under VM (31 bit mode)\n" : - "We are running native (31 bit mode)\n"); - printk((MACHINE_HAS_IEEE) ? - "This machine has an IEEE fpu\n" : - "This machine has no IEEE fpu\n"); -#else /* CONFIG_ARCH_S390X */ - printk((MACHINE_IS_VM) ? - "We are running under VM (64 bit mode)\n" : - "We are running native (64 bit mode)\n"); -#endif /* CONFIG_ARCH_S390X */ + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; - ROOT_DEV = Root_RAM0; - memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ -#ifndef CONFIG_ARCH_S390X - memory_end = memory_size & ~0x400000UL; /* align memory end to 4MB */ - /* - * We need some free virtual space to be able to do vmalloc. - * On a machine with 2GB memory we make sure that we have at - * least 128 MB free space for vmalloc. - */ - if (memory_end > 1920*1024*1024) - memory_end = 1920*1024*1024; -#else /* CONFIG_ARCH_S390X */ - memory_end = memory_size & ~0x200000UL; /* detected in head.s */ -#endif /* CONFIG_ARCH_S390X */ - init_mm.start_code = PAGE_OFFSET; - init_mm.end_code = (unsigned long) &_etext; - init_mm.end_data = (unsigned long) &_edata; - init_mm.brk = (unsigned long) &_end; - - code_resource.start = (unsigned long) &_text; - code_resource.end = (unsigned long) &_etext - 1; - data_resource.start = (unsigned long) &_etext; - data_resource.end = (unsigned long) &_edata - 1; - - /* Save unparsed command line copy for /proc/cmdline */ - memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; - - for (;;) { - /* - * "mem=XXX[kKmM]" sets memsize - */ - if (c == ' ' && strncmp(from, "mem=", 4) == 0) { - memory_end = simple_strtoul(from+4, &from, 0); - if ( *from == 'K' || *from == 'k' ) { - memory_end = memory_end << 10; - from++; - } else if ( *from == 'M' || *from == 'm' ) { - memory_end = memory_end << 20; - from++; - } - } - /* - * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes - */ - if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) { - delay = simple_strtoul(from+9, &from, 0); + for (;;) { + /* + * "mem=XXX[kKmM]" sets memsize + */ + if (c == ' ' && strncmp(from, "mem=", 4) == 0) { + memory_end = simple_strtoul(from+4, &from, 0); + if ( *from == 'K' || *from == 'k' ) { + memory_end = memory_end << 10; + from++; + } else if ( *from == 'M' || *from == 'm' ) { + memory_end = memory_end << 20; + from++; + } + } + /* + * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes + */ + if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) { + delay = simple_strtoul(from+9, &from, 0); if (*from == 's' || *from == 'S') { delay = delay*1000000; from++; @@ -403,24 +369,110 @@ void __init setup_arch(char **cmdline_p) } /* now wait for the requested amount of time */ udelay(delay); - } - cn = *(from++); - if (!cn) - break; - if (cn == '\n') - cn = ' '; /* replace newlines with space */ + } + cn = *(from++); + if (!cn) + break; + if (cn == '\n') + cn = ' '; /* replace newlines with space */ if (cn == 0x0d) cn = ' '; /* replace 0x0d with space */ - if (cn == ' ' && c == ' ') - continue; /* remove additional spaces */ - c = cn; - if (to - command_line >= COMMAND_LINE_SIZE) - break; - *(to++) = c; - } - if (c == ' ' && to > command_line) to--; - *to = '\0'; - *cmdline_p = command_line; + if (cn == ' ' && c == ' ') + continue; /* remove additional spaces */ + c = cn; + if (to - command_line >= COMMAND_LINE_SIZE) + break; + *(to++) = c; + } + if (c == ' ' && to > command_line) to--; + *to = '\0'; + *cmdline_p = command_line; +} + +static void __init +setup_lowcore(void) +{ + struct _lowcore *lc; + int lc_pages; + + /* + * Setup lowcore for boot cpu + */ + lc_pages = sizeof(void *) == 8 ? 2 : 1; + lc = (struct _lowcore *) + __alloc_bootmem(lc_pages * PAGE_SIZE, lc_pages * PAGE_SIZE, 0); + memset(lc, 0, lc_pages * PAGE_SIZE); + lc->restart_psw.mask = PSW_BASE_BITS; + lc->restart_psw.addr = + PSW_ADDR_AMODE | (unsigned long) restart_int_handler; + lc->external_new_psw.mask = PSW_KERNEL_BITS; + lc->external_new_psw.addr = + PSW_ADDR_AMODE | (unsigned long) ext_int_handler; + lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; + lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call; + lc->program_new_psw.mask = PSW_KERNEL_BITS; + lc->program_new_psw.addr = + PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; + lc->mcck_new_psw.mask = PSW_KERNEL_BITS; + lc->mcck_new_psw.addr = + PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; + lc->io_new_psw.mask = PSW_KERNEL_BITS; + lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; + lc->ipl_device = S390_lowcore.ipl_device; + lc->jiffy_timer = -1LL; + lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; + lc->async_stack = (unsigned long) + __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; +#ifdef CONFIG_CHECK_STACK + lc->panic_stack = (unsigned long) + __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE; +#endif + lc->current_task = (unsigned long) init_thread_union.thread_info.task; + lc->thread_info = (unsigned long) &init_thread_union; +#ifdef CONFIG_ARCH_S390X + if (MACHINE_HAS_DIAG44) + lc->diag44_opcode = 0x83000044; + else + lc->diag44_opcode = 0x07000700; +#endif /* CONFIG_ARCH_S390X */ + set_prefix((u32)(unsigned long) lc); +} + +static void __init +setup_resources(void) +{ + struct resource *res; + int i; + + for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { + res = alloc_bootmem_low(sizeof(struct resource)); + res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; + switch (memory_chunk[i].type) { + case CHUNK_READ_WRITE: + res->name = "System RAM"; + break; + case CHUNK_READ_ONLY: + res->name = "System ROM"; + res->flags |= IORESOURCE_READONLY; + break; + default: + res->name = "reserved"; + } + res->start = memory_chunk[i].addr; + res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; + request_resource(&iomem_resource, res); + request_resource(res, &code_resource); + request_resource(res, &data_resource); + } +} + +static void __init +setup_memory(void) +{ + unsigned long bootmap_size; + unsigned long start_pfn, end_pfn; + unsigned long last_rw_end; + int i; /* * partially used pages are not usable - thus @@ -437,6 +489,8 @@ void __init setup_arch(char **cmdline_p) /* * Register RAM areas with the bootmem allocator. */ + last_rw_end = start_pfn; + for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) { unsigned long start_chunk, end_chunk; @@ -450,102 +504,91 @@ void __init setup_arch(char **cmdline_p) start_chunk = start_pfn; if (end_chunk > end_pfn) end_chunk = end_pfn; - if (start_chunk < end_chunk) + if (start_chunk < end_chunk) { free_bootmem(start_chunk << PAGE_SHIFT, (end_chunk - start_chunk) << PAGE_SHIFT); + if (last_rw_end < start_chunk) + add_memory_hole(last_rw_end, start_chunk - 1); + last_rw_end = end_chunk; + } } - /* - * Reserve the bootmem bitmap itself as well. We do this in two - * steps (first step was init_bootmem()) because this catches - * the (very unlikely) case of us accidentally initializing the - * bootmem allocator with an invalid RAM area. - */ - reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); + if (last_rw_end < end_pfn - 1) + add_memory_hole(last_rw_end, end_pfn - 1); + + /* + * Reserve the bootmem bitmap itself as well. We do this in two + * steps (first step was init_bootmem()) because this catches + * the (very unlikely) case of us accidentally initializing the + * bootmem allocator with an invalid RAM area. + */ + reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); #ifdef CONFIG_BLK_DEV_INITRD - if (INITRD_START) { + if (INITRD_START) { if (INITRD_START + INITRD_SIZE <= memory_end) { reserve_bootmem(INITRD_START, INITRD_SIZE); initrd_start = INITRD_START; initrd_end = initrd_start + INITRD_SIZE; } else { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_start + INITRD_SIZE, memory_end); - initrd_start = initrd_end = 0; + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + initrd_start + INITRD_SIZE, memory_end); + initrd_start = initrd_end = 0; } - } + } #endif +} - for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) { - struct resource *res; - - res = alloc_bootmem_low(sizeof(struct resource)); - res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; - - switch (memory_chunk[i].type) { - case CHUNK_READ_WRITE: - res->name = "System RAM"; - break; - case CHUNK_READ_ONLY: - res->name = "System ROM"; - res->flags |= IORESOURCE_READONLY; - break; - default: - res->name = "reserved"; - } - res->start = memory_chunk[i].addr; - res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; - request_resource(&iomem_resource, res); - request_resource(res, &code_resource); - request_resource(res, &data_resource); - } +/* + * Setup function called from init/main.c just after the banner + * was printed. + */ +void __init +setup_arch(char **cmdline_p) +{ /* - * Setup lowcore for boot cpu + * print what head.S has found out about the machine */ #ifndef CONFIG_ARCH_S390X - lc = (struct _lowcore *) __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0); - memset(lc, 0, PAGE_SIZE); + printk((MACHINE_IS_VM) ? + "We are running under VM (31 bit mode)\n" : + "We are running native (31 bit mode)\n"); + printk((MACHINE_HAS_IEEE) ? + "This machine has an IEEE fpu\n" : + "This machine has no IEEE fpu\n"); #else /* CONFIG_ARCH_S390X */ - lc = (struct _lowcore *) __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0); - memset(lc, 0, 2*PAGE_SIZE); + printk((MACHINE_IS_VM) ? + "We are running under VM (64 bit mode)\n" : + "We are running native (64 bit mode)\n"); #endif /* CONFIG_ARCH_S390X */ - lc->restart_psw.mask = PSW_BASE_BITS; - lc->restart_psw.addr = - PSW_ADDR_AMODE | (unsigned long) restart_int_handler; - lc->external_new_psw.mask = PSW_KERNEL_BITS; - lc->external_new_psw.addr = - PSW_ADDR_AMODE | (unsigned long) ext_int_handler; - lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; - lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call; - lc->program_new_psw.mask = PSW_KERNEL_BITS; - lc->program_new_psw.addr = - PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; - lc->mcck_new_psw.mask = PSW_KERNEL_BITS; - lc->mcck_new_psw.addr = - PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; - lc->io_new_psw.mask = PSW_KERNEL_BITS; - lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; - lc->ipl_device = S390_lowcore.ipl_device; - lc->jiffy_timer = -1LL; - lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; - lc->async_stack = (unsigned long) - __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; -#ifdef CONFIG_CHECK_STACK - lc->panic_stack = (unsigned long) - __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE; -#endif - lc->current_task = (unsigned long) init_thread_union.thread_info.task; - lc->thread_info = (unsigned long) &init_thread_union; -#ifdef CONFIG_ARCH_S390X - if (MACHINE_HAS_DIAG44) - lc->diag44_opcode = 0x83000044; - else - lc->diag44_opcode = 0x07000700; + + ROOT_DEV = Root_RAM0; +#ifndef CONFIG_ARCH_S390X + memory_end = memory_size & ~0x400000UL; /* align memory end to 4MB */ + /* + * We need some free virtual space to be able to do vmalloc. + * On a machine with 2GB memory we make sure that we have at + * least 128 MB free space for vmalloc. + */ + if (memory_end > 1920*1024*1024) + memory_end = 1920*1024*1024; +#else /* CONFIG_ARCH_S390X */ + memory_end = memory_size & ~0x200000UL; /* detected in head.s */ #endif /* CONFIG_ARCH_S390X */ - set_prefix((u32)(unsigned long) lc); + + init_mm.start_code = PAGE_OFFSET; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + + parse_cmdline_early(cmdline_p); + + setup_memory(); + setup_resources(); + setup_lowcore(); + cpu_init(); __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 8e723bc..6ec5cd9 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -101,6 +101,7 @@ extern unsigned long _end; extern unsigned long __init_begin; extern unsigned long __init_end; +extern unsigned long __initdata zholes_size[]; /* * paging_init() sets up the page tables */ @@ -163,10 +164,13 @@ void __init paging_init(void) local_flush_tlb(); { - unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES]; + memset(zones_size, 0, sizeof(zones_size)); zones_size[ZONE_DMA] = max_low_pfn; - free_area_init(zones_size); + free_area_init_node(0, &contig_page_data, zones_size, + __pa(PAGE_OFFSET) >> PAGE_SHIFT, + zholes_size); } return; } @@ -184,9 +188,10 @@ void __init paging_init(void) _KERN_REGION_TABLE; static const int ssm_mask = 0x04000000L; - unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES]; unsigned long dma_pfn, high_pfn; + memset(zones_size, 0, sizeof(zones_size)); dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT; high_pfn = max_low_pfn; @@ -198,8 +203,8 @@ void __init paging_init(void) } /* Initialize mem_map[]. */ - free_area_init(zones_size); - + free_area_init_node(0, &contig_page_data, zones_size, + __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size); /* * map whole physical memory to virtual memory (identity mapping) -- cgit v0.10.2 From 0b642ede47969d4180b0922d982777fe64379228 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Sun, 1 May 2005 08:58:58 -0700 Subject: [PATCH] s390: default storage key Provide an easy way to define a non-zero storage key at compile time. This is useful for debugging purposes. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 11fd6d5..bee654a 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -34,7 +34,6 @@ EXPORT_SYMBOL(__clear_user_asm); EXPORT_SYMBOL(__strncpy_from_user_asm); EXPORT_SYMBOL(__strnlen_user_asm); EXPORT_SYMBOL(diag10); -EXPORT_SYMBOL(default_storage_key); /* * semaphore ops diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index f0679be..df83215 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include /* * Machine setup.. @@ -53,7 +55,6 @@ unsigned int console_devno = -1; unsigned int console_irq = -1; unsigned long memory_size = 0; unsigned long machine_flags = 0; -unsigned int default_storage_key = 0; struct { unsigned long addr, size, type; } memory_chunk[MEMORY_CHUNKS] = { { 0 } }; @@ -402,7 +403,7 @@ setup_lowcore(void) lc = (struct _lowcore *) __alloc_bootmem(lc_pages * PAGE_SIZE, lc_pages * PAGE_SIZE, 0); memset(lc, 0, lc_pages * PAGE_SIZE); - lc->restart_psw.mask = PSW_BASE_BITS; + lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) restart_int_handler; lc->external_new_psw.mask = PSW_KERNEL_BITS; @@ -470,7 +471,7 @@ static void __init setup_memory(void) { unsigned long bootmap_size; - unsigned long start_pfn, end_pfn; + unsigned long start_pfn, end_pfn, init_pfn; unsigned long last_rw_end; int i; @@ -481,6 +482,10 @@ setup_memory(void) start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT; end_pfn = max_pfn = memory_end >> PAGE_SHIFT; + /* Initialize storage key for kernel pages */ + for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++) + page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); + /* * Initialize the boot-time allocator (with low memory only): */ @@ -491,7 +496,7 @@ setup_memory(void) */ last_rw_end = start_pfn; - for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) { + for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { unsigned long start_chunk, end_chunk; if (memory_chunk[i].type != CHUNK_READ_WRITE) @@ -505,6 +510,11 @@ setup_memory(void) if (end_chunk > end_pfn) end_chunk = end_pfn; if (start_chunk < end_chunk) { + /* Initialize storage key for RAM pages */ + for (init_pfn = start_chunk ; init_pfn < end_chunk; + init_pfn++) + page_set_storage_key(init_pfn << PAGE_SHIFT, + PAGE_DEFAULT_KEY); free_bootmem(start_chunk << PAGE_SHIFT, (end_chunk - start_chunk) << PAGE_SHIFT); if (last_rw_end < start_chunk) @@ -513,6 +523,8 @@ setup_memory(void) } } + psw_set_key(PAGE_DEFAULT_KEY); + if (last_rw_end < end_pfn - 1) add_memory_hole(last_rw_end, end_pfn - 1); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 99ce5a5..1d9b3f1 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls - * $Revision: 1.131 $ + * $Revision: 1.133 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -228,7 +228,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ int cio_start (struct subchannel *sch, struct ccw1 *cpa, __u8 lpm) { - return cio_start_key(sch, cpa, lpm, default_storage_key); + return cio_start_key(sch, cpa, lpm, PAGE_DEFAULT_KEY); } /* diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 11e260e..02d01a0 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/device_ops.c * - * $Revision: 1.55 $ + * $Revision: 1.56 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -128,7 +128,7 @@ ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa, unsigned long intparm, __u8 lpm, unsigned long flags) { return ccw_device_start_key(cdev, cpa, intparm, lpm, - default_storage_key, flags); + PAGE_DEFAULT_KEY, flags); } int @@ -137,7 +137,7 @@ ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, int expires) { return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, - default_storage_key, flags, + PAGE_DEFAULT_KEY, flags, expires); } diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 9ad14db..b6daada 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -1,7 +1,9 @@ #ifndef _CIO_QDIO_H #define _CIO_QDIO_H -#define VERSION_CIO_QDIO_H "$Revision: 1.26 $" +#include + +#define VERSION_CIO_QDIO_H "$Revision: 1.32 $" #ifdef CONFIG_QDIO_DEBUG #define QDIO_VERBOSE_LEVEL 9 @@ -42,7 +44,7 @@ #define QDIO_Q_LAPS 5 -#define QDIO_STORAGE_KEY 0 +#define QDIO_STORAGE_KEY PAGE_DEFAULT_KEY #define L2_CACHELINE_SIZE 256 #define INDICATORS_PER_CACHELINE (L2_CACHELINE_SIZE/sizeof(__u32)) diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index 614e2a9..2be287b 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h @@ -16,6 +16,8 @@ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) +#define PAGE_DEFAULT_ACC 0 +#define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4) #ifdef __KERNEL__ #ifndef __ASSEMBLY__ diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index 88c272c..fb46e90 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -245,7 +245,7 @@ static inline void enabled_wait(void) psw_t wait_psw; wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT | - PSW_MASK_MCHECK | PSW_MASK_WAIT; + PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY; #ifndef __s390x__ asm volatile ( " basr %0,0\n" diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h index 1dc8066..4eff8f2 100644 --- a/include/asm-s390/ptrace.h +++ b/include/asm-s390/ptrace.h @@ -185,6 +185,7 @@ #include #include #include +#include typedef union { @@ -235,6 +236,7 @@ typedef struct #define PSW_ADDR_INSN 0x7FFFFFFFUL #define PSW_BASE_BITS 0x00080000UL +#define PSW_DEFAULT_KEY (((unsigned long) PAGE_DEFAULT_ACC) << 20) #define PSW_ASC_PRIMARY 0x00000000UL #define PSW_ASC_ACCREG 0x00004000UL @@ -260,6 +262,7 @@ typedef struct #define PSW_BASE_BITS 0x0000000180000000UL #define PSW_BASE32_BITS 0x0000000080000000UL +#define PSW_DEFAULT_KEY (((unsigned long) PAGE_DEFAULT_ACC) << 52) #define PSW_ASC_PRIMARY 0x0000000000000000UL #define PSW_ASC_ACCREG 0x0000400000000000UL @@ -268,14 +271,15 @@ typedef struct #define PSW_USER32_BITS (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \ - PSW_MASK_PSTATE) + PSW_MASK_PSTATE | PSW_DEFAULT_KEY) #endif /* __s390x__ */ -#define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY) +#define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \ + PSW_DEFAULT_KEY) #define PSW_USER_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \ - PSW_MASK_PSTATE) + PSW_MASK_PSTATE | PSW_DEFAULT_KEY) /* This macro merges a NEW PSW mask specified by the user into the currently active PSW mask CURRENT, modifying only those @@ -470,6 +474,12 @@ struct user_regs_struct extern void show_regs(struct pt_regs * regs); #endif +static inline void +psw_set_key(unsigned int key) +{ + asm volatile ( "spka 0(%0)" : : "d" (key) ); +} + #endif /* __ASSEMBLY__ */ #endif /* _S390_PTRACE_H */ -- cgit v0.10.2 From 15439d74f621ff8252b53136d259781148e6e768 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sun, 1 May 2005 08:58:58 -0700 Subject: [PATCH] s390: cmm guest sender id An arbitrary guest must not be allowed to trigger cmm actions. Only one specific guest namely the one that serves as the resource monitor may send cmm messages. Add a parameter that allows to specify the guest that may send messages. z/VMs resource manager has the name 'VMRMSVM' which is the default. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index d30cdb4..f5a5bc0 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -20,6 +20,11 @@ #include #include +static char *sender = "VMRMSVM"; +module_param(sender, charp, 0); +MODULE_PARM_DESC(sender, + "Guest name that may send SMSG messages (default VMRMSVM)"); + #include "../../../drivers/s390/net/smsgiucv.h" #define CMM_NR_PAGES ((PAGE_SIZE / sizeof(unsigned long)) - 2) @@ -367,10 +372,12 @@ static struct ctl_table cmm_dir_table[] = { #ifdef CONFIG_CMM_IUCV #define SMSG_PREFIX "CMM" static void -cmm_smsg_target(char *msg) +cmm_smsg_target(char *from, char *msg) { long pages, seconds; + if (strlen(sender) > 0 && strcmp(from, sender) != 0) + return; if (!cmm_skip_blanks(msg + strlen(SMSG_PREFIX), &msg)) return; if (strncmp(msg, "SHRINK", 6) == 0) { diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index a3d2858..1e3f7f3 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -32,7 +32,7 @@ struct smsg_callback { struct list_head list; char *prefix; int len; - void (*callback)(char *str); + void (*callback)(char *from, char *str); }; MODULE_AUTHOR @@ -55,8 +55,9 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) { struct smsg_callback *cb; unsigned char *msg; + unsigned char sender[9]; unsigned short len; - int rc; + int rc, i; len = eib->ln1msg2.ipbfln1f; msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA); @@ -69,10 +70,18 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) if (rc == 0) { msg[len] = 0; EBCASC(msg, len); + memcpy(sender, msg, 8); + sender[8] = 0; + /* Remove trailing whitespace from the sender name. */ + for (i = 7; i >= 0; i--) { + if (sender[i] != ' ' && sender[i] != '\t') + break; + sender[i] = 0; + } spin_lock(&smsg_list_lock); list_for_each_entry(cb, &smsg_list, list) if (strncmp(msg + 8, cb->prefix, cb->len) == 0) { - cb->callback(msg + 8); + cb->callback(sender, msg + 8); break; } spin_unlock(&smsg_list_lock); @@ -91,7 +100,7 @@ static struct device_driver smsg_driver = { }; int -smsg_register_callback(char *prefix, void (*callback)(char *str)) +smsg_register_callback(char *prefix, void (*callback)(char *from, char *str)) { struct smsg_callback *cb; @@ -108,7 +117,7 @@ smsg_register_callback(char *prefix, void (*callback)(char *str)) } void -smsg_unregister_callback(char *prefix, void (*callback)(char *str)) +smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str)) { struct smsg_callback *cb, *tmp; diff --git a/drivers/s390/net/smsgiucv.h b/drivers/s390/net/smsgiucv.h index 04cd871..67f5d4f 100644 --- a/drivers/s390/net/smsgiucv.h +++ b/drivers/s390/net/smsgiucv.h @@ -5,6 +5,6 @@ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) */ -int smsg_register_callback(char *, void (*)(char *)); -void smsg_unregister_callback(char *, void (*)(char *)); +int smsg_register_callback(char *, void (*)(char *, char *)); +void smsg_unregister_callback(char *, void (*)(char *, char *)); -- cgit v0.10.2 From e8f0641ef74eaa71ed9aa9d19c4b741c2143d752 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Sun, 1 May 2005 08:58:58 -0700 Subject: [PATCH] s390: allow longer debug feature names The current limitation of 16 characters of the debug feature names turned out to be insufficient. Increase it to 64 characters. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-s390/debug.h b/include/asm-s390/debug.h index 28ef235..6bbcdea 100644 --- a/include/asm-s390/debug.h +++ b/include/asm-s390/debug.h @@ -43,7 +43,7 @@ struct __debug_entry{ #define DEBUG_OFF_LEVEL -1 /* level where debug is switched off */ #define DEBUG_FLUSH_ALL -1 /* parameter to flush all areas */ #define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */ -#define DEBUG_MAX_PROCF_LEN 16 /* max length for a proc file name */ +#define DEBUG_MAX_PROCF_LEN 64 /* max length for a proc file name */ #define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */ #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */ -- cgit v0.10.2 From f24acd4503270ed4c842c8fef0b71105285e0a06 Mon Sep 17 00:00:00 2001 From: Horst Hummel Date: Sun, 1 May 2005 08:58:59 -0700 Subject: [PATCH] s390: dasd readonly attribute The independent read-only flags in devmap, dasd_device and gendisk are not kept in sync. Use one bit per feature in the dasd driver and keep that bit in sync with the gendisk bit. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index b755bac..826fd23 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * - * $Revision: 1.158 $ + * $Revision: 1.161 $ */ #include @@ -1131,13 +1131,17 @@ __dasd_process_blk_queue(struct dasd_device * device) request_queue_t *queue; struct request *req; struct dasd_ccw_req *cqr; - int nr_queued; + int nr_queued, feature_ro; queue = device->request_queue; /* No queue ? Then there is nothing to do. */ if (queue == NULL) return; + feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY); + if (feature_ro < 0) /* no devmap */ + return; + /* * We requeue request from the block device queue to the ccw * queue only in two states. In state DASD_STATE_READY the @@ -1157,8 +1161,8 @@ __dasd_process_blk_queue(struct dasd_device * device) elv_next_request(queue) && nr_queued < DASD_CHANQ_MAX_SIZE) { req = elv_next_request(queue); - if (test_bit(DASD_FLAG_RO, &device->flags) && - rq_data_dir(req) == WRITE) { + + if (feature_ro && rq_data_dir(req) == WRITE) { DBF_DEV_EVENT(DBF_ERR, device, "Rejecting write request %p", req); @@ -1803,13 +1807,17 @@ dasd_generic_set_online (struct ccw_device *cdev, { struct dasd_device *device; - int rc; + int feature_diag, rc; + + feature_diag = dasd_get_feature(cdev, DASD_FEATURE_USEDIAG); + if (feature_diag < 0) + return feature_diag; device = dasd_create_device(cdev); if (IS_ERR(device)) return PTR_ERR(device); - if (test_bit(DASD_FLAG_USE_DIAG, &device->flags)) { + if (feature_diag) { if (!dasd_diag_discipline_pointer) { printk (KERN_WARNING "dasd_generic couldn't online device %s " diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index ad1841a..1aedc48 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -11,7 +11,7 @@ * functions may not be called from interrupt context. In particular * dasd_get_device is a no-no from interrupt context. * - * $Revision: 1.37 $ + * $Revision: 1.40 $ */ #include @@ -513,14 +513,6 @@ dasd_create_device(struct ccw_device *cdev) if (!devmap->device) { devmap->device = device; device->devindex = devmap->devindex; - if (devmap->features & DASD_FEATURE_READONLY) - set_bit(DASD_FLAG_RO, &device->flags); - else - clear_bit(DASD_FLAG_RO, &device->flags); - if (devmap->features & DASD_FEATURE_USEDIAG) - set_bit(DASD_FLAG_USE_DIAG, &device->flags); - else - clear_bit(DASD_FLAG_USE_DIAG, &device->flags); get_device(&cdev->dev); device->cdev = cdev; rc = 0; @@ -651,14 +643,8 @@ dasd_ro_store(struct device *dev, const char *buf, size_t count) devmap->features |= DASD_FEATURE_READONLY; else devmap->features &= ~DASD_FEATURE_READONLY; - if (devmap->device) { - if (devmap->device->gdp) - set_disk_ro(devmap->device->gdp, ro_flag); - if (ro_flag) - set_bit(DASD_FLAG_RO, &devmap->device->flags); - else - clear_bit(DASD_FLAG_RO, &devmap->device->flags); - } + if (devmap->device && devmap->device->gdp) + set_disk_ro(devmap->device->gdp, ro_flag); spin_unlock(&dasd_devmap_lock); return count; } @@ -739,6 +725,45 @@ static struct attribute_group dasd_attr_group = { .attrs = dasd_attrs, }; +/* + * Return value of the specified feature. + */ +int +dasd_get_feature(struct ccw_device *cdev, int feature) +{ + struct dasd_devmap *devmap; + + devmap = dasd_find_busid(cdev->dev.bus_id); + if (IS_ERR(devmap)) + return (int) PTR_ERR(devmap); + + return ((devmap->features & feature) != 0); +} + +/* + * Set / reset given feature. + * Flag indicates wether to set (!=0) or the reset (=0) the feature. + */ +int +dasd_set_feature(struct ccw_device *cdev, int feature, int flag) +{ + struct dasd_devmap *devmap; + + devmap = dasd_find_busid(cdev->dev.bus_id); + if (IS_ERR(devmap)) + return (int) PTR_ERR(devmap); + + spin_lock(&dasd_devmap_lock); + if (flag) + devmap->features |= feature; + else + devmap->features &= ~feature; + + spin_unlock(&dasd_devmap_lock); + return 0; +} + + int dasd_add_sysfs_files(struct ccw_device *cdev) { diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 1d52db4..96c4934 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -9,7 +9,7 @@ * * gendisk related functions for the dasd driver. * - * $Revision: 1.48 $ + * $Revision: 1.50 $ */ #include @@ -31,12 +31,16 @@ int dasd_gendisk_alloc(struct dasd_device *device) { struct gendisk *gdp; - int len; + int len, feature_ro; /* Make sure the minor for this device exists. */ if (device->devindex >= DASD_PER_MAJOR) return -EBUSY; + feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY); + if (feature_ro < 0) + return feature_ro; + gdp = alloc_disk(1 << DASD_PARTN_BITS); if (!gdp) return -ENOMEM; @@ -71,7 +75,7 @@ dasd_gendisk_alloc(struct dasd_device *device) sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id); - if (test_bit(DASD_FLAG_RO, &device->flags)) + if (feature_ro) set_disk_ro(gdp, 1); gdp->private_data = device; gdp->queue = device->request_queue; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 4586e0e..a9f38b2 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.63 $ + * $Revision: 1.64 $ */ #ifndef DASD_INT_H @@ -329,8 +329,6 @@ struct dasd_device { #define DASD_STOPPED_DC_EIO 16 /* disconnected, return -EIO */ /* per device flags */ -#define DASD_FLAG_RO 0 /* device is read-only */ -#define DASD_FLAG_USE_DIAG 1 /* use diag disciplnie */ #define DASD_FLAG_DSC_ERROR 2 /* return -EIO when disconnected */ #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ @@ -501,6 +499,9 @@ void dasd_devmap_exit(void); struct dasd_device *dasd_create_device(struct ccw_device *); void dasd_delete_device(struct dasd_device *); +int dasd_get_feature(struct ccw_device *, int); +int dasd_set_feature(struct ccw_device *, int, int); + int dasd_add_sysfs_files(struct ccw_device *); void dasd_remove_sysfs_files(struct ccw_device *); diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index f1892ba..980c555 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -7,6 +7,8 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * + * $Revision: 1.45 $ + * * i/o controls for the dasd driver. */ #include @@ -294,6 +296,7 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args) { struct dasd_device *device; struct format_data_t fdata; + int feature_ro; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -304,7 +307,11 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args) if (device == NULL) return -ENODEV; - if (test_bit(DASD_FLAG_RO, &device->flags)) + + feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY); + if (feature_ro < 0) + return feature_ro; + if (feature_ro) return -EROFS; if (copy_from_user(&fdata, (void __user *) args, sizeof (struct format_data_t))) @@ -377,7 +384,7 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) struct dasd_device *device; struct dasd_information2_t *dasd_info; unsigned long flags; - int rc; + int rc, feature_ro; struct ccw_device *cdev; device = bdev->bd_disk->private_data; @@ -387,6 +394,10 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) if (!device->discipline->fill_info) return -EINVAL; + feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY); + if (feature_ro < 0) + return feature_ro; + dasd_info = kmalloc(sizeof(struct dasd_information2_t), GFP_KERNEL); if (dasd_info == NULL) return -ENOMEM; @@ -415,9 +426,8 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) if ((device->state < DASD_STATE_READY) || (dasd_check_blocksize(device->bp_block))) dasd_info->format = DASD_FORMAT_NONE; - - dasd_info->features |= test_bit(DASD_FLAG_RO, &device->flags) ? - DASD_FEATURE_READONLY : DASD_FEATURE_DEFAULT; + + dasd_info->features |= feature_ro; if (device->discipline) memcpy(dasd_info->type, device->discipline->name, 4); @@ -460,7 +470,7 @@ static int dasd_ioctl_set_ro(struct block_device *bdev, int no, long args) { struct dasd_device *device; - int intval; + int intval, rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -472,12 +482,11 @@ dasd_ioctl_set_ro(struct block_device *bdev, int no, long args) device = bdev->bd_disk->private_data; if (device == NULL) return -ENODEV; + set_disk_ro(bdev->bd_disk, intval); - if (intval) - set_bit(DASD_FLAG_RO, &device->flags); - else - clear_bit(DASD_FLAG_RO, &device->flags); - return 0; + rc = dasd_set_feature(device->cdev, DASD_FEATURE_READONLY, intval); + + return rc; } /* diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 353d411..d7f1974 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -9,7 +9,7 @@ * * /proc interface for the dasd driver. * - * $Revision: 1.30 $ + * $Revision: 1.31 $ */ #include @@ -54,6 +54,7 @@ dasd_devices_show(struct seq_file *m, void *v) { struct dasd_device *device; char *substr; + int feature; device = dasd_device_from_devindex((unsigned long) v - 1); if (IS_ERR(device)) @@ -77,7 +78,10 @@ dasd_devices_show(struct seq_file *m, void *v) else seq_printf(m, " is ????????"); /* Print devices features. */ - substr = test_bit(DASD_FLAG_RO, &device->flags) ? "(ro)" : " "; + feature = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY); + if (feature < 0) + return 0; + substr = feature ? "(ro)" : " "; seq_printf(m, "%4s: ", substr); /* Print device status information. */ switch ((device != NULL) ? device->state : -1) { -- cgit v0.10.2 From 6ed93c827eea181d87ce078cd1d671128c030b5a Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Sun, 1 May 2005 08:58:59 -0700 Subject: [PATCH] s390: enable write barriers in the dasd driver The DASD device driver never reorders the I/O requests and relies on the hardware to write all data to nonvolatile storage before signaling a successful write. Hence, the only thing we have to do to support write barriers is to set the queue ordered flag. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 826fd23..02cfe24 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1635,6 +1635,7 @@ dasd_setup_queue(struct dasd_device * device) blk_queue_max_hw_segments(device->request_queue, -1L); blk_queue_max_segment_size(device->request_queue, -1L); blk_queue_segment_boundary(device->request_queue, -1L); + blk_queue_ordered(device->request_queue, 1); } /* -- cgit v0.10.2 From ec5883abebb2e249ea8d318cb58fb4b2c269cf10 Mon Sep 17 00:00:00 2001 From: Horst Hummel Date: Sun, 1 May 2005 08:58:59 -0700 Subject: [PATCH] s390: don't pad cdl blocks for write requests The first blocks on a cdl formatted dasd device are smaller than the blocksize of the device. Read requests are padded with a 'e5' pattern. Write requests should not pad the (user) buffer with 'e5' because a write request is not allowed to modify the buffer. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 838aedf..811060e 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.69 $ + * $Revision: 1.71 $ */ #include @@ -1101,7 +1101,8 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) if (dasd_eckd_cdl_special(blk_per_trk, recid)){ rcmd |= 0x8; count = dasd_eckd_cdl_reclen(recid); - if (count < blksize) + if (count < blksize && + rq_data_dir(req) == READ) memset(dst + count, 0xe5, blksize - count); } -- cgit v0.10.2 From 4beb37097b20b61054b15c56848e4ffcef093819 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Sun, 1 May 2005 08:58:59 -0700 Subject: [PATCH] s390: remove ioctl32 from dasdcmb The ioctl32_conversion routines will be deprecated: Remove them from dasd_cmb and handle the three cmb ioctls like all other dasd ioctls. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/kernel/compat_ioctl.c b/arch/s390/kernel/compat_ioctl.c index 96571ff..03d03c6 100644 --- a/arch/s390/kernel/compat_ioctl.c +++ b/arch/s390/kernel/compat_ioctl.c @@ -16,6 +16,7 @@ #define CODE #include "../../../fs/compat_ioctl.c" #include +#include #include static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd, @@ -58,7 +59,11 @@ COMPATIBLE_IOCTL(BIODASDPRRD) COMPATIBLE_IOCTL(BIODASDPSRD) COMPATIBLE_IOCTL(BIODASDGATTR) COMPATIBLE_IOCTL(BIODASDSATTR) - +#if defined(CONFIG_DASD_CMB) || defined(CONFIG_DASD_CMB_MODULE) +COMPATIBLE_IOCTL(BIODASDCMFENABLE) +COMPATIBLE_IOCTL(BIODASDCMFDISABLE) +COMPATIBLE_IOCTL(BIODASDREADALLCMB) +#endif #endif #if defined(CONFIG_S390_TAPE) || defined(CONFIG_S390_TAPE_MODULE) diff --git a/drivers/s390/block/dasd_cmb.c b/drivers/s390/block/dasd_cmb.c index ed1ab47..4f365bf 100644 --- a/drivers/s390/block/dasd_cmb.c +++ b/drivers/s390/block/dasd_cmb.c @@ -1,5 +1,5 @@ /* - * linux/drivers/s390/block/dasd_cmb.c ($Revision: 1.6 $) + * linux/drivers/s390/block/dasd_cmb.c ($Revision: 1.9 $) * * Linux on zSeries Channel Measurement Facility support * (dasd device driver interface) @@ -23,7 +23,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include -#include #include #include #include @@ -84,27 +83,13 @@ dasd_ioctl_readall_cmb(struct block_device *bdev, int no, long args) static inline int ioctl_reg(unsigned int no, dasd_ioctl_fn_t handler) { - int ret; - ret = dasd_ioctl_no_register(THIS_MODULE, no, handler); -#ifdef CONFIG_COMPAT - if (ret) - return ret; - - ret = register_ioctl32_conversion(no, NULL); - if (ret) - dasd_ioctl_no_unregister(THIS_MODULE, no, handler); -#endif - return ret; + return dasd_ioctl_no_register(THIS_MODULE, no, handler); } static inline void ioctl_unreg(unsigned int no, dasd_ioctl_fn_t handler) { dasd_ioctl_no_unregister(THIS_MODULE, no, handler); -#ifdef CONFIG_COMPAT - unregister_ioctl32_conversion(no); -#endif - } static void diff --git a/include/asm-s390/cmb.h b/include/asm-s390/cmb.h index 1bfe2bd..dae1dd4 100644 --- a/include/asm-s390/cmb.h +++ b/include/asm-s390/cmb.h @@ -52,7 +52,7 @@ struct cmbdata { #define BIODASDREADALLCMB _IOWR(DASD_IOCTL_LETTER,33,struct cmbdata) #ifdef __KERNEL__ - +struct ccw_device; /** * enable_cmf() - switch on the channel measurement for a specific device * @cdev: The ccw device to be enabled -- cgit v0.10.2 From af6c8eed14a0c14791e2fbb4c7726755c1a637ca Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Sun, 1 May 2005 08:59:00 -0700 Subject: [PATCH] s390: remove ioctl32 from crypto driver The ioctl32_conversion routines will be deprecated: Remove them from the crypto driver. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c index a98c00c..9ec29bb 100644 --- a/drivers/s390/crypto/z90main.c +++ b/drivers/s390/crypto/z90main.c @@ -385,8 +385,8 @@ static int z90crypt_release(struct inode *, struct file *); static ssize_t z90crypt_read(struct file *, char __user *, size_t, loff_t *); static ssize_t z90crypt_write(struct file *, const char __user *, size_t, loff_t *); -static int z90crypt_ioctl(struct inode *, struct file *, - unsigned int, unsigned long); +static long z90crypt_unlocked_ioctl(struct file *, unsigned int, unsigned long); +static long z90crypt_compat_ioctl(struct file *, unsigned int, unsigned long); static void z90crypt_reader_task(unsigned long); static void z90crypt_schedule_reader_task(unsigned long); @@ -433,12 +433,15 @@ static atomic_t total_open; static atomic_t z90crypt_step; static struct file_operations z90crypt_fops = { - .owner = THIS_MODULE, - .read = z90crypt_read, - .write = z90crypt_write, - .ioctl = z90crypt_ioctl, - .open = z90crypt_open, - .release = z90crypt_release + .owner = THIS_MODULE, + .read = z90crypt_read, + .write = z90crypt_write, + .unlocked_ioctl = z90crypt_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = z90crypt_compat_ioctl, +#endif + .open = z90crypt_open, + .release = z90crypt_release }; #ifndef Z90CRYPT_USE_HOTPLUG @@ -474,14 +477,13 @@ struct ica_rsa_modexpo_32 { // For 32-bit callers compat_uptr_t n_modulus; }; -static int -trans_modexpo32(unsigned int fd, unsigned int cmd, unsigned long arg, - struct file *file) +static long +trans_modexpo32(struct file *filp, unsigned int cmd, unsigned long arg) { struct ica_rsa_modexpo_32 __user *mex32u = compat_ptr(arg); struct ica_rsa_modexpo_32 mex32k; struct ica_rsa_modexpo __user *mex64; - int ret = 0; + long ret = 0; unsigned int i; if (!access_ok(VERIFY_WRITE, mex32u, sizeof(struct ica_rsa_modexpo_32))) @@ -498,7 +500,7 @@ trans_modexpo32(unsigned int fd, unsigned int cmd, unsigned long arg, __put_user(compat_ptr(mex32k.b_key), &mex64->b_key) || __put_user(compat_ptr(mex32k.n_modulus), &mex64->n_modulus)) return -EFAULT; - ret = sys_ioctl(fd, cmd, (unsigned long)mex64); + ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)mex64); if (!ret) if (__get_user(i, &mex64->outputdatalength) || __put_user(i, &mex32u->outputdatalength)) @@ -518,14 +520,13 @@ struct ica_rsa_modexpo_crt_32 { // For 32-bit callers compat_uptr_t u_mult_inv; }; -static int -trans_modexpo_crt32(unsigned int fd, unsigned int cmd, unsigned long arg, - struct file *file) +static long +trans_modexpo_crt32(struct file *filp, unsigned int cmd, unsigned long arg) { struct ica_rsa_modexpo_crt_32 __user *crt32u = compat_ptr(arg); struct ica_rsa_modexpo_crt_32 crt32k; struct ica_rsa_modexpo_crt __user *crt64; - int ret = 0; + long ret = 0; unsigned int i; if (!access_ok(VERIFY_WRITE, crt32u, @@ -546,9 +547,8 @@ trans_modexpo_crt32(unsigned int fd, unsigned int cmd, unsigned long arg, __put_user(compat_ptr(crt32k.np_prime), &crt64->np_prime) || __put_user(compat_ptr(crt32k.nq_prime), &crt64->nq_prime) || __put_user(compat_ptr(crt32k.u_mult_inv), &crt64->u_mult_inv)) - ret = -EFAULT; - if (!ret) - ret = sys_ioctl(fd, cmd, (unsigned long)crt64); + return -EFAULT; + ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)crt64); if (!ret) if (__get_user(i, &crt64->outputdatalength) || __put_user(i, &crt32u->outputdatalength)) @@ -556,66 +556,34 @@ trans_modexpo_crt32(unsigned int fd, unsigned int cmd, unsigned long arg, return ret; } -static int compatible_ioctls[] = { - ICAZ90STATUS, Z90QUIESCE, Z90STAT_TOTALCOUNT, Z90STAT_PCICACOUNT, - Z90STAT_PCICCCOUNT, Z90STAT_PCIXCCCOUNT, Z90STAT_PCIXCCMCL2COUNT, - Z90STAT_PCIXCCMCL3COUNT, Z90STAT_CEX2CCOUNT, Z90STAT_REQUESTQ_COUNT, - Z90STAT_PENDINGQ_COUNT, Z90STAT_TOTALOPEN_COUNT, Z90STAT_DOMAIN_INDEX, - Z90STAT_STATUS_MASK, Z90STAT_QDEPTH_MASK, Z90STAT_PERDEV_REQCNT, -}; - -static void z90_unregister_ioctl32s(void) -{ - int i; - - unregister_ioctl32_conversion(ICARSAMODEXPO); - unregister_ioctl32_conversion(ICARSACRT); - - for(i = 0; i < ARRAY_SIZE(compatible_ioctls); i++) - unregister_ioctl32_conversion(compatible_ioctls[i]); -} - -static int z90_register_ioctl32s(void) -{ - int result, i; - - result = register_ioctl32_conversion(ICARSAMODEXPO, trans_modexpo32); - if (result == -EBUSY) { - unregister_ioctl32_conversion(ICARSAMODEXPO); - result = register_ioctl32_conversion(ICARSAMODEXPO, - trans_modexpo32); - } - if (result) - return result; - result = register_ioctl32_conversion(ICARSACRT, trans_modexpo_crt32); - if (result == -EBUSY) { - unregister_ioctl32_conversion(ICARSACRT); - result = register_ioctl32_conversion(ICARSACRT, - trans_modexpo_crt32); - } - if (result) - return result; - - for(i = 0; i < ARRAY_SIZE(compatible_ioctls); i++) { - result = register_ioctl32_conversion(compatible_ioctls[i], 0); - if (result == -EBUSY) { - unregister_ioctl32_conversion(compatible_ioctls[i]); - result = register_ioctl32_conversion( - compatible_ioctls[i], 0); - } - if (result) - return result; - } - return 0; -} -#else // !CONFIG_COMPAT -static inline void z90_unregister_ioctl32s(void) -{ -} - -static inline int z90_register_ioctl32s(void) +static long +z90crypt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - return 0; + switch (cmd) { + case ICAZ90STATUS: + case Z90QUIESCE: + case Z90STAT_TOTALCOUNT: + case Z90STAT_PCICACOUNT: + case Z90STAT_PCICCCOUNT: + case Z90STAT_PCIXCCCOUNT: + case Z90STAT_PCIXCCMCL2COUNT: + case Z90STAT_PCIXCCMCL3COUNT: + case Z90STAT_CEX2CCOUNT: + case Z90STAT_REQUESTQ_COUNT: + case Z90STAT_PENDINGQ_COUNT: + case Z90STAT_TOTALOPEN_COUNT: + case Z90STAT_DOMAIN_INDEX: + case Z90STAT_STATUS_MASK: + case Z90STAT_QDEPTH_MASK: + case Z90STAT_PERDEV_REQCNT: + return z90crypt_unlocked_ioctl(filp, cmd, arg); + case ICARSAMODEXPO: + return trans_modexpo32(filp, cmd, arg); + case ICARSACRT: + return trans_modexpo_crt32(filp, cmd, arg); + default: + return -ENOIOCTLCMD; + } } #endif @@ -730,14 +698,9 @@ z90crypt_init_module(void) reader_timer.expires = jiffies + (READERTIME * HZ / 1000); add_timer(&reader_timer); - if ((result = z90_register_ioctl32s())) - goto init_module_cleanup; - return 0; // success init_module_cleanup: - z90_unregister_ioctl32s(); - #ifndef Z90CRYPT_USE_HOTPLUG if ((nresult = misc_deregister(&z90crypt_misc_device))) PRINTK("misc_deregister failed with %d.\n", nresult); @@ -763,8 +726,6 @@ z90crypt_cleanup_module(void) PDEBUG("PID %d\n", PID()); - z90_unregister_ioctl32s(); - remove_proc_entry("driver/z90crypt", 0); #ifndef Z90CRYPT_USE_HOTPLUG @@ -800,7 +761,7 @@ z90crypt_cleanup_module(void) * z90crypt_release * z90crypt_read * z90crypt_write - * z90crypt_ioctl + * z90crypt_unlocked_ioctl * z90crypt_status * z90crypt_status_write * disable_card @@ -1804,9 +1765,8 @@ z90crypt_rsa(struct priv_data *private_data_p, pid_t pid, * This function is a little long, but it's really just one large switch * statement. */ -static int -z90crypt_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static long +z90crypt_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct priv_data *private_data_p = filp->private_data; unsigned char *status; -- cgit v0.10.2 From 9fc1427a01a9df3605e219c6de0c59c4639209a1 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Sun, 1 May 2005 08:59:00 -0700 Subject: [PATCH] s390: cio documentation Synchronize documentation with current interface. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt index d939717..f0be389 100644 --- a/Documentation/s390/cds.txt +++ b/Documentation/s390/cds.txt @@ -56,12 +56,16 @@ read_dev_chars() read device characteristics read_conf_data() +read_conf_data_lpm() read configuration data. ccw_device_get_ciw() get commands from extended sense data. ccw_device_start() +ccw_device_start_timeout() +ccw_device_start_key() +ccw_device_start_key_timeout() initiate an I/O request. ccw_device_resume() @@ -197,19 +201,21 @@ The read_dev_chars() function returns : operational. -read_conf_data() - Read Configuration Data +read_conf_data(), read_conf_data_lpm() - Read Configuration Data Retrieve the device dependent configuration data. Please have a look at your device dependent I/O commands for the device specific layout of the node -descriptor elements. +descriptor elements. read_conf_data_lpm() will retrieve the configuration data +for a specific path. -The function is meant to be called with an irq handler in place; that is, +The function is meant to be called with the device already enabled; that is, at earliest during set_online() processing. The function may be called enabled or disabled, but the device must not be locked -int read_conf_data(struct ccw_device, void **buffer, int *length, __u8 lpm); +int read_conf_data(struct ccw_device, void **buffer, int *length); +int read_conf_data_lpm(struct ccw_device, void **buffer, int *length, __u8 lpm); cdev - the ccw_device the data is requested for. buffer - Pointer to a buffer pointer. The read_conf_data() routine @@ -263,6 +269,25 @@ int ccw_device_start(struct ccw_device *cdev, unsigned long intparm, __u8 lpm, unsigned long flags); +int ccw_device_start_timeout(struct ccw_device *cdev, + struct ccw1 *cpa, + unsigned long intparm, + __u8 lpm, + unsigned long flags, + int expires); +int ccw_device_start_key(struct ccw_device *cdev, + struct ccw1 *cpa, + unsigned long intparm, + __u8 lpm, + __u8 key, + unsigned long flags); +int ccw_device_start_key_timeout(struct ccw_device *cdev, + struct ccw1 *cpa, + unsigned long intparm, + __u8 lpm, + __u8 key, + unsigned long flags, + int expires); cdev : ccw_device the I/O is destined for cpa : logical start address of channel program @@ -272,7 +297,12 @@ user_intparm : user specific interrupt information; will be presented particular I/O request. lpm : defines the channel path to be used for a specific I/O request. A value of 0 will make cio use the opm. +key : the storage key to use for the I/O (useful for operating on a + storage with a storage key != default key) flag : defines the action to be performed for I/O processing +expires : timeout value in jiffies. The common I/O layer will terminate + the running program after this and call the interrupt handler + with ERR_PTR(-ETIMEDOUT) as irb. Possible flag values are : @@ -327,6 +357,13 @@ current (last) I/O request. In case of a delayed status notification no special interrupt will be presented to indicate I/O completion as the I/O request was never started, even though ccw_device_start() returned with successful completion. +The irb may contain an error value, and the device driver should check for this +first: + +-ETIMEDOUT: the common I/O layer terminated the request after the specified + timeout value +-EIO: the common I/O layer terminated the request due to an error state + If the concurrent sense flag in the extended status word in the irb is set, the field irb->scsw.count describes the numer of device specific sense bytes available in the extended control word irb->scsw.ecw[0]. No device sensing by -- cgit v0.10.2 From e43379f10b42194b8a6e1de342cfb44463c0f6da Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 1 May 2005 08:59:00 -0700 Subject: [PATCH] nice and rt-prio rlimits Add a pair of rlimits for allowing non-root tasks to raise nice and rt priorities. Defaults to traditional behavior. Originally written by Chris Wright. The patch implements a simple rlimit ceiling for the RT (and nice) priorities a task can set. The rlimit defaults to 0, meaning no change in behavior by default. A value of 50 means RT priority levels 1-50 are allowed. A value of 100 means all 99 privilege levels from 1 to 99 are allowed. CAP_SYS_NICE is blanket permission. (akpm: see http://www.uwsg.iu.edu/hypermail/linux/kernel/0503.1/1921.html for tips on integrating this with PAM). Signed-off-by: Matt Mackall Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-generic/resource.h b/include/asm-generic/resource.h index b1fcda9..cfe3692 100644 --- a/include/asm-generic/resource.h +++ b/include/asm-generic/resource.h @@ -41,8 +41,11 @@ #define RLIMIT_LOCKS 10 /* maximum file locks held */ #define RLIMIT_SIGPENDING 11 /* max number of pending signals */ #define RLIMIT_MSGQUEUE 12 /* maximum bytes in POSIX mqueues */ +#define RLIMIT_NICE 13 /* max nice prio allowed to raise to + 0-39 for nice level 19 .. -20 */ +#define RLIMIT_RTPRIO 14 /* maximum realtime priority */ -#define RLIM_NLIMITS 13 +#define RLIM_NLIMITS 15 /* * SuS says limits have to be unsigned. @@ -81,6 +84,8 @@ [RLIMIT_LOCKS] = { RLIM_INFINITY, RLIM_INFINITY }, \ [RLIMIT_SIGPENDING] = { 0, 0 }, \ [RLIMIT_MSGQUEUE] = { MQ_BYTES_MAX, MQ_BYTES_MAX }, \ + [RLIMIT_NICE] = { 0, 0 }, \ + [RLIMIT_RTPRIO] = { 0, 0 }, \ } #endif /* __KERNEL__ */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 1cced97..8960f99 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -845,6 +845,7 @@ extern void sched_idle_next(void); extern void set_user_nice(task_t *p, long nice); extern int task_prio(const task_t *p); extern int task_nice(const task_t *p); +extern int can_nice(const task_t *p, const int nice); extern int task_curr(const task_t *p); extern int idle_cpu(int cpu); extern int sched_setscheduler(struct task_struct *, int, struct sched_param *); diff --git a/kernel/sched.c b/kernel/sched.c index 9bb7489..5dadcc6 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3223,6 +3223,19 @@ out_unlock: EXPORT_SYMBOL(set_user_nice); +/* + * can_nice - check if a task can reduce its nice value + * @p: task + * @nice: nice value + */ +int can_nice(const task_t *p, const int nice) +{ + /* convert nice value [19,-20] to rlimit style value [0,39] */ + int nice_rlim = 19 - nice; + return (nice_rlim <= p->signal->rlim[RLIMIT_NICE].rlim_cur || + capable(CAP_SYS_NICE)); +} + #ifdef __ARCH_WANT_SYS_NICE /* @@ -3242,12 +3255,8 @@ asmlinkage long sys_nice(int increment) * We don't have to worry. Conceptually one call occurs first * and we have a single winner. */ - if (increment < 0) { - if (!capable(CAP_SYS_NICE)) - return -EPERM; - if (increment < -40) - increment = -40; - } + if (increment < -40) + increment = -40; if (increment > 40) increment = 40; @@ -3257,6 +3266,9 @@ asmlinkage long sys_nice(int increment) if (nice > 19) nice = 19; + if (increment < 0 && !can_nice(current, nice)) + return -EPERM; + retval = security_task_setnice(current, nice); if (retval) return retval; @@ -3372,6 +3384,7 @@ recheck: return -EINVAL; if ((policy == SCHED_FIFO || policy == SCHED_RR) && + param->sched_priority > p->signal->rlim[RLIMIT_RTPRIO].rlim_cur && !capable(CAP_SYS_NICE)) return -EPERM; if ((current->euid != p->euid) && (current->euid != p->uid) && diff --git a/kernel/sys.c b/kernel/sys.c index df2ddcc..7f43d6e 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -227,7 +227,7 @@ static int set_one_prio(struct task_struct *p, int niceval, int error) error = -EPERM; goto out; } - if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) { + if (niceval < task_nice(p) && !can_nice(p, niceval)) { error = -EACCES; goto out; } -- cgit v0.10.2 From c8538a7aa5527d02c7191ac5da124efadf6a2827 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 1 May 2005 08:59:01 -0700 Subject: [PATCH] remove all kernel BUGs This patch eliminates all kernel BUGs, trims about 35k off the typical kernel, and makes the system slightly faster. Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-alpha/bug.h b/include/asm-alpha/bug.h index ae1e0a5..39a3e2a 100644 --- a/include/asm-alpha/bug.h +++ b/include/asm-alpha/bug.h @@ -1,6 +1,7 @@ #ifndef _ALPHA_BUG_H #define _ALPHA_BUG_H +#ifdef CONFIG_BUG #include /* ??? Would be nice to use .gprel32 here, but we can't be sure that the @@ -10,6 +11,8 @@ : : "i" (PAL_bugchk), "i"(__LINE__), "i"(__FILE__)) #define HAVE_ARCH_BUG +#endif + #include #endif diff --git a/include/asm-arm/bug.h b/include/asm-arm/bug.h index 5e91b90..24d1167 100644 --- a/include/asm-arm/bug.h +++ b/include/asm-arm/bug.h @@ -3,6 +3,7 @@ #include +#ifdef CONFIG_BUG #ifdef CONFIG_DEBUG_BUGVERBOSE extern volatile void __bug(const char *file, int line, void *data); @@ -17,6 +18,8 @@ extern volatile void __bug(const char *file, int line, void *data); #endif #define HAVE_ARCH_BUG +#endif + #include #endif diff --git a/include/asm-arm26/bug.h b/include/asm-arm26/bug.h index 920b705..7177c73 100644 --- a/include/asm-arm26/bug.h +++ b/include/asm-arm26/bug.h @@ -3,6 +3,7 @@ #include +#ifdef CONFIG_BUG #ifdef CONFIG_DEBUG_BUGVERBOSE extern volatile void __bug(const char *file, int line, void *data); /* give file/line information */ @@ -12,6 +13,8 @@ extern volatile void __bug(const char *file, int line, void *data); #endif #define HAVE_ARCH_BUG +#endif + #include #endif diff --git a/include/asm-frv/bug.h b/include/asm-frv/bug.h index 011860b..074c0d5 100644 --- a/include/asm-frv/bug.h +++ b/include/asm-frv/bug.h @@ -13,6 +13,7 @@ #include +#ifdef CONFIG_BUG /* * Tell the user there is some problem. */ @@ -45,6 +46,7 @@ do { \ #define HAVE_ARCH_KGDB_BAD_PAGE #define kgdb_bad_page(page) do { kgdb_raise(SIGABRT); } while(0) #endif +#endif #include diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h index e5913c3..6e5aaaa 100644 --- a/include/asm-generic/bug.h +++ b/include/asm-generic/bug.h @@ -4,6 +4,7 @@ #include #include +#ifdef CONFIG_BUG #ifndef HAVE_ARCH_BUG #define BUG() do { \ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ @@ -31,4 +32,22 @@ } while (0) #endif +#else /* !CONFIG_BUG */ +#ifndef HAVE_ARCH_BUG +#define BUG() +#endif + +#ifndef HAVE_ARCH_PAGE_BUG +#define PAGE_BUG(page) do { if (page) ; } while (0) +#endif + +#ifndef HAVE_ARCH_BUG_ON +#define BUG_ON(condition) do { if (condition) ; } while(0) +#endif + +#ifndef HAVE_ARCH_WARN_ON +#define WARN_ON(condition) do { if (condition) ; } while(0) +#endif +#endif + #endif diff --git a/include/asm-i386/bug.h b/include/asm-i386/bug.h index 706eb51..8f79de1 100644 --- a/include/asm-i386/bug.h +++ b/include/asm-i386/bug.h @@ -9,6 +9,8 @@ * undefined" opcode for parsing in the trap handler. */ +#ifdef CONFIG_BUG +#define HAVE_ARCH_BUG #ifdef CONFIG_DEBUG_BUGVERBOSE #define BUG() \ __asm__ __volatile__( "ud2\n" \ @@ -18,8 +20,7 @@ #else #define BUG() __asm__ __volatile__("ud2\n") #endif +#endif -#define HAVE_ARCH_BUG #include - #endif diff --git a/include/asm-ia64/bug.h b/include/asm-ia64/bug.h index 2c0cd51..3aa0a0a 100644 --- a/include/asm-ia64/bug.h +++ b/include/asm-ia64/bug.h @@ -1,6 +1,7 @@ #ifndef _ASM_IA64_BUG_H #define _ASM_IA64_BUG_H +#ifdef CONFIG_BUG #if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) # define ia64_abort() __builtin_trap() #else @@ -8,8 +9,10 @@ #endif #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0) -/* should this BUG should be made generic? */ +/* should this BUG be made generic? */ #define HAVE_ARCH_BUG +#endif + #include #endif diff --git a/include/asm-m68k/bug.h b/include/asm-m68k/bug.h index 3e1d226..072ce27 100644 --- a/include/asm-m68k/bug.h +++ b/include/asm-m68k/bug.h @@ -3,6 +3,7 @@ #include +#ifdef CONFIG_BUG #ifdef CONFIG_DEBUG_BUGVERBOSE #ifndef CONFIG_SUN3 #define BUG() do { \ @@ -22,6 +23,8 @@ #endif #define HAVE_ARCH_BUG +#endif + #include #endif diff --git a/include/asm-mips/bug.h b/include/asm-mips/bug.h index eb94bb9..3f594b4 100644 --- a/include/asm-mips/bug.h +++ b/include/asm-mips/bug.h @@ -3,12 +3,14 @@ #include +#ifdef CONFIG_BUG +#define HAVE_ARCH_BUG #define BUG() \ do { \ __asm__ __volatile__("break %0" : : "i" (BRK_BUG)); \ } while (0) +#endif -#define HAVE_ARCH_BUG #include #endif diff --git a/include/asm-parisc/bug.h b/include/asm-parisc/bug.h index e72f6e2..695588d 100644 --- a/include/asm-parisc/bug.h +++ b/include/asm-parisc/bug.h @@ -1,12 +1,14 @@ #ifndef _PARISC_BUG_H #define _PARISC_BUG_H +#ifdef CONFIG_BUG #define HAVE_ARCH_BUG #define BUG() do { \ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ dump_stack(); \ panic("BUG!"); \ } while (0) +#endif #include #endif diff --git a/include/asm-ppc/bug.h b/include/asm-ppc/bug.h index e99c6cb..8b34fd6 100644 --- a/include/asm-ppc/bug.h +++ b/include/asm-ppc/bug.h @@ -14,6 +14,7 @@ struct bug_entry { */ #define BUG_WARNING_TRAP 0x1000000 +#ifdef CONFIG_BUG #define BUG() do { \ __asm__ __volatile__( \ "1: twi 31,0,0\n" \ @@ -50,6 +51,8 @@ struct bug_entry { #define HAVE_ARCH_BUG #define HAVE_ARCH_BUG_ON #define HAVE_ARCH_WARN_ON +#endif + #include #endif diff --git a/include/asm-ppc64/bug.h b/include/asm-ppc64/bug.h index db31dd2..169868f 100644 --- a/include/asm-ppc64/bug.h +++ b/include/asm-ppc64/bug.h @@ -26,6 +26,8 @@ struct bug_entry *find_bug(unsigned long bugaddr); */ #define BUG_WARNING_TRAP 0x1000000 +#ifdef CONFIG_BUG + #define BUG() do { \ __asm__ __volatile__( \ "1: twi 31,0,0\n" \ @@ -55,11 +57,12 @@ struct bug_entry *find_bug(unsigned long bugaddr); "i" (__FILE__), "i" (__FUNCTION__)); \ } while (0) -#endif - #define HAVE_ARCH_BUG #define HAVE_ARCH_BUG_ON #define HAVE_ARCH_WARN_ON +#endif +#endif + #include #endif diff --git a/include/asm-s390/bug.h b/include/asm-s390/bug.h index 2b8d6d4..a2e7430 100644 --- a/include/asm-s390/bug.h +++ b/include/asm-s390/bug.h @@ -3,12 +3,15 @@ #include +#ifdef CONFIG_BUG #define BUG() do { \ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ __asm__ __volatile__(".long 0"); \ } while (0) #define HAVE_ARCH_BUG +#endif + #include #endif diff --git a/include/asm-sh/bug.h b/include/asm-sh/bug.h index 7017221..70508a3 100644 --- a/include/asm-sh/bug.h +++ b/include/asm-sh/bug.h @@ -3,6 +3,7 @@ #include +#ifdef CONFIG_BUG /* * Tell the user there is some problem. */ @@ -12,6 +13,8 @@ } while (0) #define HAVE_ARCH_BUG +#endif + #include #endif diff --git a/include/asm-sparc/bug.h b/include/asm-sparc/bug.h index 0d30a67..0415120 100644 --- a/include/asm-sparc/bug.h +++ b/include/asm-sparc/bug.h @@ -1,6 +1,7 @@ #ifndef _SPARC_BUG_H #define _SPARC_BUG_H +#ifdef CONFIG_BUG /* Only use the inline asm until a gcc release that can handle __builtin_trap * -rob 2003-06-25 * @@ -26,6 +27,8 @@ extern void do_BUG(const char *file, int line); #endif #define HAVE_ARCH_BUG +#endif + #include #endif diff --git a/include/asm-sparc64/bug.h b/include/asm-sparc64/bug.h index 25c5b1d..516bb27 100644 --- a/include/asm-sparc64/bug.h +++ b/include/asm-sparc64/bug.h @@ -1,6 +1,7 @@ #ifndef _SPARC64_BUG_H #define _SPARC64_BUG_H +#ifdef CONFIG_BUG #include #ifdef CONFIG_DEBUG_BUGVERBOSE @@ -14,6 +15,8 @@ extern void do_BUG(const char *file, int line); #endif #define HAVE_ARCH_BUG +#endif + #include #endif diff --git a/include/asm-v850/bug.h b/include/asm-v850/bug.h index c778916..b0ed2d3 100644 --- a/include/asm-v850/bug.h +++ b/include/asm-v850/bug.h @@ -14,9 +14,12 @@ #ifndef __V850_BUG_H__ #define __V850_BUG_H__ +#ifdef CONFIG_BUG extern void __bug (void) __attribute__ ((noreturn)); #define BUG() __bug() #define HAVE_ARCH_BUG +#endif + #include #endif /* __V850_BUG_H__ */ diff --git a/include/asm-x86_64/bug.h b/include/asm-x86_64/bug.h index 19aed6e..bdbf66e 100644 --- a/include/asm-x86_64/bug.h +++ b/include/asm-x86_64/bug.h @@ -15,11 +15,13 @@ struct bug_frame { unsigned short line; } __attribute__((packed)); +#ifdef CONFIG_BUG #define HAVE_ARCH_BUG #define BUG() \ asm volatile("ud2 ; .quad %c1 ; .short %c0" :: \ "i"(__LINE__), "i" (__stringify(__FILE__))) void out_of_line_bug(void); -#include +#endif +#include #endif diff --git a/init/Kconfig b/init/Kconfig index abe2682..42dca39 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -275,6 +275,16 @@ config KALLSYMS_EXTRA_PASS reported. KALLSYMS_EXTRA_PASS is only a temporary workaround while you wait for kallsyms to be fixed. +config BUG + bool "BUG() support" if EMBEDDED + default y + help + Disabling this option eliminates support for BUG and WARN, reducing + the size of your kernel image and potentially quietly ignoring + numerous fatal conditions. You should only consider disabling this + option for embedded systems with no facilities for reporting errors. + Just say Y. + config BASE_FULL default y bool "Enable full-sized data structures for core" if EMBEDDED diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 426a0cf..ac23847 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -108,6 +108,7 @@ config DEBUG_HIGHMEM config DEBUG_BUGVERBOSE bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED + depends on BUG depends on ARM || ARM26 || M32R || M68K || SPARC32 || SPARC64 || (X86 && !X86_64) || FRV default !EMBEDDED help -- cgit v0.10.2 From cd7619d6bf36564cf54ff7218ef54e558a741913 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 1 May 2005 08:59:01 -0700 Subject: [PATCH] Exterminate PAGE_BUG Remove PAGE_BUG - repalce it with BUG and BUG_ON. Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/arm26/mm/small_page.c b/arch/arm26/mm/small_page.c index 77be86c..3044710 100644 --- a/arch/arm26/mm/small_page.c +++ b/arch/arm26/mm/small_page.c @@ -92,8 +92,7 @@ static unsigned long __get_small_page(int priority, struct order *order) page = list_entry(order->queue.next, struct page, lru); again: #ifdef PEDANTIC - if (USED_MAP(page) & ~order->all_used) - PAGE_BUG(page); + BUG_ON(USED_MAP(page) & ~order->all_used); #endif offset = ffz(USED_MAP(page)); SET_USED(page, offset); @@ -141,8 +140,7 @@ static void __free_small_page(unsigned long spage, struct order *order) goto non_small; #ifdef PEDANTIC - if (USED_MAP(page) & ~order->all_used) - PAGE_BUG(page); + BUG_ON(USED_MAP(page) & ~order->all_used); #endif spage = spage >> order->shift; diff --git a/fs/afs/file.c b/fs/afs/file.c index 6b6bb7c..23c1251 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -131,8 +131,7 @@ static int afs_file_readpage(struct file *file, struct page *page) vnode = AFS_FS_I(inode); - if (!PageLocked(page)) - PAGE_BUG(page); + BUG_ON(!PageLocked(page)); ret = -ESTALE; if (vnode->flags & AFS_VNODE_DELETED) diff --git a/fs/buffer.c b/fs/buffer.c index 188365c..792cbac 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2078,8 +2078,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block) int nr, i; int fully_mapped = 1; - if (!PageLocked(page)) - PAGE_BUG(page); + BUG_ON(!PageLocked(page)); blocksize = 1 << inode->i_blkbits; if (!page_has_buffers(page)) create_empty_buffers(page, blocksize, 0); diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 0c607c1..771a554 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -79,8 +79,7 @@ static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT)); - if (!PageLocked(pg)) - PAGE_BUG(pg); + BUG_ON(!PageLocked(pg)); pg_buf = kmap(pg); /* FIXME: Can kmap fail? */ diff --git a/fs/udf/file.c b/fs/udf/file.c index 2faa417..bb40d63 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -49,8 +49,7 @@ static int udf_adinicb_readpage(struct file *file, struct page * page) struct inode *inode = page->mapping->host; char *kaddr; - if (!PageLocked(page)) - PAGE_BUG(page); + BUG_ON(!PageLocked(page)); kaddr = kmap(page); memset(kaddr, 0, PAGE_CACHE_SIZE); @@ -67,8 +66,7 @@ static int udf_adinicb_writepage(struct page *page, struct writeback_control *wb struct inode *inode = page->mapping->host; char *kaddr; - if (!PageLocked(page)) - PAGE_BUG(page); + BUG_ON(!PageLocked(page)); kaddr = kmap(page); memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), kaddr, inode->i_size); diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 0506e11..3d68de3 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -167,8 +167,8 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err) } page = grab_cache_page(inode->i_mapping, 0); - if (!PageLocked(page)) - PAGE_BUG(page); + BUG_ON(!PageLocked(page)); + if (!PageUptodate(page)) { kaddr = kmap(page); diff --git a/include/asm-cris/page.h b/include/asm-cris/page.h index ddd8915..c767da1 100644 --- a/include/asm-cris/page.h +++ b/include/asm-cris/page.h @@ -77,10 +77,6 @@ typedef struct { unsigned long pgprot; } pgprot_t; printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ } while (0) -#define PAGE_BUG(page) do { \ - BUG(); \ -} while (0) - /* Pure 2^n version of get_order */ static inline int get_order(unsigned long size) { diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h index 6e5aaaa..400c2b4 100644 --- a/include/asm-generic/bug.h +++ b/include/asm-generic/bug.h @@ -12,13 +12,6 @@ } while (0) #endif -#ifndef HAVE_ARCH_PAGE_BUG -#define PAGE_BUG(page) do { \ - printk("page BUG for page at %p\n", page); \ - BUG(); \ -} while (0) -#endif - #ifndef HAVE_ARCH_BUG_ON #define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) #endif @@ -37,10 +30,6 @@ #define BUG() #endif -#ifndef HAVE_ARCH_PAGE_BUG -#define PAGE_BUG(page) do { if (page) ; } while (0) -#endif - #ifndef HAVE_ARCH_BUG_ON #define BUG_ON(condition) do { if (condition) ; } while(0) #endif diff --git a/include/asm-sh64/bug.h b/include/asm-sh64/bug.h index 3acd54d..5d659ec 100644 --- a/include/asm-sh64/bug.h +++ b/include/asm-sh64/bug.h @@ -17,10 +17,6 @@ BUG(); \ } while(0) -#define PAGE_BUG(page) do { \ - BUG(); \ -} while (0) - #define WARN_ON(condition) do { \ if (unlikely((condition)!=0)) { \ printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ diff --git a/mm/filemap.c b/mm/filemap.c index ee79b5d..c085af2 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -123,8 +123,7 @@ void remove_from_page_cache(struct page *page) { struct address_space *mapping = page->mapping; - if (unlikely(!PageLocked(page))) - PAGE_BUG(page); + BUG_ON(!PageLocked(page)); write_lock_irq(&mapping->tree_lock); __remove_from_page_cache(page); -- cgit v0.10.2 From d59745ce3e7aa13856bca16d3bcbb95041775ff6 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 1 May 2005 08:59:02 -0700 Subject: [PATCH] clean up kernel messages Arrange for all kernel printks to be no-ops. Only available if CONFIG_EMBEDDED. This patch saves about 375k on my laptop config and nearly 100k on minimal configs. Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index d273fd7..e966fc8 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -380,6 +380,7 @@ rp_sidt: ALIGN ignore_int: cld +#ifdef CONFIG_PRINTK pushl %eax pushl %ecx pushl %edx @@ -400,6 +401,7 @@ ignore_int: popl %edx popl %ecx popl %eax +#endif iret /* diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 7c1cba4..e25b970 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -115,10 +115,19 @@ extern int __kernel_text_address(unsigned long addr); extern int kernel_text_address(unsigned long addr); extern int session_of_pgrp(int pgrp); +#ifdef CONFIG_PRINTK asmlinkage int vprintk(const char *fmt, va_list args) __attribute__ ((format (printf, 1, 0))); asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); +#else +static inline int vprintk(const char *s, va_list args) + __attribute__ ((format (printf, 1, 0))); +static inline int vprintk(const char *s, va_list args) { return 0; } +static inline int printk(const char *s, ...) + __attribute__ ((format (printf, 1, 2))); +static inline int printk(const char *s, ...) { return 0; } +#endif unsigned long int_sqrt(unsigned long); diff --git a/init/Kconfig b/init/Kconfig index 42dca39..40d286d 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -275,6 +275,17 @@ config KALLSYMS_EXTRA_PASS reported. KALLSYMS_EXTRA_PASS is only a temporary workaround while you wait for kallsyms to be fixed. + +config PRINTK + default y + bool "Enable support for printk" if EMBEDDED + help + This option enables normal printk support. Removing it + eliminates most of the message strings from the kernel image + and makes the kernel more or less silent. As this makes it + very difficult to diagnose system problems, saying N here is + strongly discouraged. + config BUG bool "BUG() support" if EMBEDDED default y diff --git a/kernel/printk.c b/kernel/printk.c index 1498689..290a07c 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -85,10 +85,6 @@ static int console_locked; */ static DEFINE_SPINLOCK(logbuf_lock); -static char __log_buf[__LOG_BUF_LEN]; -static char *log_buf = __log_buf; -static int log_buf_len = __LOG_BUF_LEN; - #define LOG_BUF_MASK (log_buf_len-1) #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) @@ -99,7 +95,6 @@ static int log_buf_len = __LOG_BUF_LEN; static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */ static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */ static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */ -static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ /* * Array of consoles built from command line options (console=) @@ -120,6 +115,13 @@ static int preferred_console = -1; /* Flag: console code may call schedule() */ static int console_may_schedule; +#ifdef CONFIG_PRINTK + +static char __log_buf[__LOG_BUF_LEN]; +static char *log_buf = __log_buf; +static int log_buf_len = __LOG_BUF_LEN; +static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ + /* * Setup a list of consoles. Called from init/main.c */ @@ -535,6 +537,7 @@ __setup("time", printk_time_setup); * then changes console_loglevel may break. This is because console_loglevel * is inspected when the actual printing occurs. */ + asmlinkage int printk(const char *fmt, ...) { va_list args; @@ -655,6 +658,18 @@ out: EXPORT_SYMBOL(printk); EXPORT_SYMBOL(vprintk); +#else + +asmlinkage long sys_syslog(int type, char __user * buf, int len) +{ + return 0; +} + +int do_syslog(int type, char __user * buf, int len) { return 0; } +static void call_console_drivers(unsigned long start, unsigned long end) {} + +#endif + /** * acquire_console_sem - lock the console system for exclusive use. * @@ -931,7 +946,7 @@ int unregister_console(struct console * console) return res; } EXPORT_SYMBOL(unregister_console); - + /** * tty_write_message - write a message to a certain tty, not just the console. * -- cgit v0.10.2 From 7f261b5f0dccd53ed3a9a95b55c36e24a698a92a Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Sun, 1 May 2005 08:59:02 -0700 Subject: [PATCH] move SA_xxx defines to linux/signal.h The attached patch moves the IRQ-related SA_xxx flags (namely, SA_PROBE, SA_SAMPLE_RANDOM and SA_SHIRQ) from all the arch-specific headers to linux/signal.h. This looks like a left-over after the irq-handling code was consolidated. The code was moved to kernel/irq/*, but the flags are still left per-arch. Right now, adding a new IRQ flag to the arch-specific header, like this patch does: http://cvs.sourceforge.net/viewcvs.py/*checkout*/alsa/alsa-driver/utils/patches/pcsp-kernel-2.6.10-03.diff?rev=1.1 no longer works, it breaks the compilation for all other arches, unless you add that flag to all the other arch-specific headers too. So I think such a clean-up makes sense. Signed-off-by: Stas Sergeev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-alpha/signal.h b/include/asm-alpha/signal.h index 25f98bc..4e0842b 100644 --- a/include/asm-alpha/signal.h +++ b/include/asm-alpha/signal.h @@ -109,20 +109,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 4096 #define SIGSTKSZ 16384 - -#ifdef __KERNEL__ -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x40000000 -#endif - #define SIG_BLOCK 1 /* for blocking signals */ #define SIG_UNBLOCK 2 /* for unblocking signals */ #define SIG_SETMASK 3 /* for setting the signal mask */ diff --git a/include/asm-arm/signal.h b/include/asm-arm/signal.h index b033e5f..b860dc3 100644 --- a/include/asm-arm/signal.h +++ b/include/asm-arm/signal.h @@ -114,18 +114,7 @@ typedef unsigned long sigset_t; #define SIGSTKSZ 8192 #ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE 0x80000000 -#define SA_SAMPLE_RANDOM 0x10000000 #define SA_IRQNOMASK 0x08000000 -#define SA_SHIRQ 0x04000000 #endif #define SIG_BLOCK 0 /* for blocking signals */ diff --git a/include/asm-arm26/signal.h b/include/asm-arm26/signal.h index 6f62e51..a1aacef 100644 --- a/include/asm-arm26/signal.h +++ b/include/asm-arm26/signal.h @@ -114,18 +114,7 @@ typedef unsigned long sigset_t; #define SIGSTKSZ 8192 #ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE 0x80000000 -#define SA_SAMPLE_RANDOM 0x10000000 #define SA_IRQNOMASK 0x08000000 -#define SA_SHIRQ 0x04000000 #endif #define SIG_BLOCK 0 /* for blocking signals */ diff --git a/include/asm-cris/signal.h b/include/asm-cris/signal.h index 3f187ec..2330769 100644 --- a/include/asm-cris/signal.h +++ b/include/asm-cris/signal.h @@ -108,20 +108,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-frv/signal.h b/include/asm-frv/signal.h index f18952f..c930bb1 100644 --- a/include/asm-frv/signal.h +++ b/include/asm-frv/signal.h @@ -107,20 +107,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-h8300/signal.h b/include/asm-h8300/signal.h index 3a08544..ac3e01b 100644 --- a/include/asm-h8300/signal.h +++ b/include/asm-h8300/signal.h @@ -107,19 +107,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-i386/signal.h b/include/asm-i386/signal.h index 7ef343b..0f082bd 100644 --- a/include/asm-i386/signal.h +++ b/include/asm-i386/signal.h @@ -110,20 +110,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-ia64/signal.h b/include/asm-ia64/signal.h index 660a759..85a577a 100644 --- a/include/asm-ia64/signal.h +++ b/include/asm-ia64/signal.h @@ -114,16 +114,6 @@ #define _NSIG_BPW 64 #define _NSIG_WORDS (_NSIG / _NSIG_BPW) -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 #define SA_PERCPU_IRQ 0x02000000 #endif /* __KERNEL__ */ diff --git a/include/asm-m32r/signal.h b/include/asm-m32r/signal.h index ce46eae..6e55fd4 100644 --- a/include/asm-m32r/signal.h +++ b/include/asm-m32r/signal.h @@ -114,20 +114,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-m68k/signal.h b/include/asm-m68k/signal.h index 6681bb6..1d016e9 100644 --- a/include/asm-m68k/signal.h +++ b/include/asm-m68k/signal.h @@ -105,19 +105,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-m68knommu/signal.h b/include/asm-m68knommu/signal.h index 486cbb0..37c9c8a 100644 --- a/include/asm-m68knommu/signal.h +++ b/include/asm-m68knommu/signal.h @@ -105,19 +105,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-mips/signal.h b/include/asm-mips/signal.h index 994987d..d813567 100644 --- a/include/asm-mips/signal.h +++ b/include/asm-mips/signal.h @@ -98,21 +98,6 @@ typedef unsigned long old_sigset_t; /* at least 32 bits */ #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ flag is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x02000000 - -#endif /* __KERNEL__ */ - #define SIG_BLOCK 1 /* for blocking signals */ #define SIG_UNBLOCK 2 /* for unblocking signals */ #define SIG_SETMASK 3 /* for setting the signal mask */ diff --git a/include/asm-parisc/signal.h b/include/asm-parisc/signal.h index 358f577..25cb23e 100644 --- a/include/asm-parisc/signal.h +++ b/include/asm-parisc/signal.h @@ -89,17 +89,6 @@ #define _NSIG_BPW BITS_PER_LONG #define _NSIG_WORDS (_NSIG / _NSIG_BPW) -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 - #endif /* __KERNEL__ */ #define SIG_BLOCK 0 /* for blocking signals */ diff --git a/include/asm-ppc/signal.h b/include/asm-ppc/signal.h index 8cc8b88..d890dab 100644 --- a/include/asm-ppc/signal.h +++ b/include/asm-ppc/signal.h @@ -99,19 +99,6 @@ typedef struct { #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif /* __KERNEL__ */ #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ diff --git a/include/asm-ppc64/signal.h b/include/asm-ppc64/signal.h index fe5401a..a2d7bbb 100644 --- a/include/asm-ppc64/signal.h +++ b/include/asm-ppc64/signal.h @@ -96,19 +96,6 @@ typedef struct { #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ diff --git a/include/asm-s390/signal.h b/include/asm-s390/signal.h index f273cdc..bfed83a8 100644 --- a/include/asm-s390/signal.h +++ b/include/asm-s390/signal.h @@ -117,20 +117,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-sh/signal.h b/include/asm-sh/signal.h index 0a7ff71..29f1ac1 100644 --- a/include/asm-sh/signal.h +++ b/include/asm-sh/signal.h @@ -108,20 +108,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-sh64/signal.h b/include/asm-sh64/signal.h index 77957e9..864c94e 100644 --- a/include/asm-sh64/signal.h +++ b/include/asm-sh64/signal.h @@ -107,20 +107,6 @@ typedef struct { #define MINSIGSTKSZ 2048 #define SIGSTKSZ THREAD_SIZE -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-sparc/signal.h b/include/asm-sparc/signal.h index d8211cb..f792e10 100644 --- a/include/asm-sparc/signal.h +++ b/include/asm-sparc/signal.h @@ -143,7 +143,6 @@ struct sigstack { #define SA_ONESHOT _SV_RESET #define SA_INTERRUPT 0x10u #define SA_NOMASK 0x20u -#define SA_SHIRQ 0x40u #define SA_NOCLDWAIT 0x100u #define SA_SIGINFO 0x200u @@ -162,11 +161,6 @@ struct sigstack { #ifdef __KERNEL__ /* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * * DJHR * SA_STATIC_ALLOC is used for the SPARC system to indicate that this * interrupt handler's irq structure should be statically allocated @@ -177,8 +171,6 @@ struct sigstack { * statically allocated data.. which is NOT GOOD. * */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART #define SA_STATIC_ALLOC 0x80 #endif diff --git a/include/asm-sparc64/signal.h b/include/asm-sparc64/signal.h index 6428e36..466d021 100644 --- a/include/asm-sparc64/signal.h +++ b/include/asm-sparc64/signal.h @@ -145,7 +145,6 @@ struct sigstack { #define SA_ONESHOT _SV_RESET #define SA_INTERRUPT 0x10u #define SA_NOMASK 0x20u -#define SA_SHIRQ 0x40u #define SA_NOCLDWAIT 0x100u #define SA_SIGINFO 0x200u @@ -165,11 +164,6 @@ struct sigstack { #ifdef __KERNEL__ /* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * * DJHR * SA_STATIC_ALLOC is used for the SPARC system to indicate that this * interrupt handler's irq structure should be statically allocated @@ -180,8 +174,6 @@ struct sigstack { * statically allocated data.. which is NOT GOOD. * */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART #define SA_STATIC_ALLOC 0x80 #endif diff --git a/include/asm-v850/signal.h b/include/asm-v850/signal.h index 407db87..ec3566c 100644 --- a/include/asm-v850/signal.h +++ b/include/asm-v850/signal.h @@ -110,21 +110,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 - -#ifdef __KERNEL__ -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif /* __KERNEL__ */ - - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/asm-x86_64/signal.h b/include/asm-x86_64/signal.h index 643a20d..4987ad8 100644 --- a/include/asm-x86_64/signal.h +++ b/include/asm-x86_64/signal.h @@ -116,20 +116,6 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#ifdef __KERNEL__ - -/* - * These values of sa_flags are used only by the kernel as part of the - * irq handling routines. - * - * SA_INTERRUPT is also used by the irq handling routines. - * SA_SHIRQ is for shared interrupt support on PCI and EISA. - */ -#define SA_PROBE SA_ONESHOT -#define SA_SAMPLE_RANDOM SA_RESTART -#define SA_SHIRQ 0x04000000 -#endif - #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ diff --git a/include/linux/signal.h b/include/linux/signal.h index 99c97ad..78bfb26 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -9,6 +9,17 @@ #ifdef __KERNEL__ /* + * These values of sa_flags are used only by the kernel as part of the + * irq handling routines. + * + * SA_INTERRUPT is also used by the irq handling routines. + * SA_SHIRQ is for shared interrupt support on PCI and EISA. + */ +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 + +/* * Real Time signals may be queued. */ -- cgit v0.10.2 From bcf88e1163623e8e8ef2ba7feface9c826a890c9 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sun, 1 May 2005 08:59:03 -0700 Subject: [PATCH] procfs: Fix hardlink counts The pid directories in /proc/ currently return the wrong hardlink count - 3, when there are actually 4 : ".", "..", "fd", and "task". This is easy to notice using find(1): cd /proc/ find In the output, you'll see a message similar to: find: WARNING: Hard link count is wrong for .: this may be a bug in your filesystem driver. Automatically turning on find's -noleaf option. Earlier results may have failed to include directories that should have been searched. http://bugs.gentoo.org/show_bug.cgi?id=86031 I also noticed that CONFIG_SECURITY can add a 5th: attr, and performed a similar fix on the task directories too. Signed-off-by: Daniel Drake Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/proc/base.c b/fs/proc/base.c index 39fd336..4718173 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1800,8 +1800,12 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; inode->i_op = &proc_tgid_base_inode_operations; inode->i_fop = &proc_tgid_base_operations; - inode->i_nlink = 3; inode->i_flags|=S_IMMUTABLE; +#ifdef CONFIG_SECURITY + inode->i_nlink = 5; +#else + inode->i_nlink = 4; +#endif dentry->d_op = &pid_base_dentry_operations; @@ -1855,8 +1859,12 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; inode->i_op = &proc_tid_base_inode_operations; inode->i_fop = &proc_tid_base_operations; - inode->i_nlink = 3; inode->i_flags|=S_IMMUTABLE; +#ifdef CONFIG_SECURITY + inode->i_nlink = 4; +#else + inode->i_nlink = 3; +#endif dentry->d_op = &pid_base_dentry_operations; -- cgit v0.10.2 From f246315e1ab96c40978777d1e159820ecca45aa8 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sun, 1 May 2005 08:59:03 -0700 Subject: [PATCH] procfs: Fix hardlink counts for /proc//task The current logic assumes that a /proc//task directory should have a hardlink count of 3, probably counting ".", "..", and a directory for a single child task. It's fairly obvious that this doesn't work out correctly when a PID has more than one child task, which is quite often the case. Signed-off-by: Daniel Drake Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/proc/base.c b/fs/proc/base.c index 4718173..2eac86d 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1419,6 +1419,8 @@ static struct file_operations proc_tgid_attr_operations; static struct inode_operations proc_tgid_attr_inode_operations; #endif +static int get_tid_list(int index, unsigned int *tids, struct inode *dir); + /* SMP-safe */ static struct dentry *proc_pident_lookup(struct inode *dir, struct dentry *dentry, @@ -1458,7 +1460,7 @@ static struct dentry *proc_pident_lookup(struct inode *dir, */ switch(p->type) { case PROC_TGID_TASK: - inode->i_nlink = 3; + inode->i_nlink = 2 + get_tid_list(2, NULL, dir); inode->i_op = &proc_task_inode_operations; inode->i_fop = &proc_task_operations; break; @@ -1943,7 +1945,8 @@ static int get_tid_list(int index, unsigned int *tids, struct inode *dir) if (--index >= 0) continue; - tids[nr_tids] = tid; + if (tids != NULL) + tids[nr_tids] = tid; nr_tids++; if (nr_tids >= PROC_MAXPIDS) break; @@ -2043,6 +2046,7 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi } nr_tids = get_tid_list(pos, tid_array, inode); + inode->i_nlink = pos + nr_tids; for (i = 0; i < nr_tids; i++) { unsigned long j = PROC_NUMBUF; -- cgit v0.10.2 From 66cf8f1443301a1d5bc9c21709e4264e6919a3e1 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 1 May 2005 08:59:03 -0700 Subject: [PATCH] kernel/rcupdate.c: make the exports EXPORT_SYMBOL_GPL The gpl exports need to be put back. Moving them to GPL -- but in a measured manner, as I proposed on this list some months ago -- is fine. Changing these particular exports precipitously is most definitely -not- fine. Here is my earlier proposal: http://marc.theaimsgroup.com/?l=linux-kernel&m=110520930301813&w=2 See below for a patch that puts the exports back, along with an updated version of my earlier patch that starts the process of moving them to GPL. I will also be following this message with RFC patches that introduce two (EXPORT_SYMBOL_GPL) interfaces to replace synchronize_kernel(), which then becomes deprecated. Signed-off-by: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 56627c1..d3c52dd 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -48,3 +48,18 @@ When: April 2005 Why: Replaced by ->compat_ioctl in file_operations and other method vecors. Who: Andi Kleen , Christoph Hellwig + +--------------------------- + +What: RCU API moves to EXPORT_SYMBOL_GPL +When: April 2006 +Files: include/linux/rcupdate.h, kernel/rcupdate.c +Why: Outside of Linux, the only implementations of anything even + vaguely resembling RCU that I am aware of are in DYNIX/ptx, + VM/XA, Tornado, and K42. I do not expect anyone to port binary + drivers or kernel modules from any of these, since the first two + are owned by IBM and the last two are open-source research OSes. + So these will move to GPL after a grace period to allow + people, who might be using implementations that I am not aware + of, to adjust to this upcoming change. +Who: Paul E. McKenney diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index d00eded..ad49772 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -465,6 +465,6 @@ void synchronize_kernel(void) } module_param(maxbatch, int, 0); -EXPORT_SYMBOL_GPL(call_rcu); -EXPORT_SYMBOL_GPL(call_rcu_bh); -EXPORT_SYMBOL_GPL(synchronize_kernel); +EXPORT_SYMBOL(call_rcu); /* WARNING: GPL-only in April 2006. */ +EXPORT_SYMBOL(call_rcu_bh); /* WARNING: GPL-only in April 2006. */ +EXPORT_SYMBOL(synchronize_kernel); /* WARNING: GPL-only in April 2006. */ -- cgit v0.10.2 From 512345be2549308b8ae8e85a3ff7f6d56a38e5f6 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 1 May 2005 08:59:03 -0700 Subject: [PATCH] Add deprecated_for_modules Add a deprecated_for_modules macro that allows symbols to be deprecated only when used by modules, as suggested by Andrew Morton some months back. Signed-off-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 487725c..d737821 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -90,6 +90,12 @@ extern void __chk_io_ptr(void __iomem *); # define __deprecated /* unimplemented */ #endif +#ifdef MODULE +#define __deprecated_for_modules __deprecated +#else +#define __deprecated_for_modules +#endif + #ifndef __must_check #define __must_check #endif -- cgit v0.10.2 From 9b06e818985d139fd9e82c28297f7744e1b484e1 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 1 May 2005 08:59:04 -0700 Subject: [PATCH] Deprecate synchronize_kernel, GPL replacement The synchronize_kernel() primitive is used for quite a few different purposes: waiting for RCU readers, waiting for NMIs, waiting for interrupts, and so on. This makes RCU code harder to read, since synchronize_kernel() might or might not have matching rcu_read_lock()s. This patch creates a new synchronize_rcu() that is to be used for RCU readers and a new synchronize_sched() that is used for the rest. These two new primitives currently have the same implementation, but this is might well change with additional real-time support. Both new primitives are GPL-only, the old primitive is deprecated. Signed-off-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 4d74743..fd276ad 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -157,9 +157,9 @@ static inline int rcu_pending(int cpu) /** * rcu_read_lock - mark the beginning of an RCU read-side critical section. * - * When synchronize_kernel() is invoked on one CPU while other CPUs + * When synchronize_rcu() is invoked on one CPU while other CPUs * are within RCU read-side critical sections, then the - * synchronize_kernel() is guaranteed to block until after all the other + * synchronize_rcu() is guaranteed to block until after all the other * CPUs exit their critical sections. Similarly, if call_rcu() is invoked * on one CPU while other CPUs are within RCU read-side critical * sections, invocation of the corresponding RCU callback is deferred @@ -256,6 +256,21 @@ static inline int rcu_pending(int cpu) (p) = (v); \ }) +/** + * synchronize_sched - block until all CPUs have exited any non-preemptive + * kernel code sequences. + * + * This means that all preempt_disable code sequences, including NMI and + * hardware-interrupt handlers, in progress on entry will have completed + * before this primitive returns. However, this does not guarantee that + * softirq handlers will have completed, since in some kernels + * + * This primitive provides the guarantees made by the (deprecated) + * synchronize_kernel() API. In contrast, synchronize_rcu() only + * guarantees that rcu_read_lock() sections will have completed. + */ +#define synchronize_sched() synchronize_rcu() + extern void rcu_init(void); extern void rcu_check_callbacks(int cpu, int user); extern void rcu_restart_cpu(int cpu); @@ -265,7 +280,9 @@ extern void FASTCALL(call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *head))); extern void FASTCALL(call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *head))); -extern void synchronize_kernel(void); +extern __deprecated_for_modules void synchronize_kernel(void); +extern void synchronize_rcu(void); +void synchronize_idle(void); #endif /* __KERNEL__ */ #endif /* __LINUX_RCUPDATE_H */ diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index ad49772..f436993 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -444,15 +444,18 @@ static void wakeme_after_rcu(struct rcu_head *head) } /** - * synchronize_kernel - wait until a grace period has elapsed. + * synchronize_rcu - wait until a grace period has elapsed. * * Control will return to the caller some time after a full grace * period has elapsed, in other words after all currently executing RCU * read-side critical sections have completed. RCU read-side critical * sections are delimited by rcu_read_lock() and rcu_read_unlock(), * and may be nested. + * + * If your read-side code is not protected by rcu_read_lock(), do -not- + * use synchronize_rcu(). */ -void synchronize_kernel(void) +void synchronize_rcu(void) { struct rcu_synchronize rcu; @@ -464,7 +467,16 @@ void synchronize_kernel(void) wait_for_completion(&rcu.completion); } +/* + * Deprecated, use synchronize_rcu() or synchronize_sched() instead. + */ +void synchronize_kernel(void) +{ + synchronize_rcu(); +} + module_param(maxbatch, int, 0); EXPORT_SYMBOL(call_rcu); /* WARNING: GPL-only in April 2006. */ EXPORT_SYMBOL(call_rcu_bh); /* WARNING: GPL-only in April 2006. */ +EXPORT_SYMBOL_GPL(synchronize_rcu); EXPORT_SYMBOL(synchronize_kernel); /* WARNING: GPL-only in April 2006. */ -- cgit v0.10.2 From fbd568a3e61a7decb8a754ad952aaa5b5c82e9e5 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 1 May 2005 08:59:04 -0700 Subject: [PATCH] Change synchronize_kernel to _rcu and _sched This patch changes calls to synchronize_kernel(), deprecated in the earlier "Deprecate synchronize_kernel, GPL replacement" patch to instead call the new synchronize_rcu() and synchronize_sched() APIs. Signed-off-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c index b2e462a..c58d0c1 100644 --- a/arch/i386/oprofile/nmi_timer_int.c +++ b/arch/i386/oprofile/nmi_timer_int.c @@ -36,7 +36,7 @@ static void timer_stop(void) { enable_timer_nmi_watchdog(); unset_nmi_callback(); - synchronize_kernel(); + synchronize_sched(); /* Allow already-started NMIs to complete. */ } diff --git a/arch/ppc64/kernel/HvLpEvent.c b/arch/ppc64/kernel/HvLpEvent.c index 9802bee..f8f1963 100644 --- a/arch/ppc64/kernel/HvLpEvent.c +++ b/arch/ppc64/kernel/HvLpEvent.c @@ -45,7 +45,7 @@ int HvLpEvent_unregisterHandler( HvLpEvent_Type eventType ) /* We now sleep until all other CPUs have scheduled. This ensures that * the deletion is seen by all other CPUs, and that the deleted handler * isn't still running on another CPU when we return. */ - synchronize_kernel(); + synchronize_rcu(); } } return rc; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 05a1781..ff64d33 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -838,7 +838,7 @@ int acpi_processor_cst_has_changed (struct acpi_processor *pr) /* Fall back to the default idle loop */ pm_idle = pm_idle_save; - synchronize_kernel(); + synchronize_sched(); /* Relies on interrupts forcing exit from idle. */ pr->flags.power = 0; result = acpi_processor_get_power_info(pr); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 29de259..44a7f13 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2199,7 +2199,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) /* Wait until we know that we are out of any interrupt handlers might have been running before we freed the interrupt. */ - synchronize_kernel(); + synchronize_sched(); if (new_smi->si_sm) { if (new_smi->handlers) @@ -2312,7 +2312,7 @@ static void __exit cleanup_one_si(struct smi_info *to_clean) /* Wait until we know that we are out of any interrupt handlers might have been running before we freed the interrupt. */ - synchronize_kernel(); + synchronize_sched(); /* Wait for the timer to stop. This avoids problems with race conditions removing the timer here. */ diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index f7304f0..ff66ed4 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -678,7 +678,7 @@ static void atkbd_disconnect(struct serio *serio) atkbd_disable(atkbd); /* make sure we don't have a command in flight */ - synchronize_kernel(); + synchronize_sched(); /* Allow atkbd_interrupt()s to complete. */ flush_scheduled_work(); device_remove_file(&serio->dev, &atkbd_attr_extra); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index c9b134c..1891e49 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -355,7 +355,7 @@ static int multipath_remove_disk(mddev_t *mddev, int number) goto abort; } p->rdev = NULL; - synchronize_kernel(); + synchronize_rcu(); if (atomic_read(&rdev->nr_pending)) { /* lost the race, try later */ err = -EBUSY; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index a389394..83380b5 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -797,7 +797,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number) goto abort; } p->rdev = NULL; - synchronize_kernel(); + synchronize_rcu(); if (atomic_read(&rdev->nr_pending)) { /* lost the race, try later */ err = -EBUSY; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index b100bfe..e9dc287 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -977,7 +977,7 @@ static int raid10_remove_disk(mddev_t *mddev, int number) goto abort; } p->rdev = NULL; - synchronize_kernel(); + synchronize_rcu(); if (atomic_read(&rdev->nr_pending)) { /* lost the race, try later */ err = -EBUSY; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 52c3a81..e96e2a1 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1873,7 +1873,7 @@ static int raid5_remove_disk(mddev_t *mddev, int number) goto abort; } p->rdev = NULL; - synchronize_kernel(); + synchronize_rcu(); if (atomic_read(&rdev->nr_pending)) { /* lost the race, try later */ err = -EBUSY; diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 7e30ab2..8a33f35 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -2038,7 +2038,7 @@ static int raid6_remove_disk(mddev_t *mddev, int number) goto abort; } p->rdev = NULL; - synchronize_kernel(); + synchronize_rcu(); if (atomic_read(&rdev->nr_pending)) { /* lost the race, try later */ err = -EBUSY; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 07e2df0..c59507f 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2385,7 +2385,7 @@ core_down: } /* Give a racing hard_start_xmit a few cycles to complete. */ - synchronize_kernel(); + synchronize_sched(); /* FIXME: should this be synchronize_irq()? */ /* * And now for the 50k$ question: are IRQ disabled or not ? diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index 3720e77..83e6a06 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -45,7 +45,7 @@ s390_register_adapter_interrupt (adapter_int_handler_t handler) else ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0); if (!ret) - synchronize_kernel(); + synchronize_sched(); /* Allow interrupts to complete. */ sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (4, dbf_txt); @@ -65,7 +65,7 @@ s390_unregister_adapter_interrupt (adapter_int_handler_t handler) ret = -EINVAL; else { adapter_handler = NULL; - synchronize_kernel(); + synchronize_sched(); /* Allow interrupts to complete. */ ret = 0; } sprintf (dbf_txt, "ret:%d", ret); diff --git a/kernel/module.c b/kernel/module.c index 2dbfa07..5734ab0 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1801,7 +1801,7 @@ sys_init_module(void __user *umod, /* Init routine failed: abort. Try to protect us from buggy refcounters. */ mod->state = MODULE_STATE_GOING; - synchronize_kernel(); + synchronize_sched(); if (mod->unsafe) printk(KERN_ERR "%s: module is now stuck!\n", mod->name); diff --git a/kernel/profile.c b/kernel/profile.c index a66be46..0221a50 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -184,7 +184,7 @@ void unregister_timer_hook(int (*hook)(struct pt_regs *)) WARN_ON(hook != timer_hook); timer_hook = NULL; /* make sure all CPUs see the NULL hook */ - synchronize_kernel(); + synchronize_sched(); /* Allow ongoing interrupts to complete. */ } EXPORT_SYMBOL_GPL(register_timer_hook); diff --git a/mm/slab.c b/mm/slab.c index 771cc09..8407426 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1666,7 +1666,7 @@ int kmem_cache_destroy(kmem_cache_t * cachep) } if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) - synchronize_kernel(); + synchronize_rcu(); /* no cpu_online check required here since we clear the percpu * array on cpu offline and set this to NULL. diff --git a/net/core/dev.c b/net/core/dev.c index 7bd4cd4..f5f0058 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3091,7 +3091,7 @@ void free_netdev(struct net_device *dev) void synchronize_net(void) { might_sleep(); - synchronize_kernel(); + synchronize_rcu(); } /** -- cgit v0.10.2 From a83f1fe27f7252a2b73b4f22066e92bf99bd595b Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 1 May 2005 08:59:05 -0700 Subject: [PATCH] Update RCU documentation Update the RCU documentation to allow for the new synchronize_rcu() and synchronize_sched() primitives. Fix a few other nits as well. Signed-off-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt index 12250b3..9c6d450 100644 --- a/Documentation/RCU/RTFP.txt +++ b/Documentation/RCU/RTFP.txt @@ -108,8 +108,9 @@ year saw a paper describing an RCU implementation of System V IPC 2004 has seen a Linux-Journal article on use of RCU in dcache [McKenney04a], a performance comparison of locking to RCU on several different CPUs [McKenney04b], a dissertation describing use of RCU in a -number of operating-system kernels [PaulEdwardMcKenneyPhD], and a paper -describing how to make RCU safe for soft-realtime applications [Sarma04c]. +number of operating-system kernels [PaulEdwardMcKenneyPhD], a paper +describing how to make RCU safe for soft-realtime applications [Sarma04c], +and a paper describing SELinux performance with RCU [JamesMorris04b]. Bibtex Entries @@ -341,6 +342,17 @@ Dipankar Sarma" ,pages="18-26" } +@techreport{Friedberg03a +,author="Stuart A. Friedberg" +,title="Lock-Free Wild Card Search Data Structure and Method" +,institution="US Patent and Trademark Office" +,address="Washington, DC" +,year="2003" +,number="US Patent 6,662,184 (contributed under GPL)" +,month="December" +,pages="112" +} + @article{McKenney04a ,author="Paul E. McKenney and Dipankar Sarma and Maneesh Soni" ,title="Scaling dcache with {RCU}" @@ -373,6 +385,9 @@ in Operating System Kernels" ,school="OGI School of Science and Engineering at Oregon Health and Sciences University" ,year="2004" +,note="Available: +\url{http://www.rdrop.com/users/paulmck/RCU/RCUdissertation.2004.07.14e1.pdf} +[Viewed October 15, 2004]" } @Conference{Sarma04c @@ -385,3 +400,13 @@ Oregon Health and Sciences University" ,month="June" ,pages="182-191" } + +@unpublished{JamesMorris04b +,Author="James Morris" +,Title="Recent Developments in {SELinux} Kernel Performance" +,month="December" +,year="2004" +,note="Available: +\url{http://www.livejournal.com/users/james_morris/2153.html} +[Viewed December 10, 2004]" +} diff --git a/Documentation/RCU/UP.txt b/Documentation/RCU/UP.txt index 551a803..3bfb84b 100644 --- a/Documentation/RCU/UP.txt +++ b/Documentation/RCU/UP.txt @@ -2,11 +2,11 @@ RCU on Uniprocessor Systems A common misconception is that, on UP systems, the call_rcu() primitive -may immediately invoke its function, and that the synchronize_kernel +may immediately invoke its function, and that the synchronize_rcu() primitive may return immediately. The basis of this misconception is that since there is only one CPU, it should not be necessary to wait for anything else to get done, since there are no other CPUs for -anything else to be happening on. Although this approach will sort of +anything else to be happening on. Although this approach will -sort- -of- work a surprising amount of the time, it is a very bad idea in general. This document presents two examples that demonstrate exactly how bad an idea this is. @@ -44,14 +44,14 @@ its arguments would cause it to fail to make the fundamental guarantee underlying RCU, namely that call_rcu() defers invoking its arguments until all RCU read-side critical sections currently executing have completed. -Quick Quiz: why is it -not- legal to invoke synchronize_kernel() in +Quick Quiz: why is it -not- legal to invoke synchronize_rcu() in this case? Summary Permitting call_rcu() to immediately invoke its arguments or permitting -synchronize_kernel() to immediately return breaks RCU, even on a UP system. +synchronize_rcu() to immediately return breaks RCU, even on a UP system. So do not do it! Even on a UP system, the RCU infrastructure -must- respect grace periods. diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt index b3a568a..8f3fb77 100644 --- a/Documentation/RCU/checklist.txt +++ b/Documentation/RCU/checklist.txt @@ -32,7 +32,10 @@ over a rather long period of time, but improvements are always welcome! them -- even x86 allows reads to be reordered), and be prepared to explain why this added complexity is worthwhile. If you choose #c, be prepared to explain how this single task does not - become a major bottleneck on big multiprocessor machines. + become a major bottleneck on big multiprocessor machines (for + example, if the task is updating information relating to itself + that other tasks can read, there by definition can be no + bottleneck). 2. Do the RCU read-side critical sections make proper use of rcu_read_lock() and friends? These primitives are needed @@ -89,27 +92,34 @@ over a rather long period of time, but improvements are always welcome! "_rcu()" list-traversal primitives, such as the list_for_each_entry_rcu(). - b. If the list macros are being used, the list_del_rcu(), - list_add_tail_rcu(), and list_del_rcu() primitives must - be used in order to prevent weakly ordered machines from - misordering structure initialization and pointer planting. + b. If the list macros are being used, the list_add_tail_rcu() + and list_add_rcu() primitives must be used in order + to prevent weakly ordered machines from misordering + structure initialization and pointer planting. Similarly, if the hlist macros are being used, the - hlist_del_rcu() and hlist_add_head_rcu() primitives - are required. + hlist_add_head_rcu() primitive is required. - c. Updates must ensure that initialization of a given + c. If the list macros are being used, the list_del_rcu() + primitive must be used to keep list_del()'s pointer + poisoning from inflicting toxic effects on concurrent + readers. Similarly, if the hlist macros are being used, + the hlist_del_rcu() primitive is required. + + The list_replace_rcu() primitive may be used to + replace an old structure with a new one in an + RCU-protected list. + + d. Updates must ensure that initialization of a given structure happens before pointers to that structure are publicized. Use the rcu_assign_pointer() primitive when publicizing a pointer to a structure that can be traversed by an RCU read-side critical section. - [The rcu_assign_pointer() primitive is in process.] - 5. If call_rcu(), or a related primitive such as call_rcu_bh(), is used, the callback function must be written to be called from softirq context. In particular, it cannot block. -6. Since synchronize_kernel() blocks, it cannot be called from +6. Since synchronize_rcu() can block, it cannot be called from any sort of irq context. 7. If the updater uses call_rcu(), then the corresponding readers @@ -125,9 +135,9 @@ over a rather long period of time, but improvements are always welcome! such cases is a must, of course! And the jury is still out on whether the increased speed is worth it. -8. Although synchronize_kernel() is a bit slower than is call_rcu(), +8. Although synchronize_rcu() is a bit slower than is call_rcu(), it usually results in simpler code. So, unless update performance - is important or the updaters cannot block, synchronize_kernel() + is important or the updaters cannot block, synchronize_rcu() should be used in preference to call_rcu(). 9. All RCU list-traversal primitives, which include @@ -155,3 +165,14 @@ over a rather long period of time, but improvements are always welcome! you -must- use the "_rcu()" variants of the list macros. Failing to do so will break Alpha and confuse people reading your code. + +11. Note that synchronize_rcu() -only- guarantees to wait until + all currently executing rcu_read_lock()-protected RCU read-side + critical sections complete. It does -not- necessarily guarantee + that all currently running interrupts, NMIs, preempt_disable() + code, or idle loops will complete. Therefore, if you do not have + rcu_read_lock()-protected read-side critical sections, do -not- + use synchronize_rcu(). + + If you want to wait for some of these other things, you might + instead need to use synchronize_irq() or synchronize_sched(). diff --git a/Documentation/RCU/listRCU.txt b/Documentation/RCU/listRCU.txt index bda6ead..f8a54fa 100644 --- a/Documentation/RCU/listRCU.txt +++ b/Documentation/RCU/listRCU.txt @@ -32,6 +32,7 @@ implementation of audit_filter_task() might be as follows: enum audit_state state; read_lock(&auditsc_lock); + /* Note: audit_netlink_sem held by caller. */ list_for_each_entry(e, &audit_tsklist, list) { if (audit_filter_rules(tsk, &e->rule, NULL, &state)) { read_unlock(&auditsc_lock); @@ -55,6 +56,7 @@ This means that RCU can be easily applied to the read side, as follows: enum audit_state state; rcu_read_lock(); + /* Note: audit_netlink_sem held by caller. */ list_for_each_entry_rcu(e, &audit_tsklist, list) { if (audit_filter_rules(tsk, &e->rule, NULL, &state)) { rcu_read_unlock(); @@ -139,12 +141,15 @@ Normally, the write_lock() and write_unlock() would be replaced by a spin_lock() and a spin_unlock(), but in this case, all callers hold audit_netlink_sem, so no additional locking is required. The auditsc_lock can therefore be eliminated, since use of RCU eliminates the need for -writers to exclude readers. +writers to exclude readers. Normally, the write_lock() calls would +be converted into spin_lock() calls. The list_del(), list_add(), and list_add_tail() primitives have been replaced by list_del_rcu(), list_add_rcu(), and list_add_tail_rcu(). The _rcu() list-manipulation primitives add memory barriers that are -needed on weakly ordered CPUs (most of them!). +needed on weakly ordered CPUs (most of them!). The list_del_rcu() +primitive omits the pointer poisoning debug-assist code that would +otherwise cause concurrent readers to fail spectacularly. So, when readers can tolerate stale data and when entries are either added or deleted, without in-place modification, it is very easy to use RCU! @@ -166,6 +171,7 @@ otherwise, the added fields would need to be filled in): struct audit_newentry *ne; write_lock(&auditsc_lock); + /* Note: audit_netlink_sem held by caller. */ list_for_each_entry(e, list, list) { if (!audit_compare_rule(rule, &e->rule)) { e->rule.action = newaction; @@ -199,8 +205,7 @@ RCU ("read-copy update") its name. The RCU code is as follows: audit_copy_rule(&ne->rule, &e->rule); ne->rule.action = newaction; ne->rule.file_count = newfield_count; - list_add_rcu(ne, e); - list_del(e); + list_replace_rcu(e, ne); call_rcu(&e->rcu, audit_free_rule, e); return 0; } diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt index 7e0c2ab..eb44400 100644 --- a/Documentation/RCU/rcu.txt +++ b/Documentation/RCU/rcu.txt @@ -43,7 +43,9 @@ o If I am running on a uniprocessor kernel, which can only do one o How can I see where RCU is currently used in the Linux kernel? - Search for "rcu_read_lock", "call_rcu", and "synchronize_kernel". + Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu", + "rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh", + "synchronize_rcu", and "synchronize_net". o What guidelines should I follow when writing code that uses RCU? -- cgit v0.10.2 From 9a3bb3017383fbb6fe56431d17f60bd0d50f0717 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 1 May 2005 08:59:05 -0700 Subject: [PATCH] reiserfs: make resize option auto-get new device size It's trivial for the resize option to auto-get the underlying device size, while it's harder for the user. I've copied the code from jfs. Since of the different reiserfs option parser (which does not use the superior match_token used by almost every other filesystem), I've had to use the "resize=auto" and not "resize" option to specify this behaviour. Changing the option parser to the kernel one wouldn't be bad but I've no time to do this cleanup in this moment. Btw, the mount(8) man page should be updated to include this option. Cc the relevant people, please (I hope I cc'ed the right people). Cc: Cc: Cc: Cc: Alex Zarochentsev Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index bcdf243..bc5e889 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -889,12 +889,18 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st char * p; p = NULL; - /* "resize=NNN" */ - *blocks = simple_strtoul (arg, &p, 0); - if (*p != '\0') { - /* NNN does not look like a number */ - reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg); - return 0; + /* "resize=NNN" or "resize=auto" */ + + if (!strcmp(arg, "auto")) { + /* From JFS code, to auto-get the size.*/ + *blocks = s->s_bdev->bd_inode->i_size >> s->s_blocksize_bits; + } else { + *blocks = simple_strtoul (arg, &p, 0); + if (*p != '\0') { + /* NNN does not look like a number */ + reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg); + return 0; + } } } @@ -903,7 +909,8 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st unsigned long val = simple_strtoul (arg, &p, 0); /* commit=NNN (time in seconds) */ if ( *p != '\0' || val >= (unsigned int)-1) { - reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg); return 0; + reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg); + return 0; } *commit_max_age = (unsigned int)val; } -- cgit v0.10.2 From 0c8b971ebb21dc33271c38d17fd58b8072009dc5 Mon Sep 17 00:00:00 2001 From: Peter Missel Date: Sun, 1 May 2005 08:59:05 -0700 Subject: [PATCH] LifeView FlyTV Platinum FM: Remote Control support Subject says it ... this card's IR microcontroller design and attachment are compatible to the company's previous designs, so the patch was as simple as it gets. DESC LifeView FlyTV Platinum FM: GPIO usage EDESC From: Peter Missel This is take two of a patch that should have appeared two days ago, before yesterday's "remote control" patch for the same card. This patch sets unconnected GPIO to Output to keep them from floating (just good driver writing practice, being nice to the chip), and uses GPIO16 to switch TV vs. FM - this pin switches inputs onto the tuner, as well as the audio output from the tuner into the 7135 SIF input. Consequently, FM radio support is being un-commented because it's now working (sort of, see below). These two patches get the card almost fully operational; there appears to be a bug in tda8290.c remaining that puts an offset onto the tuned frequency in FM radio mode. We're investigating. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 180d317..cfe4b57 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1948,6 +1948,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) dev->has_remote = 1; board_flyvideo(dev); break; + case SAA7134_BOARD_FLYTVPLATINUM_FM: case SAA7134_BOARD_CINERGY400: case SAA7134_BOARD_CINERGY600: case SAA7134_BOARD_CINERGY600_MK3: diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 727d437..ca50cf5 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -379,6 +379,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) switch (dev->board) { case SAA7134_BOARD_FLYVIDEO2000: case SAA7134_BOARD_FLYVIDEO3000: + case SAA7134_BOARD_FLYTVPLATINUM_FM: ir_codes = flyvideo_codes; mask_keycode = 0xEC00000; mask_keydown = 0x0040000; -- cgit v0.10.2 From 6c9e7376bed151d1655c12d2d5f5cc96bfb83dbd Mon Sep 17 00:00:00 2001 From: Peter Missel Date: Sun, 1 May 2005 08:59:05 -0700 Subject: [PATCH] LifeView FlyTV Platinum FM: GPIO usage This is take two of a patch that should have appeared two days ago, before yesterday's "remote control" patch for the same card. This patch sets unconnected GPIO to Output to keep them from floating (just good driver writing practice, being nice to the chip), and uses GPIO16 to switch TV vs. FM - this pin switches inputs onto the tuner, as well as the audio output from the tuner into the 7135 SIF input. Consequently, FM radio support is being un-commented because it's now working (sort of, see below). These two patches get the card almost fully operational; there appears to be a bug in tda8290.c remaining that puts an offset onto the tuned frequency in FM radio mode. We're investigating. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index cfe4b57..72a7b24 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -183,12 +183,12 @@ struct saa7134_board saa7134_boards[] = { .name = "LifeView FlyTV Platinum FM", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, -// .gpiomask = 0xe000, + .gpiomask = 0x1E000, /* Set GP16 and unused 15,14,13 to Output */ .inputs = {{ .name = name_tv, .vmux = 1, .amux = TV, -// .gpio = 0x0000, + .gpio = 0x10000, /* GP16=1 selects TV input */ .tv = 1, },{ /* .name = name_tv_mono, @@ -212,12 +212,12 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, // .gpio = 0x4000, }}, -/* .radio = { + .radio = { .name = name_radio, - .amux = LINE2, - .gpio = 0x2000, + .amux = TV, + .gpio = 0x00000, /* GP16=0 selects FM radio antenna */ }, -*/ }, + }, [SAA7134_BOARD_EMPRESS] = { /* "Gert Vervoort" */ .name = "EMPRESS", -- cgit v0.10.2 From 41f11a4fa378201e902892130b11d78cf7cf8e10 Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Sun, 1 May 2005 08:59:06 -0700 Subject: [PATCH] kallsyms C_SYMBOL_PREFIX support kallsyms does not consider SYMBOL_PREFIX of C. Consequently it does not work on architectures using that prefix character (h8300, v850). Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 090ffda..fe11df8 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -69,6 +69,7 @@ static struct sym_entry *table; static int size, cnt; static unsigned long long _stext, _etext, _sinittext, _einittext; static int all_symbols = 0; +static char symbol_prefix_char = '\0'; struct token { unsigned char data[MAX_TOK_SIZE]; @@ -93,7 +94,7 @@ unsigned char best_table_len[256]; static void usage(void) { - fprintf(stderr, "Usage: kallsyms [--all-symbols] < in.map > out.S\n"); + fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=] < in.map > out.S\n"); exit(1); } @@ -112,6 +113,7 @@ static int read_symbol(FILE *in, struct sym_entry *s) { char str[500]; + char *sym; int rc; rc = fscanf(in, "%llx %c %499s\n", &s->addr, &s->type, str); @@ -123,27 +125,32 @@ read_symbol(FILE *in, struct sym_entry *s) return -1; } + sym = str; + /* skip prefix char */ + if (symbol_prefix_char && str[0] == symbol_prefix_char) + sym++; + /* Ignore most absolute/undefined (?) symbols. */ - if (strcmp(str, "_stext") == 0) + if (strcmp(sym, "_stext") == 0) _stext = s->addr; - else if (strcmp(str, "_etext") == 0) + else if (strcmp(sym, "_etext") == 0) _etext = s->addr; - else if (strcmp(str, "_sinittext") == 0) + else if (strcmp(sym, "_sinittext") == 0) _sinittext = s->addr; - else if (strcmp(str, "_einittext") == 0) + else if (strcmp(sym, "_einittext") == 0) _einittext = s->addr; else if (toupper(s->type) == 'A') { /* Keep these useful absolute symbols */ - if (strcmp(str, "__kernel_syscall_via_break") && - strcmp(str, "__kernel_syscall_via_epc") && - strcmp(str, "__kernel_sigtramp") && - strcmp(str, "__gp")) + if (strcmp(sym, "__kernel_syscall_via_break") && + strcmp(sym, "__kernel_syscall_via_epc") && + strcmp(sym, "__kernel_sigtramp") && + strcmp(sym, "__gp")) return -1; } else if (toupper(s->type) == 'U' || - is_arm_mapping_symbol(str)) + is_arm_mapping_symbol(sym)) return -1; /* include the type field in the symbol name, so that it gets @@ -177,6 +184,11 @@ symbol_valid(struct sym_entry *s) "_SDA2_BASE_", /* ppc */ NULL }; int i; + int offset = 1; + + /* skip prefix char */ + if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char) + offset++; /* if --all-symbols is not specified, then symbols outside the text * and inittext sections are discarded */ @@ -190,17 +202,17 @@ symbol_valid(struct sym_entry *s) * they may get dropped in pass 2, which breaks the kallsyms * rules. */ - if ((s->addr == _etext && strcmp(s->sym + 1, "_etext")) || - (s->addr == _einittext && strcmp(s->sym + 1, "_einittext"))) + if ((s->addr == _etext && strcmp(s->sym + offset, "_etext")) || + (s->addr == _einittext && strcmp(s->sym + offset, "_einittext"))) return 0; } /* Exclude symbols which vary between passes. */ - if (strstr(s->sym + 1, "_compiled.")) + if (strstr(s->sym + offset, "_compiled.")) return 0; for (i = 0; special_symbols[i]; i++) - if( strcmp(s->sym + 1, special_symbols[i]) == 0 ) + if( strcmp(s->sym + offset, special_symbols[i]) == 0 ) return 0; return 1; @@ -225,9 +237,15 @@ read_map(FILE *in) static void output_label(char *label) { - printf(".globl %s\n",label); + if (symbol_prefix_char) + printf(".globl %c%s\n", symbol_prefix_char, label); + else + printf(".globl %s\n", label); printf("\tALGN\n"); - printf("%s:\n",label); + if (symbol_prefix_char) + printf("%c%s:\n", symbol_prefix_char, label); + else + printf("%s:\n", label); } /* uncompress a compressed symbol. When this function is called, the best table @@ -665,6 +683,13 @@ static void optimize_token_table(void) insert_real_symbols_in_table(); + /* When valid symbol is not registered, exit to error */ + if (good_head.left == good_head.right && + bad_head.left == bad_head.right) { + fprintf(stderr, "No valid symbol.\n"); + exit(1); + } + optimize_result(); } @@ -672,9 +697,21 @@ static void optimize_token_table(void) int main(int argc, char **argv) { - if (argc == 2 && strcmp(argv[1], "--all-symbols") == 0) - all_symbols = 1; - else if (argc != 1) + if (argc >= 2) { + int i; + for (i = 1; i < argc; i++) { + if(strcmp(argv[i], "--all-symbols") == 0) + all_symbols = 1; + else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) { + char *p = &argv[i][16]; + /* skip quote */ + if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\'')) + p++; + symbol_prefix_char = *p; + } else + usage(); + } + } else if (argc != 1) usage(); read_map(stdin); @@ -683,4 +720,3 @@ main(int argc, char **argv) return 0; } - -- cgit v0.10.2 From 1181c1f923c349acaa01bca40fe600584f265132 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sun, 1 May 2005 08:59:06 -0700 Subject: [PATCH] noop-iosched: kill O(N) merge scan Profiling hit rates on merging shows that the last merge hint works extremely well for most work loads. So lets kill the linear merge scan in noop-iosched, so it provides O(1) run time for any operation. Testing credits go to Ken Chen from Intel. Signed-off-by: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/block/noop-iosched.c b/drivers/block/noop-iosched.c index 888c477..b1730b6 100644 --- a/drivers/block/noop-iosched.c +++ b/drivers/block/noop-iosched.c @@ -13,34 +13,13 @@ static int elevator_noop_merge(request_queue_t *q, struct request **req, struct bio *bio) { - struct list_head *entry = &q->queue_head; - struct request *__rq; int ret; - if ((ret = elv_try_last_merge(q, bio))) { + ret = elv_try_last_merge(q, bio); + if (ret != ELEVATOR_NO_MERGE) *req = q->last_merge; - return ret; - } - while ((entry = entry->prev) != &q->queue_head) { - __rq = list_entry_rq(entry); - - if (__rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) - break; - else if (__rq->flags & REQ_STARTED) - break; - - if (!blk_fs_request(__rq)) - continue; - - if ((ret = elv_try_merge(__rq, bio))) { - *req = __rq; - q->last_merge = __rq; - return ret; - } - } - - return ELEVATOR_NO_MERGE; + return ret; } static void elevator_noop_merge_requests(request_queue_t *q, struct request *req, -- cgit v0.10.2 From 4750e2c0c59e0c84c6c036b3d96ebd88365ae7ee Mon Sep 17 00:00:00 2001 From: Joe Korty Date: Sun, 1 May 2005 08:59:06 -0700 Subject: [PATCH] add EOWNERDEAD and ENOTRECOVERABLE version 2 Add EOWNERDEAD and ENOTRECOVERABLE to all architectures. This is to support the upcoming patches for robust mutexes. We normally don't reserve parts of the name/number space for external patches, but robust mutexes are sufficiently popular and important to justify it in this case. Signed-off-by: Joe Korty Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-alpha/errno.h b/include/asm-alpha/errno.h index c85ab6b..69e2655 100644 --- a/include/asm-alpha/errno.h +++ b/include/asm-alpha/errno.h @@ -116,4 +116,8 @@ #define EKEYREVOKED 134 /* Key has been revoked */ #define EKEYREJECTED 135 /* Key was rejected by service */ +/* for robust mutexes */ +#define EOWNERDEAD 136 /* Owner died */ +#define ENOTRECOVERABLE 137 /* State not recoverable */ + #endif diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h index 4dd2384..e8852c0 100644 --- a/include/asm-generic/errno.h +++ b/include/asm-generic/errno.h @@ -102,4 +102,8 @@ #define EKEYREVOKED 128 /* Key has been revoked */ #define EKEYREJECTED 129 /* Key was rejected by service */ +/* for robust mutexes */ +#define EOWNERDEAD 130 /* Owner died */ +#define ENOTRECOVERABLE 131 /* State not recoverable */ + #endif diff --git a/include/asm-mips/errno.h b/include/asm-mips/errno.h index 2b458f9..3c0d840 100644 --- a/include/asm-mips/errno.h +++ b/include/asm-mips/errno.h @@ -115,6 +115,10 @@ #define EKEYREVOKED 163 /* Key has been revoked */ #define EKEYREJECTED 164 /* Key was rejected by service */ +/* for robust mutexes */ +#define EOWNERDEAD 165 /* Owner died */ +#define ENOTRECOVERABLE 166 /* State not recoverable */ + #define EDQUOT 1133 /* Quota exceeded */ #ifdef __KERNEL__ diff --git a/include/asm-parisc/errno.h b/include/asm-parisc/errno.h index a10f109..08464c4 100644 --- a/include/asm-parisc/errno.h +++ b/include/asm-parisc/errno.h @@ -115,5 +115,9 @@ #define ENOTSUP 252 /* Function not implemented (POSIX.4 / HPUX) */ #define ECANCELLED 253 /* aio request was canceled before complete (POSIX.4 / HPUX) */ +/* for robust mutexes */ +#define EOWNERDEAD 254 /* Owner died */ +#define ENOTRECOVERABLE 255 /* State not recoverable */ + #endif diff --git a/include/asm-sparc/errno.h b/include/asm-sparc/errno.h index 8c01c5f3..ed41c8b 100644 --- a/include/asm-sparc/errno.h +++ b/include/asm-sparc/errno.h @@ -107,4 +107,8 @@ #define EKEYREVOKED 130 /* Key has been revoked */ #define EKEYREJECTED 131 /* Key was rejected by service */ +/* for robust mutexes */ +#define EOWNERDEAD 132 /* Owner died */ +#define ENOTRECOVERABLE 133 /* State not recoverable */ + #endif diff --git a/include/asm-sparc64/errno.h b/include/asm-sparc64/errno.h index cc98a73..ea3509e 100644 --- a/include/asm-sparc64/errno.h +++ b/include/asm-sparc64/errno.h @@ -107,4 +107,8 @@ #define EKEYREVOKED 130 /* Key has been revoked */ #define EKEYREJECTED 131 /* Key was rejected by service */ +/* for robust mutexes */ +#define EOWNERDEAD 132 /* Owner died */ +#define ENOTRECOVERABLE 133 /* State not recoverable */ + #endif /* !(_SPARC64_ERRNO_H) */ -- cgit v0.10.2 From 40be0c28b33ff0821594a3fa7126354dfe6eccd1 Mon Sep 17 00:00:00 2001 From: Lars Marowsky-Bree Date: Sun, 1 May 2005 08:59:07 -0700 Subject: [PATCH] nbd: Don't create all MAX_NBD devices by default all the time This patches adds the "nbds_max" parameter to the nbd kernel module, which limits the number of nbds allocated. Previously, always all 128 entries were allocated unconditionally, which used to waste resources and needlessly flood the hotplug system with events. (Defaults to 16 now.) Signed-off-by: Lars Marowsky-Bree Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index efdf044..9e268dd 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -78,6 +78,7 @@ #define DBG_RX 0x0200 #define DBG_TX 0x0400 static unsigned int debugflags; +static unsigned int nbds_max = 16; #endif /* NDEBUG */ static struct nbd_device nbd_dev[MAX_NBD]; @@ -647,7 +648,13 @@ static int __init nbd_init(void) return -EIO; } - for (i = 0; i < MAX_NBD; i++) { + if (nbds_max > MAX_NBD) { + printk(KERN_CRIT "nbd: cannot allocate more than %u nbds; %u requested.\n", MAX_NBD, + nbds_max); + return -EINVAL; + } + + for (i = 0; i < nbds_max; i++) { struct gendisk *disk = alloc_disk(1); if (!disk) goto out; @@ -673,7 +680,7 @@ static int __init nbd_init(void) dprintk(DBG_INIT, "nbd: debugflags=0x%x\n", debugflags); devfs_mk_dir("nbd"); - for (i = 0; i < MAX_NBD; i++) { + for (i = 0; i < nbds_max; i++) { struct gendisk *disk = nbd_dev[i].disk; nbd_dev[i].file = NULL; nbd_dev[i].magic = LO_MAGIC; @@ -706,8 +713,9 @@ out: static void __exit nbd_cleanup(void) { int i; - for (i = 0; i < MAX_NBD; i++) { + for (i = 0; i < nbds_max; i++) { struct gendisk *disk = nbd_dev[i].disk; + nbd_dev[i].magic = 0; if (disk) { del_gendisk(disk); blk_cleanup_queue(disk->queue); @@ -725,6 +733,8 @@ module_exit(nbd_cleanup); MODULE_DESCRIPTION("Network Block Device"); MODULE_LICENSE("GPL"); +module_param(nbds_max, int, 0444); +MODULE_PARM_DESC(nbds_max, "How many network block devices to initialize."); #ifndef NDEBUG module_param(debugflags, int, 0644); MODULE_PARM_DESC(debugflags, "flags for controlling debug output"); -- cgit v0.10.2 From 127144df4ce817ad648af15a3983c8d52aacf670 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Sun, 1 May 2005 08:59:07 -0700 Subject: [PATCH] Fix rewriting on a full reiserfs filesystem Allow rewriting of a file and extending a file upto the end of the allocated block on a full filesystem. From: Chris Mason Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 2695011..f6860e8 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -1284,10 +1284,11 @@ static ssize_t reiserfs_file_write( struct file *file, /* the file we are going reiserfs_claim_blocks_to_be_allocated(inode->i_sb, num_pages << (PAGE_CACHE_SHIFT - inode->i_blkbits)); reiserfs_write_unlock(inode->i_sb); - if ( !num_pages ) { /* If we do not have enough space even for */ - res = -ENOSPC; /* single page, return -ENOSPC */ - if ( pos > (inode->i_size & (inode->i_sb->s_blocksize-1))) - break; // In case we are writing past the file end, break. + if ( !num_pages ) { /* If we do not have enough space even for a single page... */ + if ( pos > inode->i_size+inode->i_sb->s_blocksize-(pos & (inode->i_sb->s_blocksize-1))) { + res = -ENOSPC; + break; // In case we are writing past the end of the last file block, break. + } // Otherwise we are possibly overwriting the file, so // let's set write size to be equal or less than blocksize. // This way we get it correctly for file holes. -- cgit v0.10.2 From a40920b42ae232fac514cc4a1eb92996114af340 Mon Sep 17 00:00:00 2001 From: Bill Nottingham Date: Sun, 1 May 2005 08:59:07 -0700 Subject: [PATCH] vgacon: set vc_hi_font_mask correctly When allocating a new VC with vgacon_init(), the font is shared across all the VGA consoles. However, the font mask was always set to the default value of zero in visual_init(), even if we were using 512 character fonts at the time. Moreover, code in vgacon.c:vga_do_font_op() didn't reset the mask if the console driver thinks it's already in 512 character mode. This means that to *fix* it, you'd actually have to take the console out of 512 character mode and then set it back. The attached sets vc_hi_font_mask in vgacon_init() for any new consoles opened if the vgacon driver is already in 512 character mode, solving this. This bug goes back to 2.4.18 at least, probably earlier. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 7d1ae06..bcf59b2 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -337,6 +337,8 @@ static void vgacon_init(struct vc_data *c, int init) c->vc_scan_lines = vga_scan_lines; c->vc_font.height = vga_video_font_height; c->vc_complement_mask = 0x7700; + if (vga_512_chars) + c->vc_hi_font_mask = 0x0800; p = *c->vc_uni_pagedir_loc; if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir || !--c->vc_uni_pagedir_loc[1]) -- cgit v0.10.2 From 696f9486d0207d499391004f5bc9bd7c0e6ae82f Mon Sep 17 00:00:00 2001 From: Joel Becker Date: Sun, 1 May 2005 08:59:08 -0700 Subject: [PATCH] hangcheck-timer: Update to 0.9.0. I recently realized that the in-kernel copy of hangcheck-timer was quite stale. Here's the latest. It adds support for s390, ppc64, and ia64 too. Signed-off-by: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 97ac4ed..e162dab 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -982,7 +982,7 @@ config MAX_RAW_DEVS config HANGCHECK_TIMER tristate "Hangcheck timer" - depends on X86_64 || X86 + depends on X86_64 || X86 || IA64 || PPC64 || ARCH_S390 help The hangcheck-timer module detects when the system has gone out to lunch past a certain margin. It can reboot the system diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index 83d6b37..78e650f 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -3,7 +3,7 @@ * * Driver for a little io fencing timer. * - * Copyright (C) 2002 Oracle Corporation. All rights reserved. + * Copyright (C) 2002, 2003 Oracle. All rights reserved. * * Author: Joel Becker * @@ -44,11 +44,14 @@ #include #include #include +#include #include +#include #include +#include -#define VERSION_STR "0.5.0" +#define VERSION_STR "0.9.0" #define DEFAULT_IOFENCE_MARGIN 60 /* Default fudge factor, in seconds */ #define DEFAULT_IOFENCE_TICK 180 /* Default timer timeout, in seconds */ @@ -56,18 +59,89 @@ static int hangcheck_tick = DEFAULT_IOFENCE_TICK; static int hangcheck_margin = DEFAULT_IOFENCE_MARGIN; static int hangcheck_reboot; /* Defaults to not reboot */ +static int hangcheck_dump_tasks; /* Defaults to not dumping SysRQ T */ -/* Driver options */ +/* options - modular */ module_param(hangcheck_tick, int, 0); MODULE_PARM_DESC(hangcheck_tick, "Timer delay."); module_param(hangcheck_margin, int, 0); MODULE_PARM_DESC(hangcheck_margin, "If the hangcheck timer has been delayed more than hangcheck_margin seconds, the driver will fire."); module_param(hangcheck_reboot, int, 0); MODULE_PARM_DESC(hangcheck_reboot, "If nonzero, the machine will reboot when the timer margin is exceeded."); +module_param(hangcheck_dump_tasks, int, 0); +MODULE_PARM_DESC(hangcheck_dump_tasks, "If nonzero, the machine will dump the system task state when the timer margin is exceeded."); -MODULE_AUTHOR("Joel Becker"); +MODULE_AUTHOR("Oracle"); MODULE_DESCRIPTION("Hangcheck-timer detects when the system has gone out to lunch past a certain margin."); MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION_STR); + +/* options - nonmodular */ +#ifndef MODULE + +static int __init hangcheck_parse_tick(char *str) +{ + int par; + if (get_option(&str,&par)) + hangcheck_tick = par; + return 1; +} + +static int __init hangcheck_parse_margin(char *str) +{ + int par; + if (get_option(&str,&par)) + hangcheck_margin = par; + return 1; +} + +static int __init hangcheck_parse_reboot(char *str) +{ + int par; + if (get_option(&str,&par)) + hangcheck_reboot = par; + return 1; +} + +static int __init hangcheck_parse_dump_tasks(char *str) +{ + int par; + if (get_option(&str,&par)) + hangcheck_dump_tasks = par; + return 1; +} + +__setup("hcheck_tick", hangcheck_parse_tick); +__setup("hcheck_margin", hangcheck_parse_margin); +__setup("hcheck_reboot", hangcheck_parse_reboot); +__setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); +#endif /* not MODULE */ + +#if defined(CONFIG_X86) || defined(CONFIG_X86_64) +# define HAVE_MONOTONIC +# define TIMER_FREQ 1000000000ULL +#elif defined(CONFIG_ARCH_S390) +/* FA240000 is 1 Second in the IBM time universe (Page 4-38 Principles of Op for zSeries */ +# define TIMER_FREQ 0xFA240000ULL +#elif defined(CONFIG_IA64) +# define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq) +#elif defined(CONFIG_PPC64) +# define TIMER_FREQ (HZ*loops_per_jiffy) +#endif + +#ifdef HAVE_MONOTONIC +extern unsigned long long monotonic_clock(void); +#else +static inline unsigned long long monotonic_clock(void) +{ +# ifdef __s390__ + /* returns the TOD. see 4-38 Principles of Op of zSeries */ + return get_clock(); +# else + return get_cycles(); +# endif /* __s390__ */ +} +#endif /* HAVE_MONOTONIC */ /* Last time scheduled */ @@ -78,7 +152,6 @@ static void hangcheck_fire(unsigned long); static struct timer_list hangcheck_ticktock = TIMER_INITIALIZER(hangcheck_fire, 0, 0); -extern unsigned long long monotonic_clock(void); static void hangcheck_fire(unsigned long data) { @@ -92,6 +165,12 @@ static void hangcheck_fire(unsigned long data) tsc_diff = (cur_tsc + (~0ULL - hangcheck_tsc)); /* or something */ if (tsc_diff > hangcheck_tsc_margin) { + if (hangcheck_dump_tasks) { + printk(KERN_CRIT "Hangcheck: Task state:\n"); +#ifdef CONFIG_MAGIC_SYSRQ + handle_sysrq('t', NULL, NULL); +#endif /* CONFIG_MAGIC_SYSRQ */ + } if (hangcheck_reboot) { printk(KERN_CRIT "Hangcheck: hangcheck is restarting the machine.\n"); machine_restart(NULL); @@ -108,10 +187,16 @@ static int __init hangcheck_init(void) { printk("Hangcheck: starting hangcheck timer %s (tick is %d seconds, margin is %d seconds).\n", VERSION_STR, hangcheck_tick, hangcheck_margin); - - hangcheck_tsc_margin = hangcheck_margin + hangcheck_tick; - hangcheck_tsc_margin *= 1000000000; - +#if defined (HAVE_MONOTONIC) + printk("Hangcheck: Using monotonic_clock().\n"); +#elif defined(__s390__) + printk("Hangcheck: Using TOD.\n"); +#else + printk("Hangcheck: Using get_cycles().\n"); +#endif /* HAVE_MONOTONIC */ + hangcheck_tsc_margin = + (unsigned long long)(hangcheck_margin + hangcheck_tick); + hangcheck_tsc_margin *= (unsigned long long)TIMER_FREQ; hangcheck_tsc = monotonic_clock(); mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ)); @@ -123,6 +208,7 @@ static int __init hangcheck_init(void) static void __exit hangcheck_exit(void) { del_timer_sync(&hangcheck_ticktock); + printk("Hangcheck: Stopped hangcheck timer.\n"); } module_init(hangcheck_init); -- cgit v0.10.2 From a71c1ab50a2a0f4dd9834bf5a917a2f064535c6b Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Sun, 1 May 2005 08:59:08 -0700 Subject: [PATCH] consolidate SIGEV_PAD_SIZE Discussing with Matthew Wilcox some of his outstanding patches lead me to this patch (among others). The preamble in struct sigevent can be expressed independently of the architecture. Also use __ARCH_SI_PREAMBLE_SIZE on ia64. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-alpha/siginfo.h b/include/asm-alpha/siginfo.h index 86bcab5..9822362 100644 --- a/include/asm-alpha/siginfo.h +++ b/include/asm-alpha/siginfo.h @@ -4,8 +4,6 @@ #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) #define __ARCH_SI_TRAPNO -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4) - #include #endif diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h index 9cac8e8..8786e01 100644 --- a/include/asm-generic/siginfo.h +++ b/include/asm-generic/siginfo.h @@ -236,11 +236,18 @@ typedef struct siginfo { #define SIGEV_THREAD 2 /* deliver via thread creation */ #define SIGEV_THREAD_ID 4 /* deliver to thread */ -#define SIGEV_MAX_SIZE 64 -#ifndef SIGEV_PAD_SIZE -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3) +/* + * This works because the alignment is ok on all current architectures + * but we leave open this being overridden in the future + */ +#ifndef __ARCH_SIGEV_PREAMBLE_SIZE +#define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(int) * 2 + sizeof(sigval_t)) #endif +#define SIGEV_MAX_SIZE 64 +#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE - __ARCH_SIGEV_PREAMBLE_SIZE) \ + / sizeof(int)) + typedef struct sigevent { sigval_t sigev_value; int sigev_signo; diff --git a/include/asm-ia64/siginfo.h b/include/asm-ia64/siginfo.h index d55f139..9294e4b 100644 --- a/include/asm-ia64/siginfo.h +++ b/include/asm-ia64/siginfo.h @@ -8,9 +8,7 @@ * David Mosberger-Tang , Hewlett-Packard Co */ -#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 4) - -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4) +#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) #define HAVE_ARCH_SIGINFO_T #define HAVE_ARCH_COPY_SIGINFO diff --git a/include/asm-mips/siginfo.h b/include/asm-mips/siginfo.h index 8ddd3c9..a0e26e6 100644 --- a/include/asm-mips/siginfo.h +++ b/include/asm-mips/siginfo.h @@ -11,8 +11,6 @@ #include -#define SIGEV_HEAD_SIZE (sizeof(long) + 2*sizeof(int)) -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE-SIGEV_HEAD_SIZE) / sizeof(int)) #undef __ARCH_SI_TRAPNO /* exception code needs to fill this ... */ #define HAVE_ARCH_SIGINFO_T diff --git a/include/asm-s390/siginfo.h b/include/asm-s390/siginfo.h index 7230353..e0ff1ab 100644 --- a/include/asm-s390/siginfo.h +++ b/include/asm-s390/siginfo.h @@ -13,12 +13,6 @@ #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) #endif -#ifdef CONFIG_ARCH_S390X -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4) -#else -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3) -#endif - #include #endif diff --git a/include/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h index 7160449..df17e47 100644 --- a/include/asm-sparc64/siginfo.h +++ b/include/asm-sparc64/siginfo.h @@ -3,8 +3,6 @@ #define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4) - #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) #define __ARCH_SI_TRAPNO #define __ARCH_SI_BAND_T int diff --git a/include/asm-x86_64/siginfo.h b/include/asm-x86_64/siginfo.h index 7bc1598..d09a1e6 100644 --- a/include/asm-x86_64/siginfo.h +++ b/include/asm-x86_64/siginfo.h @@ -3,8 +3,6 @@ #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4) - #include #endif -- cgit v0.10.2 From e49332bd12e92da2df6d002f857ec62675ba2648 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 1 May 2005 08:59:08 -0700 Subject: [PATCH] misc verify_area cleanups There were still a few comments left refering to verify_area, and two functions, verify_area_skas & verify_area_tt that just wrap corresponding access_ok_skas & access_ok_tt functions, just like verify_area does for access_ok - deprecate those. There was also a few places that still used verify_area in commented-out code, fix those up to use access_ok. After applying this one there should not be anything left but finally removing verify_area completely, which will happen after a kernel release or two. Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index d3b4c54..ec0f68c 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -222,7 +222,7 @@ asmlinkage int sys_vm86(struct pt_regs regs) goto out; case VM86_PLUS_INSTALL_CHECK: /* NOTE: on old vm86 stuff this will return the error - from verify_area(), because the subfunction is + from access_ok(), because the subfunction is interpreted as (invalid) address to vm86_struct. So the installation check works. */ diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h index 11986c9..c356203 100644 --- a/arch/um/kernel/skas/include/uaccess-skas.h +++ b/arch/um/kernel/skas/include/uaccess-skas.h @@ -18,7 +18,7 @@ ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \ ((unsigned long) (addr) + (size) >= (unsigned long)(addr)))) -static inline int verify_area_skas(int type, const void * addr, +static inline int __deprecated verify_area_skas(int type, const void * addr, unsigned long size) { return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h index f0bad01..bb69d6b 100644 --- a/arch/um/kernel/tt/include/uaccess-tt.h +++ b/arch/um/kernel/tt/include/uaccess-tt.h @@ -33,7 +33,7 @@ extern unsigned long uml_physmem; (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ (under_task_size(addr, size) || is_stack(addr, size)))) -static inline int verify_area_tt(int type, const void * addr, +static inline int __deprecated verify_area_tt(int type, const void * addr, unsigned long size) { return(access_ok_tt(type, addr, size) ? 0 : -EFAULT); diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index 903e4c3..a229915 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -52,7 +52,7 @@ #define KERNEL #include #include -#include /* for verify_area */ +#include #include /* for -EBUSY */ #include /* for request_region */ #include /* for loops_per_jiffy */ diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index c789d5c..50e0b61 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -1987,10 +1987,9 @@ static inline int sx_set_serial_info(struct specialix_port * port, func_enter(); /* - error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp)); - if (error) { + if (!access_ok(VERIFY_READ, (void *) newinfo, sizeof(tmp))) { func_exit(); - return error; + return -EFAULT; } */ if (copy_from_user(&tmp, newinfo, sizeof(tmp))) { @@ -2046,14 +2045,12 @@ static inline int sx_get_serial_info(struct specialix_port * port, { struct serial_struct tmp; struct specialix_board *bp = port_Board(port); - // int error; func_enter(); /* - error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)); - if (error) - return error; + if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp))) + return -EFAULT; */ memset(&tmp, 0, sizeof(tmp)); diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h index 3c6d42a..d0a9c2f 100644 --- a/include/asm-frv/pgtable.h +++ b/include/asm-frv/pgtable.h @@ -349,9 +349,9 @@ static inline pmd_t *pmd_offset(pud_t *dir, unsigned long address) /* * Define this to warn about kernel memory accesses that are - * done without a 'verify_area(VERIFY_WRITE,..)' + * done without a 'access_ok(VERIFY_WRITE,..)' */ -#undef TEST_VERIFY_AREA +#undef TEST_ACCESS_OK #define pte_present(x) (pte_val(x) & _PAGE_PRESENT) #define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) diff --git a/include/asm-i386/checksum.h b/include/asm-i386/checksum.h index d76a5f0..6413420 100644 --- a/include/asm-i386/checksum.h +++ b/include/asm-i386/checksum.h @@ -33,7 +33,7 @@ asmlinkage unsigned int csum_partial_copy_generic(const unsigned char *src, unsi * passed in an incorrect kernel address to one of these functions. * * If you use these functions directly please don't forget the - * verify_area(). + * access_ok(). */ static __inline__ unsigned int csum_partial_copy_nocheck (const unsigned char *src, unsigned char *dst, diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 5c72542..8d60c2b 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -193,9 +193,9 @@ extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; /* * Define this if things work differently on an i386 and an i486: * it will (on an i486) warn about kernel memory accesses that are - * done without a 'verify_area(VERIFY_WRITE,..)' + * done without a 'access_ok(VERIFY_WRITE,..)' */ -#undef TEST_VERIFY_AREA +#undef TEST_ACCESS_OK /* The boot page tables (all created as a single array) */ extern unsigned long pg0[]; diff --git a/include/asm-parisc/uaccess.h b/include/asm-parisc/uaccess.h index 8a08423..c1b5bde 100644 --- a/include/asm-parisc/uaccess.h +++ b/include/asm-parisc/uaccess.h @@ -24,7 +24,7 @@ /* * Note that since kernel addresses are in a separate address space on - * parisc, we don't need to do anything for access_ok() or verify_area(). + * parisc, we don't need to do anything for access_ok(). * We just let the page fault handler do the right thing. This also means * that put_user is the same as __put_user, etc. */ diff --git a/include/asm-sh/checksum.h b/include/asm-sh/checksum.h index 5113c7f..5ebd0f2 100644 --- a/include/asm-sh/checksum.h +++ b/include/asm-sh/checksum.h @@ -42,7 +42,7 @@ asmlinkage unsigned int csum_partial_copy_generic(const unsigned char *src, unsi * passed in an incorrect kernel address to one of these functions. * * If you use these functions directly please don't forget the - * verify_area(). + * access_ok(). */ static __inline__ unsigned int csum_partial_copy_nocheck (const unsigned char *src, unsigned char *dst, diff --git a/include/asm-sh64/checksum.h b/include/asm-sh64/checksum.h index aa3911a..fd034e9 100644 --- a/include/asm-sh64/checksum.h +++ b/include/asm-sh64/checksum.h @@ -34,7 +34,7 @@ asmlinkage unsigned int csum_partial(const unsigned char *buff, int len, * passed in an incorrect kernel address to one of these functions. * * If you use these functions directly please don't forget the - * verify_area(). + * access_ok(). */ diff --git a/include/asm-sparc/uaccess.h b/include/asm-sparc/uaccess.h index 3f47889..f461144 100644 --- a/include/asm-sparc/uaccess.h +++ b/include/asm-sparc/uaccess.h @@ -18,7 +18,7 @@ #ifndef __ASSEMBLY__ -/* Sparc is not segmented, however we need to be able to fool verify_area() +/* Sparc is not segmented, however we need to be able to fool access_ok() * when doing system calls from kernel mode legitimately. * * "For historical reasons, these macros are grossly misnamed." -Linus diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index c32d27a..7b214cf 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -23,7 +23,7 @@ #include /* return codes */ #include #include /* kmalloc(), kfree() */ -#include /* verify_area(), etc. */ +#include #include /* inline mem*, str* functions */ #include /* __initfunc et al. */ #include /* htons(), etc. */ diff --git a/net/atm/common.c b/net/atm/common.c index 6d16be3..e93e838 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -12,7 +12,7 @@ #include /* SOL_SOCKET */ #include /* error codes */ #include -#include /* verify_area */ +#include #include #include /* struct timeval */ #include @@ -540,7 +540,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, error = -EMSGSIZE; goto out; } - /* verify_area is done by net/socket.c */ + eff = (size+3) & ~3; /* align to word boundary */ prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); error = 0; diff --git a/net/core/iovec.c b/net/core/iovec.c index d57ace9..65e4b56 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -33,7 +33,7 @@ * Verify iovec. The caller must ensure that the iovec is big enough * to hold the message iovec. * - * Save time not doing verify_area. copy_*_user will make this work + * Save time not doing access_ok. copy_*_user will make this work * in any case. */ diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 956c17f..d6844ac 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -48,8 +48,8 @@ #include #include #include /* support for loadable modules */ -#include /* kmalloc(), kfree() */ -#include /* verify_area(), etc. */ +#include /* kmalloc(), kfree() */ +#include #include /* inline mem*, str* functions */ #include /* htons(), etc. */ -- cgit v0.10.2 From f78fc874f42f63a460bcebc2aeb98db526280d1c Mon Sep 17 00:00:00 2001 From: Vinay K Nallamothu Date: Sun, 1 May 2005 08:59:09 -0700 Subject: [PATCH] __attribute__ placement fixes The variable attributes "packed" and "align" when used with struct, should have the following order: struct ... {...} __attribute__((packed)) var; This patch fixes few instances where the variable and attributes are placed the other way around and had no effect. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/net/gt96100eth.h b/drivers/net/gt96100eth.h index 2f4bfd4..395869c 100644 --- a/drivers/net/gt96100eth.h +++ b/drivers/net/gt96100eth.h @@ -214,7 +214,7 @@ typedef struct { u32 cmdstat; u32 next; u32 buff_ptr; -} gt96100_td_t __attribute__ ((packed)); +} __attribute__ ((packed)) gt96100_td_t; typedef struct { #ifdef DESC_BE @@ -227,7 +227,7 @@ typedef struct { u32 cmdstat; u32 next; u32 buff_ptr; -} gt96100_rd_t __attribute__ ((packed)); +} __attribute__ ((packed)) gt96100_rd_t; /* Values for the Tx command-status descriptor entry. */ diff --git a/include/asm-m68knommu/MC68328.h b/include/asm-m68knommu/MC68328.h index 4f5a984..a337e56 100644 --- a/include/asm-m68knommu/MC68328.h +++ b/include/asm-m68knommu/MC68328.h @@ -993,7 +993,7 @@ typedef volatile struct { volatile unsigned short int pad1; volatile unsigned short int pad2; volatile unsigned short int pad3; -} m68328_uart __attribute__((packed)); +} __attribute__((packed)) m68328_uart; /********** diff --git a/include/asm-m68knommu/MC68EZ328.h b/include/asm-m68knommu/MC68EZ328.h index 801933d..69b7f91 100644 --- a/include/asm-m68knommu/MC68EZ328.h +++ b/include/asm-m68knommu/MC68EZ328.h @@ -815,7 +815,7 @@ typedef volatile struct { volatile unsigned short int nipr; volatile unsigned short int pad1; volatile unsigned short int pad2; -} m68328_uart __attribute__((packed)); +} __attribute__((packed)) m68328_uart; /********** diff --git a/include/asm-m68knommu/MC68VZ328.h b/include/asm-m68knommu/MC68VZ328.h index df74322..2b9bf62 100644 --- a/include/asm-m68knommu/MC68VZ328.h +++ b/include/asm-m68knommu/MC68VZ328.h @@ -909,7 +909,7 @@ typedef struct { volatile unsigned short int nipr; volatile unsigned short int hmark; volatile unsigned short int unused; -} m68328_uart __attribute__((packed)); +} __attribute__((packed)) m68328_uart; -- cgit v0.10.2 From 439bd3708792e31057db424d1165473122d531a3 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Sun, 1 May 2005 08:59:09 -0700 Subject: [PATCH] Leadtek Winfast remote controls Add missing button codes for the Leadtek Winfast remote controls. Signed-off-by: Nicolas Boichat Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c index 8c842e2..84a49d2 100644 --- a/drivers/media/common/ir-common.c +++ b/drivers/media/common/ir-common.c @@ -131,10 +131,10 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { [ 18 ] = KEY_KP0, [ 0 ] = KEY_POWER, -// [ 27 ] = MTS button + [ 27 ] = KEY_LANGUAGE, //MTS button [ 2 ] = KEY_TUNER, // TV/FM [ 30 ] = KEY_VIDEO, -// [ 22 ] = display button + [ 22 ] = KEY_INFO, //display button [ 4 ] = KEY_VOLUMEUP, [ 8 ] = KEY_VOLUMEDOWN, [ 12 ] = KEY_CHANNELUP, @@ -142,7 +142,7 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { [ 3 ] = KEY_ZOOM, // fullscreen [ 31 ] = KEY_SUBTITLE, // closed caption/teletext [ 32 ] = KEY_SLEEP, -// [ 41 ] = boss key + [ 41 ] = KEY_SEARCH, //boss key [ 20 ] = KEY_MUTE, [ 43 ] = KEY_RED, [ 44 ] = KEY_GREEN, @@ -150,17 +150,17 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { [ 46 ] = KEY_BLUE, [ 24 ] = KEY_KPPLUS, //fine tune + [ 25 ] = KEY_KPMINUS, //fine tune - -// [ 42 ] = picture in picture - [ 33 ] = KEY_KPDOT, + [ 42 ] = KEY_ANGLE, //picture in picture + [ 33 ] = KEY_KPDOT, [ 19 ] = KEY_KPENTER, -// [ 17 ] = recall + [ 17 ] = KEY_AGAIN, //recall [ 34 ] = KEY_BACK, [ 35 ] = KEY_PLAYPAUSE, [ 36 ] = KEY_NEXT, -// [ 37 ] = time shifting + [ 37 ] = KEY_T, //time shifting [ 38 ] = KEY_STOP, - [ 39 ] = KEY_RECORD -// [ 40 ] = snapshot + [ 39 ] = KEY_RECORD, + [ 40 ] = KEY_SHUFFLE //snapshot }; EXPORT_SYMBOL_GPL(ir_codes_winfast); -- cgit v0.10.2 From 74f9f974a64dc3de554aa1977bf108334436e47b Mon Sep 17 00:00:00 2001 From: Edward Shishkin Date: Sun, 1 May 2005 08:59:09 -0700 Subject: [PATCH] reiserfs: journal_init fix This fixes segmentation fault when specifying bad journal device via a mount option. Don't pass a zero pointer to bdevname() if filp_open() returns error. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index c9ad3a7..b16d65a 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2306,13 +2306,16 @@ static int journal_init_dev( struct super_block *super, if( !IS_ERR( journal -> j_dev_file ) ) { struct inode *jdev_inode = journal->j_dev_file->f_mapping->host; if( !S_ISBLK( jdev_inode -> i_mode ) ) { - reiserfs_warning (super, "journal_init_dev: '%s' is " - "not a block device", jdev_name ); + reiserfs_warning(super, "journal_init_dev: '%s' is " + "not a block device", jdev_name ); result = -ENOTBLK; + release_journal_dev( super, journal ); } else { /* ok */ journal->j_dev_bd = I_BDEV(jdev_inode); set_blocksize(journal->j_dev_bd, super->s_blocksize); + reiserfs_info(super, "journal_init_dev: journal device: %s\n", + bdevname(journal->j_dev_bd, b)); } } else { result = PTR_ERR( journal -> j_dev_file ); @@ -2321,11 +2324,6 @@ static int journal_init_dev( struct super_block *super, "journal_init_dev: Cannot open '%s': %i", jdev_name, result ); } - if( result != 0 ) { - release_journal_dev( super, journal ); - } - reiserfs_info(super, "journal_init_dev: journal device: %s\n", - bdevname(journal->j_dev_bd, b)); return result; } -- cgit v0.10.2 From 5717ffbe16815db229a66fee824c2190cb306734 Mon Sep 17 00:00:00 2001 From: "aquynh@gmail.com" Date: Sun, 1 May 2005 08:59:10 -0700 Subject: [PATCH] dontdiff file sorted in alphabet order Documentation/dontdiff is a little messy. Here is a patch to sort the content of that file in alphabetical Signed-off-by: Nguyen Anh Quynh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/dontdiff b/Documentation/dontdiff index 734fcc8..7c24964 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -1,137 +1,137 @@ -.* +*.a +*.aux +*.bin +*.cpio +*.css +*.dvi +*.eps +*.gif +*.grep +*.grp +*.gz +*.html +*.jpeg +*.ko +*.log +*.lst +*.mod.c +*.o +*.orig +*.out +*.pdf +*.png +*.ps +*.rej +*.s +*.sgml +*.so +*.tex +*.ver +*_MODULES +*_vga16.c +*cscope* *~ +.* +.cscope +53c700_d.h 53c8xx_d.h* -*.a +BitKeeper +COPYING +CREDITS +CVS +ChangeSet +Kerntypes +MODS.txt +Module.symvers +PENDING +SCCS +System.map* +TAGS aic7*reg.h* -aic7*seq.h* aic7*reg_print.c* -53c700_d.h +aic7*seq.h* aicasm aicdb.h* asm asm_offsets.* autoconf.h* -*.aux bbootsect -*.bin bin2c binkernel.spec -BitKeeper bootsect bsetup btfixupprep build bvmlinux bzImage* -ChangeSet classlist.h* -compile.h* comp*.log +compile.h* config config-* config_data.h* conmakehash consolemap_deftbl.c* -COPYING -CREDITS -.cscope -*cscope* +crc32table.h* cscope.* -*.out -*.css -CVS defkeymap.c* devlist.h* docproc dummy_sym.c* -*.dvi -*.eps +elfconfig.h* filelist fixdep fore200e_mkfirm fore200e_pca_fw.c* gen-devlist -gen_init_cpio -gen_crc32table -crc32table.h* -*.cpio gen-kdb_cmds.c* -gentbl +gen_crc32table +gen_init_cpio genksyms -*.gif -*.gz -*.html +gentbl ikconfig.h* initramfs_list -*.jpeg +kallsyms kconfig kconfig.tk -Kerntypes keywords.c* ksym.c* ksym.h* -kallsyms -mk_elfconfig -elfconfig.h* -modpost -pnmtologo -logo_*.c -*.log lex.c* +logo_*.c logo_*_clut224.c logo_*_mono.c lxdialog make_times_h map +maui_boot.h +mk_elfconfig mkdep -*_MODULES -MODS.txt +mktables +modpost modversions.h* -Module.symvers -*.mod.c -*.o -*.ko -*.orig -*.lst -*.grp -*.grep oui.c* -mktables -raid6tables.c -raid6int*.c -raid6altivec*.c -wanxlfw.inc -maui_boot.h -pss_boot.h -trix_boot.h -*.pdf parse.c* parse.h* -PENDING +pnmtologo ppc_defs.h* promcon_tbl.c* -*.png -*.ps -*.rej -SCCS +pss_boot.h +raid6altivec*.c +raid6int*.c +raid6tables.c setup -*.s -*.so -*.sgml sim710_d.h* sm_tbl* split-include -System.map* tags -TAGS -*.tex times.h* tkparse -*.ver +trix_boot.h version.h* -*_vga16.c vmlinux -vmlinux.lds vmlinux-* +vmlinux.lds vsyscall.lds +wanxlfw.inc zImage -- cgit v0.10.2 From 9206880198589670dfc33feb9d2e903c3492701f Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 1 May 2005 08:59:10 -0700 Subject: [PATCH] IPMI: fix for handling bad IPMI DMI data Ignore the bottom bit of the base address from the DMI data. It is supposed to be set to 1 if it is I/O space. Few systems do this, but this enables the ones that do set it to work properly. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 44a7f13..3522723 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1623,7 +1623,13 @@ static int decode_dmi(dmi_header_t *dm, int intf_num) } } else { /* Old DMI spec. */ - ipmi_data->base_addr = base_addr; + /* Note that technically, the lower bit of the base + * address should be 1 if the address is I/O and 0 if + * the address is in memory. So many systems get that + * wrong (and all that I have seen are I/O) so we just + * ignore that bit and assume I/O. Systems that use + * memory should use the newer spec, anyway. */ + ipmi_data->base_addr = base_addr & 0xfffe; ipmi_data->addr_space = IPMI_IO_ADDR_SPACE; ipmi_data->offset = 1; } -- cgit v0.10.2 From 35bc37a0e0979a091bcf5d9161ffe935b3aa998c Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 1 May 2005 08:59:10 -0700 Subject: [PATCH] IPMI: fix for handling bad ACPI data If the ACPI register bit width is zero (an invalid value) assume it is the default spacing. This avoids some coredumps on invalid data and makes some systems work that have broken ACPI data. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 3522723..7522bd5 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1526,8 +1526,17 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info) info->irq_setup = NULL; } - regspacings[intf_num] = spmi->addr.register_bit_width / 8; - info->io.regspacing = spmi->addr.register_bit_width / 8; + if (spmi->addr.register_bit_width) { + /* A (hopefully) properly formed register bit width. */ + regspacings[intf_num] = spmi->addr.register_bit_width / 8; + info->io.regspacing = spmi->addr.register_bit_width / 8; + } else { + /* Some broken systems get this wrong and set the value + * to zero. Assume it is the default spacing. If that + * is wrong, too bad, the vendor should fix the tables. */ + regspacings[intf_num] = DEFAULT_REGSPACING; + info->io.regspacing = DEFAULT_REGSPACING; + } regsizes[intf_num] = regspacings[intf_num]; info->io.regsize = regsizes[intf_num]; regshifts[intf_num] = spmi->addr.register_bit_offset; -- cgit v0.10.2 From ec26d79f4f5822283e0bffa44a542fd13c5146e4 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 1 May 2005 08:59:11 -0700 Subject: [PATCH] ipmi: fix watchdog so the device can be reopened on an unexpected close If there is an unexpected close, still allow the watchdog interface to be re-opened on the IPMI watchdog. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index fd70938..fcd1c02 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -709,11 +709,11 @@ static int ipmi_close(struct inode *ino, struct file *filep) if (expect_close == 42) { ipmi_watchdog_state = WDOG_TIMEOUT_NONE; ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); - clear_bit(0, &ipmi_wdog_open); } else { printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); ipmi_heartbeat(); } + clear_bit(0, &ipmi_wdog_open); } ipmi_fasync (-1, filep, 0); -- cgit v0.10.2 From 9dbf68f97d585265eaadd15aea308efd9ae39d34 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 1 May 2005 08:59:11 -0700 Subject: [PATCH] ipmi: enable interrupts on the BT driver Enable interrupts for a BT interface. There is a specific register that needs to be set up to enable interrupts that also must be modified to clear the irq. Also, don't reset the BMC on a BT interface. That's probably not a good idea as the BMC may be performing other important functions and a reset should only be a last resort. Also, that register is also used to enable/disable interrupts to the BT; modifying it may screw up the interrupts. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 225b330..5ce9c62 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -235,7 +235,6 @@ static void reset_flags(struct si_sm_data *bt) if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY); BT_CONTROL(BT_CLR_WR_PTR); BT_CONTROL(BT_SMS_ATN); - BT_INTMASK_W(BT_BMC_HWRST); #ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION if (BT_STATUS & BT_B2H_ATN) { int i; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 7522bd5..5419440 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -100,6 +100,11 @@ enum si_intf_state { /* FIXME - add watchdog stuff. */ }; +/* Some BT-specific defines we need here. */ +#define IPMI_BT_INTMASK_REG 2 +#define IPMI_BT_INTMASK_CLEAR_IRQ_BIT 2 +#define IPMI_BT_INTMASK_ENABLE_IRQ_BIT 1 + enum si_type { SI_KCS, SI_SMIC, SI_BT }; @@ -875,6 +880,17 @@ static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs) return IRQ_HANDLED; } +static irqreturn_t si_bt_irq_handler(int irq, void *data, struct pt_regs *regs) +{ + struct smi_info *smi_info = data; + /* We need to clear the IRQ flag for the BT interface. */ + smi_info->io.outputb(&smi_info->io, IPMI_BT_INTMASK_REG, + IPMI_BT_INTMASK_CLEAR_IRQ_BIT + | IPMI_BT_INTMASK_ENABLE_IRQ_BIT); + return si_irq_handler(irq, data, regs); +} + + static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, @@ -1001,11 +1017,22 @@ static int std_irq_setup(struct smi_info *info) if (!info->irq) return 0; - rv = request_irq(info->irq, - si_irq_handler, - SA_INTERRUPT, - DEVICE_NAME, - info); + if (info->si_type == SI_BT) { + rv = request_irq(info->irq, + si_bt_irq_handler, + SA_INTERRUPT, + DEVICE_NAME, + info); + if (!rv) + /* Enable the interrupt in the BT interface. */ + info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, + IPMI_BT_INTMASK_ENABLE_IRQ_BIT); + } else + rv = request_irq(info->irq, + si_irq_handler, + SA_INTERRUPT, + DEVICE_NAME, + info); if (rv) { printk(KERN_WARNING "ipmi_si: %s unable to claim interrupt %d," @@ -1024,6 +1051,9 @@ static void std_irq_cleanup(struct smi_info *info) if (!info->irq) return; + if (info->si_type == SI_BT) + /* Disable the interrupt in the BT interface. */ + info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, 0); free_irq(info->irq, info); } -- cgit v0.10.2 From 882fe011a92fa4fc31ca6cc95b279f7e4e52935c Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 1 May 2005 08:59:12 -0700 Subject: [PATCH] ipmi: fix a deadlock Correct an issue with the IPMI message layer taking a lock and calling lower layer driver. If an error occrues at the lower layer the lock can be taken again causing a deadlock. The lock is released before calling the lower layer. Signed-off-by: David Griego Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index a6606a1..d7fb452 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2588,28 +2588,20 @@ handle_msg_timeout(struct ipmi_recv_msg *msg) deliver_response(msg); } -static void -send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, - struct ipmi_smi_msg *smi_msg, - unsigned char seq, long seqid) +static struct ipmi_smi_msg * +smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, + unsigned char seq, long seqid) { - if (!smi_msg) - smi_msg = ipmi_alloc_smi_msg(); + struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg(); if (!smi_msg) /* If we can't allocate the message, then just return, we get 4 retries, so this should be ok. */ - return; + return NULL; memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len); smi_msg->data_size = recv_msg->msg.data_len; smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid); - /* Send the new message. We send with a zero priority. It - timed out, I doubt time is that critical now, and high - priority messages are really only for messages to the local - MC, which don't get resent. */ - intf->handlers->sender(intf->send_info, smi_msg, 0); - #ifdef DEBUG_MSGING { int m; @@ -2619,6 +2611,7 @@ send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, printk("\n"); } #endif + return smi_msg; } static void @@ -2683,14 +2676,13 @@ ipmi_timeout_handler(long timeout_period) intf->timed_out_ipmb_commands++; spin_unlock(&intf->counter_lock); } else { + struct ipmi_smi_msg *smi_msg; /* More retries, send again. */ /* Start with the max timer, set to normal timer after the message is sent. */ ent->timeout = MAX_MSG_TIMEOUT; ent->retries_left--; - send_from_recv_msg(intf, ent->recv_msg, NULL, - j, ent->seqid); spin_lock(&intf->counter_lock); if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) @@ -2698,6 +2690,20 @@ ipmi_timeout_handler(long timeout_period) else intf->retransmitted_ipmb_commands++; spin_unlock(&intf->counter_lock); + smi_msg = smi_from_recv_msg(intf, + ent->recv_msg, j, ent->seqid); + if(!smi_msg) + continue; + + spin_unlock_irqrestore(&(intf->seq_lock),flags); + /* Send the new message. We send with a zero + * priority. It timed out, I doubt time is + * that critical now, and high priority + * messages are really only for messages to the + * local MC, which don't get resent. */ + intf->handlers->sender(intf->send_info, + smi_msg, 0); + spin_lock_irqsave(&(intf->seq_lock), flags); } } spin_unlock_irqrestore(&(intf->seq_lock), flags); -- cgit v0.10.2 From 434498d5323445b59167fd7aa5633b74ebbce901 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Sun, 1 May 2005 08:59:12 -0700 Subject: [PATCH] sn_console: make sal_console_uart static again Signed-off-by: Andreas Schwab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index ffaab9b..fee6418 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -787,7 +787,7 @@ static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port) static void sn_sal_console_write(struct console *, const char *, unsigned); static int __init sn_sal_console_setup(struct console *, char *); -extern struct uart_driver sal_console_uart; +static struct uart_driver sal_console_uart; extern struct tty_driver *uart_console_device(struct console *, int *); static struct console sal_console = { @@ -801,7 +801,7 @@ static struct console sal_console = { #define SAL_CONSOLE &sal_console -struct uart_driver sal_console_uart = { +static struct uart_driver sal_console_uart = { .owner = THIS_MODULE, .driver_name = "sn_console", .dev_name = DEVICE_NAME, -- cgit v0.10.2 From 7d87e14c236d6c4cab66d87cf0bc1e0f0375d308 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Sun, 1 May 2005 08:59:12 -0700 Subject: [PATCH] consolidate sys_shmat Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index b5d0fd2..64e450d 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -457,22 +457,6 @@ osf_getdomainname(char __user *name, int namelen) return 0; } -asmlinkage long -osf_shmat(int shmid, void __user *shmaddr, int shmflg) -{ - unsigned long raddr; - long err; - - err = do_shmat(shmid, shmaddr, shmflg, &raddr); - - /* - * This works because all user-level addresses are - * non-negative longs! - */ - return err ? err : (long)raddr; -} - - /* * The following stuff should move into a header file should it ever * be labeled "officially supported." Right now, there is just enough diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S index 3864b33..0521208 100644 --- a/arch/alpha/kernel/systbls.S +++ b/arch/alpha/kernel/systbls.S @@ -227,7 +227,7 @@ sys_call_table: .quad sys_semop .quad osf_utsname .quad sys_lchown - .quad osf_shmat + .quad sys_shmat .quad sys_shmctl /* 210 */ .quad sys_shmdt .quad sys_shmget diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index 7ba6342..ef32577 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c @@ -227,18 +227,6 @@ asmlinkage int sys_ipc(uint call, int first, int second, int third, } } -asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg, - unsigned long __user *addr) -{ - unsigned long ret; - long err; - - err = do_shmat(shmid, shmaddr, shmflg, &ret); - if (err == 0) - err = put_user(ret, addr); - return err; -} - /* Fork a new task - this creates a new program thread. * This is called indirectly via a small wrapper */ diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index bd86fea..d3f0938 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1417,7 +1417,7 @@ sys_call_table: data8 sys_msgrcv data8 sys_msgctl data8 sys_shmget - data8 ia64_shmat + data8 sys_shmat data8 sys_shmdt // 1115 data8 sys_shmctl data8 sys_syslog diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index 3ac216e..a8cf6d8 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -93,20 +93,6 @@ sys_getpagesize (void) } asmlinkage unsigned long -ia64_shmat (int shmid, void __user *shmaddr, int shmflg) -{ - unsigned long raddr; - int retval; - - retval = do_shmat(shmid, shmaddr, shmflg, &raddr); - if (retval < 0) - return retval; - - force_successful_syscall_return(); - return raddr; -} - -asmlinkage unsigned long ia64_brk (unsigned long brk) { unsigned long rlim, retval, newbrk, oldbrk; diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 598bfe7..ae2a131 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -374,22 +374,6 @@ asmlinkage int sys_ipc (uint call, int first, int second, } /* - * Native ABI that is O32 or N64 version - */ -asmlinkage long sys_shmat(int shmid, char __user *shmaddr, - int shmflg, unsigned long *addr) -{ - unsigned long raddr; - int err; - - err = do_shmat(shmid, shmaddr, shmflg, &raddr); - if (err) - return err; - - return put_user(raddr, addr); -} - -/* * No implemented yet ... */ asmlinkage int sys_cachectl(char *addr, int nbytes, int op) diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 7958cd8..d15a1d5 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -161,17 +161,6 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, } } -long sys_shmat_wrapper(int shmid, char __user *shmaddr, int shmflag) -{ - unsigned long raddr; - int r; - - r = do_shmat(shmid, shmaddr, shmflag, &raddr); - if (r < 0) - return r; - return raddr; -} - /* Fucking broken ABI */ #ifdef CONFIG_64BIT diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 779b537..dcfa4d3 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -297,7 +297,7 @@ ENTRY_DIFF(msgrcv) ENTRY_SAME(msgget) /* 190 */ ENTRY_SAME(msgctl) - ENTRY_SAME(shmat_wrapper) + ENTRY_SAME(shmat) ENTRY_SAME(shmdt) ENTRY_SAME(shmget) ENTRY_SAME(shmctl) /* 195 */ diff --git a/arch/sh64/kernel/sys_sh64.c b/arch/sh64/kernel/sys_sh64.c index 4546845..58ff7d5 100644 --- a/arch/sh64/kernel/sys_sh64.c +++ b/arch/sh64/kernel/sys_sh64.c @@ -283,18 +283,3 @@ asmlinkage int sys_uname(struct old_utsname * name) up_read(&uts_sem); return err?-EFAULT:0; } - -/* Copy from mips version */ -asmlinkage long sys_shmatcall(int shmid, char __user *shmaddr, - int shmflg) -{ - unsigned long raddr; - int err; - - err = do_shmat(shmid, shmaddr, shmflg, &raddr); - if (err) - return err; - - err = raddr; - return err; -} diff --git a/arch/sh64/kernel/syscalls.S b/arch/sh64/kernel/syscalls.S index 8ed417d..6aabc63 100644 --- a/arch/sh64/kernel/syscalls.S +++ b/arch/sh64/kernel/syscalls.S @@ -268,7 +268,7 @@ sys_call_table: .long sys_msgrcv .long sys_msgget .long sys_msgctl - .long sys_shmatcall + .long sys_shmat .long sys_shmdt /* 245 */ .long sys_shmget .long sys_shmctl diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h index b56b335..67923cc 100644 --- a/arch/um/include/sysdep-x86_64/syscalls.h +++ b/arch/um/include/sysdep-x86_64/syscalls.h @@ -26,7 +26,6 @@ extern syscall_handler_t *ia32_sys_call_table[]; extern long old_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff); -extern syscall_handler_t wrap_sys_shmat; extern syscall_handler_t sys_modify_ldt; extern syscall_handler_t sys_arch_prctl; diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index 15768c9..ab4b0ab 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c @@ -14,14 +14,6 @@ #include "asm/prctl.h" /* XXX This should get the constants from libc */ #include "choose-mode.h" -/* XXX: copied from x86-64: arch/x86_64/kernel/sys_x86_64.c */ -asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg) -{ - unsigned long raddr; - - return do_shmat(shmid, shmaddr, shmflg, &raddr) ?: (long) raddr; -} - asmlinkage long sys_uname64(struct new_utsname __user * name) { int err; diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c index 477d8be..dbebd5c 100644 --- a/arch/x86_64/kernel/sys_x86_64.c +++ b/arch/x86_64/kernel/sys_x86_64.c @@ -152,12 +152,6 @@ asmlinkage long sys_uname(struct new_utsname __user * name) return err ? -EFAULT : 0; } -asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg) -{ - unsigned long raddr; - return do_shmat(shmid,shmaddr,shmflg,&raddr) ?: (long)raddr; -} - asmlinkage long sys_time64(long __user * tloc) { struct timeval now; diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index 3d65d24..3c9af6f 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -76,7 +76,7 @@ __SYSCALL(__NR_madvise, sys_madvise) #define __NR_shmget 29 __SYSCALL(__NR_shmget, sys_shmget) #define __NR_shmat 30 -__SYSCALL(__NR_shmat, wrap_sys_shmat) +__SYSCALL(__NR_shmat, sys_shmat) #define __NR_shmctl 31 __SYSCALL(__NR_shmctl, sys_shmctl) diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 757cd9b..c39f6f7 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -456,8 +456,7 @@ asmlinkage long sys_semctl(int semid, int semnum, int cmd, union semun arg); asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, unsigned nsops, const struct timespec __user *timeout); -asmlinkage long sys_shmat(int shmid, char __user *shmaddr, - int shmflg, unsigned long __user *addr); +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); diff --git a/ipc/shm.c b/ipc/shm.c index 06cd5c91..cce02243 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -28,6 +28,8 @@ #include #include #include +#include + #include #include "util.h" @@ -771,6 +773,18 @@ out: return err; } +asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg) +{ + unsigned long ret; + long err; + + err = do_shmat(shmid, shmaddr, shmflg, &ret); + if (err) + return err; + force_successful_syscall_return(); + return (long)ret; +} + /* * detach and kill segment if marked destroyed. * The work is done in shm_close. diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 1802a31..0dda70e 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -52,6 +52,7 @@ cond_syscall(sys_msgsnd); cond_syscall(sys_msgrcv); cond_syscall(sys_msgctl); cond_syscall(sys_shmget); +cond_syscall(sys_shmat); cond_syscall(sys_shmdt); cond_syscall(sys_shmctl); cond_syscall(sys_mq_open); -- cgit v0.10.2 From 1c72d46d98e4eb16f1a1b38eba94cc3aa8022cfa Mon Sep 17 00:00:00 2001 From: Kylene Hall Date: Sun, 1 May 2005 08:59:13 -0700 Subject: [PATCH] Fix Tpm driver -- Maintainers entry This patch adds the maintainers entry. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index 4333b69..f384a97 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2113,6 +2113,13 @@ M: perex@suse.cz L: alsa-devel@alsa-project.org S: Maintained +TPM DEVICE DRIVER +P: Kylene Hall +M: kjhall@us.ibm.com +W: http://tpmdd.sourceforge.net +L: tpmdd-devel@lists.sourceforge.net +S: Maintained + UltraSPARC (sparc64): P: David S. Miller M: davem@davemloft.net -- cgit v0.10.2 From e5bdd883a189243541e7a132385580703b049102 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 1 May 2005 08:59:13 -0700 Subject: [PATCH] new valid_signal() function This patch adds a new function valid_signal() that tests if its argument is a valid signal number. The reasons for adding this new function are: - some code currently testing _NSIG directly has off-by-one errors. Using this function instead avoids such errors. - some code currently tests unsigned signal numbers for <0 which is pointless and generates warnings when building with gcc -W. Using this function instead avoids such warnings. I considered various places to add this function but eventually settled on include/linux/signal.h as the most logical place for it. If there's some reason this is a bad choice then please let me know (hints as to a better location are then welcome of course). Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/signal.h b/include/linux/signal.h index 78bfb26..0a98f5e 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -220,6 +220,12 @@ static inline void init_sigpending(struct sigpending *sig) INIT_LIST_HEAD(&sig->list); } +/* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */ +static inline int valid_signal(unsigned long sig) +{ + return sig <= _NSIG ? 1 : 0; +} + extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p); extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); extern long do_sigpending(void __user *, unsigned long); -- cgit v0.10.2 From 7ed20e1ad521b5f5df61bf6559ae60738e393741 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 1 May 2005 08:59:14 -0700 Subject: [PATCH] convert that currently tests _NSIG directly to use valid_signal() Convert most of the current code that uses _NSIG directly to instead use valid_signal(). This avoids gcc -W warnings and off-by-one errors. Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index d005831..bbd3753 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -335,7 +336,7 @@ do_sys_ptrace(long request, long pid, long addr, long data, /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -365,7 +366,7 @@ do_sys_ptrace(long request, long pid, long addr, long data, case PTRACE_SINGLESTEP: /* execute single instruction. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; /* Mark single stepping. */ child->thread_info->bpt_nsaved = -1; diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index efd7a34..cd99b83 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -693,7 +694,7 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat case PTRACE_SYSCALL: case PTRACE_CONT: ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -728,7 +729,7 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat */ case PTRACE_SINGLESTEP: ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; child->ptrace |= PT_SINGLESTEP; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); diff --git a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c index 2a13714..8a52124 100644 --- a/arch/arm26/kernel/ptrace.c +++ b/arch/arm26/kernel/ptrace.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -591,7 +592,7 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat case PTRACE_SYSCALL: case PTRACE_CONT: ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -626,7 +627,7 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat */ case PTRACE_SINGLESTEP: ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; child->ptrace |= PT_SINGLESTEP; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c index da15db8..581ecab 100644 --- a/arch/cris/arch-v10/kernel/ptrace.c +++ b/arch/cris/arch-v10/kernel/ptrace.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -184,7 +185,7 @@ sys_ptrace(long request, long pid, long addr, long data) case PTRACE_CONT: ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) { @@ -219,7 +220,7 @@ sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SINGLESTEP: ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c index 2a0efb7..cbe03cb 100644 --- a/arch/frv/kernel/ptrace.c +++ b/arch/frv/kernel/ptrace.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -239,7 +240,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -267,7 +268,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SINGLESTEP: /* set the trap flag. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); ptrace_enable(child); diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c index 5f19d77..05c15e8 100644 --- a/arch/h8300/kernel/ptrace.c +++ b/arch/h8300/kernel/ptrace.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -171,7 +172,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned long) data >= _NSIG) + if (!valid_signal(data)) break ; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -202,7 +203,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SINGLESTEP: { /* set the trap flag. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index b2f1764..e8c965c 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -511,7 +512,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) { set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -543,7 +544,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SINGLESTEP: /* set the trap flag. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); set_singlestep(child); diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 55789fc..c253fd5 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -1481,7 +1482,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data) case PTRACE_CONT: /* restart after signal. */ ret = -EIO; - if (data > _NSIG) + if (!valid_signal(data)) goto out_tsk; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -1520,7 +1521,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data) /* let child execute for one instruction */ case PTRACE_SINGLEBLOCK: ret = -EIO; - if (data > _NSIG) + if (!valid_signal(data)) goto out_tsk; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c index 8b40f36..124f7c1 100644 --- a/arch/m32r/kernel/ptrace.c +++ b/arch/m32r/kernel/ptrace.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -665,7 +666,7 @@ do_ptrace(long request, struct task_struct *child, long addr, long data) case PTRACE_SYSCALL: case PTRACE_CONT: ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -700,7 +701,7 @@ do_ptrace(long request, struct task_struct *child, long addr, long data) unsigned long pc, insn; ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); if ((child->ptrace & PT_DTRACE) == 0) { diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 0beb533..f4e1e5e 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -251,7 +252,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) long tmp; ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) { child->thread.work.syscall_trace = ~0; @@ -292,7 +293,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) long tmp; ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; child->thread.work.syscall_trace = 0; tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c index 15cf790..9724e1c 100644 --- a/arch/m68knommu/kernel/ptrace.c +++ b/arch/m68knommu/kernel/ptrace.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -240,7 +241,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) long tmp; ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -278,7 +279,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) long tmp; ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 92f2c39..a2f899c 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -257,7 +258,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) { set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 611dee9..eee2079 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -241,7 +242,7 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned int) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) { set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index 2937a92..c07db9d 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -285,7 +286,7 @@ long sys_ptrace(long request, pid_t pid, long addr, long data) ret = -EIO; DBG("sys_ptrace(%s)\n", request == PTRACE_SYSCALL ? "SYSCALL" : "CONT"); - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) goto out_tsk; child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP); if (request == PTRACE_SYSCALL) { @@ -311,7 +312,7 @@ long sys_ptrace(long request, pid_t pid, long addr, long data) case PTRACE_SINGLEBLOCK: DBG("sys_ptrace(SINGLEBLOCK)\n"); ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) goto out_tsk; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->ptrace &= ~PT_SINGLESTEP; @@ -328,7 +329,7 @@ long sys_ptrace(long request, pid_t pid, long addr, long data) case PTRACE_SINGLESTEP: DBG("sys_ptrace(SINGLESTEP)\n"); ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) goto out_tsk; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index 426b6f7..59d59a8 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -356,7 +357,7 @@ int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) { set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -389,7 +390,7 @@ int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SINGLESTEP: { /* set the trap flag. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); set_single_step(child); diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index 354a287..5a84632 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -162,7 +163,7 @@ int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -194,7 +195,7 @@ int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SINGLESTEP: { /* set the trap flag. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); set_single_step(child); diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c index ee81b1b..1643642 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/ppc64/kernel/ptrace32.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -293,7 +294,7 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -325,7 +326,7 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) case PTRACE_SINGLESTEP: { /* set the trap flag. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); set_single_step(child); diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 647233c..9f0d73e 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -609,7 +610,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data) /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ - if ((unsigned long) data >= _NSIG) + if (!valid_signal(data)) return -EIO; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -637,7 +638,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_SINGLESTEP: /* set the trap flag. */ - if ((unsigned long) data >= _NSIG) + if (!valid_signal(data)) return -EIO; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c index 1b0dfb4..b28919b 100644 --- a/arch/sh/kernel/ptrace.c +++ b/arch/sh/kernel/ptrace.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -197,7 +198,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -228,7 +229,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) struct pt_regs *dummy = NULL; ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); if ((child->ptrace & PT_DTRACE) == 0) { diff --git a/arch/sh64/kernel/ptrace.c b/arch/sh64/kernel/ptrace.c index 800288c..fd20009 100644 --- a/arch/sh64/kernel/ptrace.c +++ b/arch/sh64/kernel/ptrace.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -255,7 +256,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -285,7 +286,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) struct pt_regs *regs; ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); if ((child->ptrace & PT_DTRACE) == 0) { diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index c4f93bd..475c4c1 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -526,7 +527,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) addr = 1; case PTRACE_CONT: { /* restart after signal. */ - if (data > _NSIG) { + if (!valid_signal(data)) { pt_error_return(regs, EIO); goto out_tsk; } diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 5f080cf..80a76e2 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -559,7 +560,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) addr = 1; case PTRACE_CONT: { /* restart after signal. */ - if (data > _NSIG) { + if (!valid_signal(data)) { pt_error_return(regs, EIO); goto out_tsk; } diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 3a99ee6..e50e60f 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -143,7 +143,7 @@ long sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; child->ptrace &= ~PT_DTRACE; @@ -179,7 +179,7 @@ long sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SINGLESTEP: { /* set the trap flag. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->ptrace |= PT_DTRACE; diff --git a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c index 8fa7807..4726b87 100644 --- a/arch/v850/kernel/ptrace.c +++ b/arch/v850/kernel/ptrace.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -208,7 +209,7 @@ int sys_ptrace(long request, long pid, long addr, long data) /* Execute a single instruction. */ case PTRACE_SINGLESTEP: rval = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; /* Turn CHILD's single-step flag on or off. */ diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index c701167..c64b9c9 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -467,7 +468,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data case PTRACE_CONT: /* restart after signal. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child,TIF_SYSCALL_TRACE); @@ -529,7 +530,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data case PTRACE_SINGLESTEP: /* set the trap flag. */ ret = -EIO; - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) break; clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE); set_singlestep(child); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 5d386f4..8971484 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -641,7 +642,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, extern int spawnpid, spawnsig; if (!perm || !capable(CAP_KILL)) return -EPERM; - if (arg < 1 || arg > _NSIG || arg == SIGKILL) + if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) return -EINVAL; spawnpid = current->pid; spawnsig = arg; diff --git a/fs/fcntl.c b/fs/fcntl.c index 3e7ab16..286a9f8 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -308,7 +309,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, break; case F_SETSIG: /* arg == 0 restores default behaviour. */ - if (arg < 0 || arg > _NSIG) { + if (!valid_signal(arg)) { break; } err = 0; diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 33f7152..0acf245 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "util.h" @@ -976,8 +977,7 @@ asmlinkage long sys_mq_notify(mqd_t mqdes, notification.sigev_notify != SIGEV_THREAD)) return -EINVAL; if (notification.sigev_notify == SIGEV_SIGNAL && - (notification.sigev_signo < 0 || - notification.sigev_signo > _NSIG)) { + !valid_signal(notification.sigev_signo)) { return -EINVAL; } if (notification.sigev_notify == SIGEV_THREAD) { diff --git a/kernel/exit.c b/kernel/exit.c index 93851bc..eb8da36 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -277,7 +278,7 @@ void set_special_pids(pid_t session, pid_t pgrp) */ int allow_signal(int sig) { - if (sig < 1 || sig > _NSIG) + if (!valid_signal(sig) || sig < 1) return -EINVAL; spin_lock_irq(¤t->sighand->siglock); @@ -298,7 +299,7 @@ EXPORT_SYMBOL(allow_signal); int disallow_signal(int sig) { - if (sig < 1 || sig > _NSIG) + if (!valid_signal(sig) || sig < 1) return -EINVAL; spin_lock_irq(¤t->sighand->siglock); diff --git a/kernel/futex.c b/kernel/futex.c index 7b54a67..c7130f8 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -39,6 +39,7 @@ #include #include #include +#include #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8) @@ -654,7 +655,7 @@ static int futex_fd(unsigned long uaddr, int signal) int ret, err; ret = -EINVAL; - if (signal < 0 || signal > _NSIG) + if (!valid_signal(signal)) goto out; ret = get_unused_fd(); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index f5cc1ce..8dcb8f6 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -166,7 +167,7 @@ bad: int ptrace_detach(struct task_struct *child, unsigned int data) { - if ((unsigned long) data > _NSIG) + if (!valid_signal(data)) return -EIO; /* Architecture-specific hardware disable .. */ diff --git a/kernel/signal.c b/kernel/signal.c index e6567d7..8f3debc 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -646,7 +647,7 @@ static int check_kill_permission(int sig, struct siginfo *info, struct task_struct *t) { int error = -EINVAL; - if (sig < 0 || sig > _NSIG) + if (!valid_signal(sig)) return error; error = -EPERM; if ((!info || ((unsigned long)info != 1 && @@ -1245,7 +1246,7 @@ send_sig_info(int sig, struct siginfo *info, struct task_struct *p) * Make sure legacy kernel users don't send in bad values * (normal paths check this in check_kill_permission). */ - if (sig < 0 || sig > _NSIG) + if (!valid_signal(sig)) return -EINVAL; /* @@ -1520,7 +1521,7 @@ void do_notify_parent(struct task_struct *tsk, int sig) if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) sig = 0; } - if (sig > 0 && sig <= _NSIG) + if (valid_signal(sig) && sig > 0) __group_send_sig_info(sig, &info, tsk->parent); __wake_up_parent(tsk, tsk->parent); spin_unlock_irqrestore(&psig->siglock, flags); @@ -2364,7 +2365,7 @@ do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) { struct k_sigaction *k; - if (sig < 1 || sig > _NSIG || (act && sig_kernel_only(sig))) + if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig))) return -EINVAL; k = ¤t->sighand->action[sig-1]; diff --git a/kernel/sys.c b/kernel/sys.c index 7f43d6e..f64e97c 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -1637,7 +1638,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, switch (option) { case PR_SET_PDEATHSIG: sig = arg2; - if (sig < 0 || sig > _NSIG) { + if (!valid_signal(sig)) { error = -EINVAL; break; } -- cgit v0.10.2 From dbcf31ba68c92b23ac3f874c4d516bacd5d7518a Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sun, 1 May 2005 08:59:14 -0700 Subject: [PATCH] fix include order in mthca_memfree.c Fix order of #include lines in mthca_memfree.c Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 986f218..637b30e 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -32,10 +32,11 @@ * $Id$ */ +#include + #include "mthca_memfree.h" #include "mthca_dev.h" #include "mthca_cmd.h" -#include /* * We allocate in as big chunks as we can, up to a maximum of 256 KB -- cgit v0.10.2 From 16f31113a614a35acc2da64f4ae39ab0ed7e194f Mon Sep 17 00:00:00 2001 From: Yum Rayan Date: Sun, 1 May 2005 08:59:14 -0700 Subject: [PATCH] serial_cs: Reduce stack usage in serial_event() This patch reduces the stack usage of the function serial_event() in serial_cs from 2212 to 228. I used a patched version of gcc 3.4.3 on i386 with -fno-unit-at-a-time disabled. This patch is only compile tested. Acked-by: Randy Dunlap Signed-off-by: Yum Rayan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 9034f9a..6eeb48f 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -107,6 +107,13 @@ struct serial_info { int line[4]; }; +struct serial_cfg_mem { + tuple_t tuple; + cisparse_t parse; + u_char buf[256]; +}; + + static void serial_config(dev_link_t * link); static int serial_event(event_t event, int priority, event_callback_args_t * args); @@ -357,14 +364,24 @@ static int simple_config(dev_link_t *link) static int size_table[2] = { 8, 16 }; client_handle_t handle = link->handle; struct serial_info *info = link->priv; - tuple_t tuple; - u_char buf[256]; - cisparse_t parse; - cistpl_cftable_entry_t *cf = &parse.cftable_entry; + struct serial_cfg_mem *cfg_mem; + tuple_t *tuple; + u_char *buf; + cisparse_t *parse; + cistpl_cftable_entry_t *cf; config_info_t config; int i, j, try; int s; + cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); + if (!cfg_mem) + return -1; + + tuple = &cfg_mem->tuple; + parse = &cfg_mem->parse; + cf = &parse->cftable_entry; + buf = cfg_mem->buf; + /* If the card is already configured, look up the port and irq */ i = pcmcia_get_configuration_info(handle, &config); if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { @@ -377,21 +394,23 @@ static int simple_config(dev_link_t *link) port = config.BasePort1 + 0x28; info->slave = 1; } - if (info->slave) + if (info->slave) { + kfree(cfg_mem); return setup_serial(handle, info, port, config.AssignedIRQ); + } } link->conf.Vcc = config.Vcc; /* First pass: look for a config entry that looks normal. */ - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + tuple->TupleData = (cisdata_t *) buf; + tuple->TupleOffset = 0; + tuple->TupleDataMax = 255; + tuple->Attributes = 0; + tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; /* Two tries: without IO aliases, then with aliases */ for (s = 0; s < 2; s++) { for (try = 0; try < 2; try++) { - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(handle, tuple, parse); while (i != CS_NO_MORE_ITEMS) { if (i != CS_SUCCESS) goto next_entry; @@ -409,14 +428,14 @@ static int simple_config(dev_link_t *link) goto found_port; } next_entry: - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(handle, tuple, parse); } } } /* Second pass: try to find an entry that isn't picky about its base address, then try to grab any standard serial port address, and finally try to get any free port. */ - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(handle, tuple, parse); while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { @@ -429,7 +448,7 @@ next_entry: goto found_port; } } - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(handle, tuple, parse); } found_port: @@ -437,6 +456,7 @@ next_entry: printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); cs_error(link->handle, RequestIO, i); + kfree(cfg_mem); return -1; } @@ -450,9 +470,10 @@ next_entry: i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); + kfree(cfg_mem); return -1; } - + kfree(cfg_mem); return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); } @@ -460,29 +481,39 @@ static int multi_config(dev_link_t * link) { client_handle_t handle = link->handle; struct serial_info *info = link->priv; - tuple_t tuple; - u_char buf[256]; - cisparse_t parse; - cistpl_cftable_entry_t *cf = &parse.cftable_entry; + struct serial_cfg_mem *cfg_mem; + tuple_t *tuple; + u_char *buf; + cisparse_t *parse; + cistpl_cftable_entry_t *cf; config_info_t config; - int i, base2 = 0; + int i, rc, base2 = 0; + + cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); + if (!cfg_mem) + return -1; + tuple = &cfg_mem->tuple; + parse = &cfg_mem->parse; + cf = &parse->cftable_entry; + buf = cfg_mem->buf; i = pcmcia_get_configuration_info(handle, &config); if (i != CS_SUCCESS) { cs_error(handle, GetConfigurationInfo, i); - return -1; + rc = -1; + goto free_cfg_mem; } link->conf.Vcc = config.Vcc; - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + tuple->TupleData = (cisdata_t *) buf; + tuple->TupleOffset = 0; + tuple->TupleDataMax = 255; + tuple->Attributes = 0; + tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; /* First, look for a generic full-sized window */ link->io.NumPorts1 = info->multi * 8; - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(handle, tuple, parse); while (i != CS_NO_MORE_ITEMS) { /* The quad port cards have bad CIS's, so just look for a window larger than 8 ports and assume it will be right */ @@ -497,14 +528,14 @@ static int multi_config(dev_link_t * link) if (i == CS_SUCCESS) break; } - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(handle, tuple, parse); } /* If that didn't work, look for two windows */ if (i != CS_SUCCESS) { link->io.NumPorts1 = link->io.NumPorts2 = 8; info->multi = 2; - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(handle, tuple, parse); while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { link->conf.ConfigIndex = cf->index; @@ -517,13 +548,14 @@ static int multi_config(dev_link_t * link) if (i == CS_SUCCESS) break; } - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(handle, tuple, parse); } } if (i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i); - return -1; + rc = -1; + goto free_cfg_mem; } i = pcmcia_request_irq(link->handle, &link->irq); @@ -541,7 +573,8 @@ static int multi_config(dev_link_t * link) i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); - return -1; + rc = -1; + goto free_cfg_mem; } /* The Oxford Semiconductor OXCF950 cards are in fact single-port: @@ -554,17 +587,23 @@ static int multi_config(dev_link_t * link) setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); outb(12, base2 + 1); } - return 0; + rc = 0; + goto free_cfg_mem; } setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); /* The Nokia cards are not really multiport cards */ - if (info->manfid == MANFID_NOKIA) - return 0; + if (info->manfid == MANFID_NOKIA) { + rc = 0; + goto free_cfg_mem; + } for (i = 0; i < info->multi - 1; i++) - setup_serial(handle, info, base2 + (8 * i), link->irq.AssignedIRQ); - - return 0; + setup_serial(handle, info, base2 + (8 * i), + link->irq.AssignedIRQ); + rc = 0; +free_cfg_mem: + kfree(cfg_mem); + return rc; } /*====================================================================== @@ -579,39 +618,49 @@ void serial_config(dev_link_t * link) { client_handle_t handle = link->handle; struct serial_info *info = link->priv; - tuple_t tuple; - u_short buf[128]; - cisparse_t parse; - cistpl_cftable_entry_t *cf = &parse.cftable_entry; + struct serial_cfg_mem *cfg_mem; + tuple_t *tuple; + u_char *buf; + cisparse_t *parse; + cistpl_cftable_entry_t *cf; int i, last_ret, last_fn; DEBUG(0, "serial_config(0x%p)\n", link); - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.Attributes = 0; + cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); + if (!cfg_mem) + goto failed; + + tuple = &cfg_mem->tuple; + parse = &cfg_mem->parse; + cf = &parse->cftable_entry; + buf = cfg_mem->buf; + + tuple->TupleData = (cisdata_t *) buf; + tuple->TupleOffset = 0; + tuple->TupleDataMax = 255; + tuple->Attributes = 0; /* Get configuration register information */ - tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(handle, &tuple, &parse); + tuple->DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(handle, tuple, parse); if (last_ret != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; + link->conf.ConfigBase = parse->config.base; + link->conf.Present = parse->config.rmask[0]; /* Configure card */ link->state |= DEV_CONFIG; /* Is this a compliant multifunction card? */ - tuple.DesiredTuple = CISTPL_LONGLINK_MFC; - tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; - info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS); + tuple->DesiredTuple = CISTPL_LONGLINK_MFC; + tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; + info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS); /* Is this a multiport card? */ - tuple.DesiredTuple = CISTPL_MANFID; - if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { + tuple->DesiredTuple = CISTPL_MANFID; + if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { info->manfid = le16_to_cpu(buf[0]); for (i = 0; i < MULTI_COUNT; i++) if ((info->manfid == multi_id[i].manfid) && @@ -623,13 +672,13 @@ void serial_config(dev_link_t * link) /* Another check for dual-serial cards: look for either serial or multifunction cards that ask for appropriate IO port ranges */ - tuple.DesiredTuple = CISTPL_FUNCID; + tuple->DesiredTuple = CISTPL_FUNCID; if ((info->multi == 0) && - ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) || - (parse.funcid.func == CISTPL_FUNCID_MULTI) || - (parse.funcid.func == CISTPL_FUNCID_SERIAL))) { - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { + ((first_tuple(handle, tuple, parse) != CS_SUCCESS) || + (parse->funcid.func == CISTPL_FUNCID_MULTI) || + (parse->funcid.func == CISTPL_FUNCID_SERIAL))) { + tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; + if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) info->multi = cf->io.win[0].len >> 3; if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && @@ -664,6 +713,7 @@ void serial_config(dev_link_t * link) link->dev = &info->node[0]; link->state &= ~DEV_CONFIG_PENDING; + kfree(cfg_mem); return; cs_failed: @@ -671,6 +721,7 @@ void serial_config(dev_link_t * link) failed: serial_remove(link); link->state &= ~DEV_CONFIG_PENDING; + kfree(cfg_mem); } /*====================================================================== -- cgit v0.10.2 From efcd5e3ab089496865571d22443dd3f514dae60c Mon Sep 17 00:00:00 2001 From: Emanuele Giaquinta Date: Sun, 1 May 2005 08:59:15 -0700 Subject: [PATCH] Makefile: fix for compatibility with *emacs ctags I've noticed that, starting from linux-2.6.12-rc1, in the top Makefile the "cmd_tags" variable has been changed in a way incompatible with *emacs ctags. Since the "--extra" option exists only in "exuberant ctags", it should be included in the CTAGSF shell variable. Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Makefile b/Makefile index 4899089..f7eb558 100644 --- a/Makefile +++ b/Makefile @@ -1190,8 +1190,8 @@ cmd_TAGS = $(all-sources) | etags - quiet_cmd_tags = MAKE $@ define cmd_tags rm -f $@; \ - CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_GPL"`; \ - $(all-sources) | xargs ctags $$CTAGSF -a --extra=+f + CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_GPL --extra=+f"`; \ + $(all-sources) | xargs ctags $$CTAGSF -a endef TAGS: FORCE -- cgit v0.10.2 From 212079cf4ee99e492a57b817e796825d423a30bb Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Sun, 1 May 2005 08:59:15 -0700 Subject: [PATCH] aio: remove superfluous kiocb member initialization This patch removes superfluous kiocb member initialization in the AIO allocation and deallocation path. For example, in really_put_req(), right before kiocb is returned to slab, 5 variables are reset to NULL. The same variables will be initialized at the kiocb allocation time, so why bother reset them knowing that they will be set to valid data at alloc time? Another example: ki_retry is initialized in __aio_get_req, but is initialized again in io_submit_one. Signed-off-by: Ken Chen Cc: Benjamin LaHaise Cc: Suparna Bhattacharya Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/aio.c b/fs/aio.c index a82214d..9f807a5 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -405,7 +405,6 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx) req->ki_ctx = ctx; req->ki_cancel = NULL; req->ki_retry = NULL; - req->ki_obj.user = NULL; req->ki_dtor = NULL; req->private = NULL; INIT_LIST_HEAD(&req->ki_run_list); @@ -451,11 +450,6 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) { if (req->ki_dtor) req->ki_dtor(req); - req->ki_ctx = NULL; - req->ki_filp = NULL; - req->ki_obj.user = NULL; - req->ki_dtor = NULL; - req->private = NULL; kmem_cache_free(kiocb_cachep, req); ctx->reqs_active--; @@ -1515,8 +1509,7 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, } req->ki_filp = file; - iocb->aio_key = req->ki_key; - ret = put_user(iocb->aio_key, &user_iocb->aio_key); + ret = put_user(req->ki_key, &user_iocb->aio_key); if (unlikely(ret)) { dprintk("EFAULT: aio_key\n"); goto out_put_req; @@ -1531,8 +1524,6 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, req->ki_opcode = iocb->aio_lio_opcode; init_waitqueue_func_entry(&req->ki_wait, aio_wake_function); INIT_LIST_HEAD(&req->ki_wait.task_list); - req->ki_run_list.next = req->ki_run_list.prev = NULL; - req->ki_retry = NULL; req->ki_retried = 0; req->ki_kicked = 0; req->ki_queued = 0; -- cgit v0.10.2 From 4bf69b2a06090c01c27f25ea5cd1440f7bf9256f Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Sun, 1 May 2005 08:59:15 -0700 Subject: [PATCH] aio: ring wrapping simplification Since the tail pointer in aio_ring structure never wrap ring size more than once, so a simple compare is sufficient to wrap the index around. This avoid a more expensive mod operation. Signed-off-by: Ken Chen Cc: Benjamin LaHaise Cc: Suparna Bhattacharya Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/aio.c b/fs/aio.c index 9f807a5..40517f3 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -978,7 +978,8 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2) tail = info->tail; event = aio_ring_event(info, tail, KM_IRQ0); - tail = (tail + 1) % info->nr; + if (++tail >= info->nr) + tail = 0; event->obj = (u64)(unsigned long)iocb->ki_obj.user; event->data = iocb->ki_user_data; -- cgit v0.10.2 From 644d3a088a3b862ed0b57c286cf58a6bd338ce08 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Sun, 1 May 2005 08:59:15 -0700 Subject: [PATCH] aio: clean up debug code Clean up code that was previously used for debug purpose. Remove aio_run, aio_wakeups, iocb->ki_queued and iocb->ki_kicked. Also clean up unused variable count in __aio_run_iocbs() and debug code in read_events(). Signed-off-by: Ken Chen Cc: Benjamin LaHaise Cc: Suparna Bhattacharya Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/aio.c b/fs/aio.c index 40517f3..674bb47 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -40,9 +40,6 @@ #define dprintk(x...) do { ; } while (0) #endif -static long aio_run = 0; /* for testing only */ -static long aio_wakeups = 0; /* for testing only */ - /*------ sysctl variables----*/ atomic_t aio_nr = ATOMIC_INIT(0); /* current system wide number of aio requests */ unsigned aio_max_nr = 0x10000; /* system wide maximum number of aio requests */ @@ -617,7 +614,6 @@ static inline int __queue_kicked_iocb(struct kiocb *iocb) if (list_empty(&iocb->ki_run_list)) { list_add_tail(&iocb->ki_run_list, &ctx->run_list); - iocb->ki_queued++; return 1; } return 0; @@ -658,10 +654,8 @@ static ssize_t aio_run_iocb(struct kiocb *iocb) } if (!(iocb->ki_retried & 0xff)) { - pr_debug("%ld retry: %d of %d (kick %ld, Q %ld run %ld, wake %ld)\n", - iocb->ki_retried, - iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes, - iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups); + pr_debug("%ld retry: %d of %d\n", iocb->ki_retried, + iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes); } if (!(retry = iocb->ki_retry)) { @@ -768,7 +762,6 @@ out: static int __aio_run_iocbs(struct kioctx *ctx) { struct kiocb *iocb; - int count = 0; LIST_HEAD(run_list); list_splice_init(&ctx->run_list, &run_list); @@ -783,9 +776,7 @@ static int __aio_run_iocbs(struct kioctx *ctx) aio_run_iocb(iocb); if (__aio_put_req(ctx, iocb)) /* drop extra ref */ put_ioctx(ctx); - count++; } - aio_run++; if (!list_empty(&ctx->run_list)) return 1; return 0; @@ -884,10 +875,8 @@ static void queue_kicked_iocb(struct kiocb *iocb) spin_lock_irqsave(&ctx->ctx_lock, flags); run = __queue_kicked_iocb(iocb); spin_unlock_irqrestore(&ctx->ctx_lock, flags); - if (run) { + if (run) aio_queue_work(ctx); - aio_wakeups++; - } } /* @@ -907,7 +896,6 @@ void fastcall kick_iocb(struct kiocb *iocb) return; } - iocb->ki_kicked++; /* If its already kicked we shouldn't queue it again */ if (!kiocbTryKick(iocb)) { queue_kicked_iocb(iocb); @@ -1003,10 +991,8 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2) pr_debug("added to ring %p at [%lu]\n", iocb, tail); - pr_debug("%ld retries: %d of %d (kicked %ld, Q %ld run %ld wake %ld)\n", - iocb->ki_retried, - iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes, - iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups); + pr_debug("%ld retries: %d of %d\n", iocb->ki_retried, + iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes); put_rq: /* everything turned out well, dispose of the aiocb. */ ret = __aio_put_req(ctx, iocb); @@ -1114,7 +1100,6 @@ static int read_events(struct kioctx *ctx, int i = 0; struct io_event ent; struct aio_timeout to; - int event_loop = 0; /* testing only */ int retry = 0; /* needed to zero any padding within an entry (there shouldn't be @@ -1181,7 +1166,6 @@ retry: if (to.timed_out) /* Only check after read evt */ break; schedule(); - event_loop++; if (signal_pending(tsk)) { ret = -EINTR; break; @@ -1209,9 +1193,6 @@ retry: if (timeout) clear_timeout(&to); out: - pr_debug("event loop executed %d times\n", event_loop); - pr_debug("aio_run %ld\n", aio_run); - pr_debug("aio_wakeups %ld\n", aio_wakeups); return i ? i : ret; } @@ -1526,10 +1507,6 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, init_waitqueue_func_entry(&req->ki_wait, aio_wake_function); INIT_LIST_HEAD(&req->ki_wait.task_list); req->ki_retried = 0; - req->ki_kicked = 0; - req->ki_queued = 0; - aio_run = 0; - aio_wakeups = 0; ret = aio_setup_iocb(req); -- cgit v0.10.2 From 954d3e95369cf73b4bc1e570729f68264a0e6fe0 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Sun, 1 May 2005 08:59:16 -0700 Subject: [PATCH] aio: optimize io_submit_one() This patch optimizes io_submit_one to call aio_run_iocb() directly if ctx->run_list is empty. When the list is empty, the operation of adding to the list, then call to __aio_run_iocbs() is unnecessary because these operations are done in one atomic step. ctx->run_list always has only one element in this case. This optimization speeds up industry standard db transaction processing benchmark by 0.2%. Signed-off-by: Ken Chen Cc: Benjamin LaHaise Cc: Suparna Bhattacharya Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/aio.c b/fs/aio.c index 674bb47..7afa222 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1514,10 +1514,14 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, goto out_put_req; spin_lock_irq(&ctx->ctx_lock); - list_add_tail(&req->ki_run_list, &ctx->run_list); - /* drain the run list */ - while (__aio_run_iocbs(ctx)) - ; + if (likely(list_empty(&ctx->run_list))) { + aio_run_iocb(req); + } else { + list_add_tail(&req->ki_run_list, &ctx->run_list); + /* drain the run list */ + while (__aio_run_iocbs(ctx)) + ; + } spin_unlock_irq(&ctx->ctx_lock); aio_put_req(req); /* drop extra ref to req */ return 0; -- cgit v0.10.2 From 945b092011c6af71a0107be96e119c8c08776f3f Mon Sep 17 00:00:00 2001 From: Colin Leroy Date: Sun, 1 May 2005 08:59:16 -0700 Subject: [PATCH] hfs, hfsplus: don't leak s_fs_info and fix an oops This patch fixes the leak of sb->s_fs_info in both the HFS and HFS+ modules. In addition to this, it fixes an oops happening when trying to mount a non-hfsplus filesystem using hfsplus. This patch is from Roman Zippel, based off patches sent by myself. Signed-off-by: Colin Leroy Signed-off-by: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c index 4efb640..217e32f 100644 --- a/fs/hfs/mdb.c +++ b/fs/hfs/mdb.c @@ -333,6 +333,8 @@ void hfs_mdb_close(struct super_block *sb) * Release the resources associated with the in-core MDB. */ void hfs_mdb_put(struct super_block *sb) { + if (!HFS_SB(sb)) + return; /* free the B-trees */ hfs_btree_close(HFS_SB(sb)->ext_tree); hfs_btree_close(HFS_SB(sb)->cat_tree); @@ -340,4 +342,7 @@ void hfs_mdb_put(struct super_block *sb) /* free the buffers holding the primary and alternate MDBs */ brelse(HFS_SB(sb)->mdb_bh); brelse(HFS_SB(sb)->alt_mdb_bh); + + kfree(HFS_SB(sb)); + sb->s_fs_info = NULL; } diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 1e2c193..ab783f6 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -297,7 +297,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) res = -EINVAL; if (!parse_options((char *)data, sbi)) { hfs_warn("hfs_fs: unable to parse mount options.\n"); - goto bail3; + goto bail; } sb->s_op = &hfs_super_operations; @@ -310,7 +310,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n", hfs_mdb_name(sb)); res = -EINVAL; - goto bail2; + goto bail; } /* try to get the root inode */ @@ -340,10 +340,8 @@ bail_iput: iput(root_inode); bail_no_root: hfs_warn("hfs_fs: get root inode failed.\n"); +bail: hfs_mdb_put(sb); -bail2: -bail3: - kfree(sbi); return res; } diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 5f80446..d55ad67 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -208,7 +208,9 @@ static void hfsplus_write_super(struct super_block *sb) static void hfsplus_put_super(struct super_block *sb) { dprint(DBG_SUPER, "hfsplus_put_super\n"); - if (!(sb->s_flags & MS_RDONLY)) { + if (!sb->s_fs_info) + return; + if (!(sb->s_flags & MS_RDONLY) && HFSPLUS_SB(sb).s_vhdr) { struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; vhdr->modify_date = hfsp_now2mt(); @@ -226,6 +228,8 @@ static void hfsplus_put_super(struct super_block *sb) brelse(HFSPLUS_SB(sb).s_vhbh); if (HFSPLUS_SB(sb).nls) unload_nls(HFSPLUS_SB(sb).nls); + kfree(sb->s_fs_info); + sb->s_fs_info = NULL; } static int hfsplus_statfs(struct super_block *sb, struct kstatfs *buf) -- cgit v0.10.2 From 4dcd00b18118d174c4b8d838c11f437f0af3c20c Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Sun, 1 May 2005 08:59:16 -0700 Subject: [PATCH] autofs4: wait order fix It's possible for an event wait request to arive before the event requestor. If this happens the daemon never gets notified and autofs hangs. Signed-off-by: Ian Kent Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index f5a52c8..9789877 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -84,6 +84,7 @@ struct autofs_wait_queue { char *name; /* This is for status reporting upon return */ int status; + atomic_t notified; atomic_t wait_ctr; }; diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 1ab24a6..5a40d36 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -210,17 +210,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, wq->len = len; wq->status = -EINTR; /* Status return if interrupted */ atomic_set(&wq->wait_ctr, 2); + atomic_set(&wq->notified, 1); up(&sbi->wq_sem); - - DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d", - (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); - /* autofs4_notify_daemon() may block */ - if (notify != NFY_NONE) { - autofs4_notify_daemon(sbi,wq, - notify == NFY_MOUNT ? - autofs_ptype_missing : - autofs_ptype_expire_multi); - } } else { atomic_inc(&wq->wait_ctr); up(&sbi->wq_sem); @@ -229,6 +220,17 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); } + if (notify != NFY_NONE && atomic_dec_and_test(&wq->notified)) { + int type = (notify == NFY_MOUNT ? + autofs_ptype_missing : autofs_ptype_expire_multi); + + DPRINTK(("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", + (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify)); + + /* autofs4_notify_daemon() may block */ + autofs4_notify_daemon(sbi, wq, type); + } + /* wq->name is NULL if and only if the lock is already released */ if ( sbi->catatonic ) { -- cgit v0.10.2 From 3a9720ce73c9247e5262922d65e90444ea75eb50 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Sun, 1 May 2005 08:59:17 -0700 Subject: [PATCH] autofs4: tree race fix For tree mount maps, a call to chdir or chroot, to a directory above the moint point directories at a certain time during the expire results in the expire incorrectly thinking the tree is not busy. This patch adds a check to see if the filesystem above the tree mount points is busy and also locks the filesystem during the tree mount expire to prevent the race. Signed-off-by: Ian Kent Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 9789877..c7b2b88 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -102,6 +102,7 @@ struct autofs_sb_info { int needs_reghost; struct super_block *sb; struct semaphore wq_sem; + spinlock_t fs_lock; struct autofs_wait_queue *queues; /* Wait queue pointer */ }; @@ -127,9 +128,18 @@ static inline int autofs4_oz_mode(struct autofs_sb_info *sbi) { static inline int autofs4_ispending(struct dentry *dentry) { struct autofs_info *inf = autofs4_dentry_ino(dentry); + int pending = 0; - return (dentry->d_flags & DCACHE_AUTOFS_PENDING) || - (inf != NULL && inf->flags & AUTOFS_INF_EXPIRING); + if (dentry->d_flags & DCACHE_AUTOFS_PENDING) + return 1; + + if (inf) { + spin_lock(&inf->sbi->fs_lock); + pending = inf->flags & AUTOFS_INF_EXPIRING; + spin_unlock(&inf->sbi->fs_lock); + } + + return pending; } static inline void autofs4_copy_atime(struct file *src, struct file *dst) diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 31540a6..500425e 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -99,6 +99,10 @@ static int autofs4_check_tree(struct vfsmount *mnt, if (!autofs4_can_expire(top, timeout, do_now)) return 0; + /* Is someone visiting anywhere in the tree ? */ + if (may_umount_tree(mnt)) + return 0; + spin_lock(&dcache_lock); repeat: next = this_parent->d_subdirs.next; @@ -270,10 +274,18 @@ static struct dentry *autofs4_expire(struct super_block *sb, /* Case 2: tree mount, expire iff entire tree is not busy */ if (!exp_leaves) { + /* Lock the tree as we must expire as a whole */ + spin_lock(&sbi->fs_lock); if (autofs4_check_tree(mnt, dentry, timeout, do_now)) { - expired = dentry; - break; + struct autofs_info *inf = autofs4_dentry_ino(dentry); + + /* Set this flag early to catch sys_chdir and the like */ + inf->flags |= AUTOFS_INF_EXPIRING; + spin_unlock(&sbi->fs_lock); + expired = dentry; + break; } + spin_unlock(&sbi->fs_lock); /* Case 3: direct mount, expire individual leaves */ } else { expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index a525607..4bb14cc 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -206,6 +206,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) sbi->version = 0; sbi->sub_version = 0; init_MUTEX(&sbi->wq_sem); + spin_lock_init(&sbi->fs_lock); sbi->queues = NULL; s->s_blocksize = 1024; s->s_blocksize_bits = 10; -- cgit v0.10.2 From d46aa455dd5457fdbebad17db4ff4df655cbfbae Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Sun, 1 May 2005 08:59:17 -0700 Subject: [PATCH] autofs4: bump version number Bump autofs4 version so we know what's going on. Signed-off-by: Ian Kent Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h index d1c7b0e..a1657fb 100644 --- a/include/linux/auto_fs4.h +++ b/include/linux/auto_fs4.h @@ -23,7 +23,7 @@ #define AUTOFS_MIN_PROTO_VERSION 3 #define AUTOFS_MAX_PROTO_VERSION 4 -#define AUTOFS_PROTO_SUBVERSION 5 +#define AUTOFS_PROTO_SUBVERSION 6 /* Mask for expire behaviour */ #define AUTOFS_EXP_IMMEDIATE 1 -- cgit v0.10.2 From 6a3a16f2ef6f335286e2b2bf8284b0ab4ff38ec0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 1 May 2005 08:59:17 -0700 Subject: [PATCH] reiserfs endianness: clone struct reiserfs_key struct reiserfs_key cloned; (currently) identical struct in_core_key added. Places that expect host-endian data in reiserfs_key switched to in_core_key. Basically, we get annotation of reiserfs_key users and keep the resulting tree obviously equivalent to original. Signed-off-by: Al Viro Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index a4e2ed5..f4f16fa 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -736,7 +736,7 @@ static inline int this_blocknr_allocation_would_make_it_a_large_file(reiserfs_bl #ifdef DISPLACE_NEW_PACKING_LOCALITIES static inline void displace_new_packing_locality (reiserfs_blocknr_hint_t *hint) { - struct reiserfs_key * key = &hint->key; + struct in_core_key * key = &hint->key; hint->th->displace_new_blocks = 0; hint->search_start = hint->beg + keyed_hash((char*)(&key->k_objectid),4) % (hint->end - hint->beg); @@ -777,7 +777,7 @@ static inline int old_way (reiserfs_blocknr_hint_t * hint) static inline void hundredth_slices (reiserfs_blocknr_hint_t * hint) { - struct reiserfs_key * key = &hint->key; + struct in_core_key * key = &hint->key; b_blocknr_t slice_start; slice_start = (keyed_hash((char*)(&key->k_dir_id),4) % 100) * (hint->end / 100); diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 73ec521..1d380a5 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -229,6 +229,7 @@ const struct reiserfs_key MIN_KEY = {0, 0, {{0, 0},}}; /* Maximal possible key. It is never in the tree. */ const struct reiserfs_key MAX_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}}; +const struct in_core_key MAX_IN_CORE_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}}; /* Get delimiting key of the buffer by looking for it in the buffers in the path, starting from the bottom diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index bc5e889..d6d1d7e 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -110,7 +110,7 @@ static void reiserfs_unlockfs(struct super_block *s) { reiserfs_allow_writes(s) ; } -extern const struct reiserfs_key MAX_KEY; +extern const struct in_core_key MAX_IN_CORE_KEY; /* this is used to delete "save link" when there are no items of a @@ -164,7 +164,7 @@ static int finish_unfinished (struct super_block * s) /* compose key to look for "save" links */ max_cpu_key.version = KEY_FORMAT_3_5; - max_cpu_key.on_disk_key = MAX_KEY; + max_cpu_key.on_disk_key = MAX_IN_CORE_KEY; max_cpu_key.key_length = 3; #ifdef CONFIG_QUOTA diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index bccff8b..d086787 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -433,6 +433,23 @@ static inline void set_offset_v2_k_offset( struct offset_v2 *v2, loff_t offset ) # define set_offset_v2_k_offset(v2,val) (offset_v2_k_offset(v2) = (val)) #endif +struct in_core_offset_v1 { + __u32 k_offset; + __u32 k_uniqueness; +} __attribute__ ((__packed__)); + +struct in_core_offset_v2 { +#ifdef __LITTLE_ENDIAN + /* little endian version */ + __u64 k_offset:60; + __u64 k_type: 4; +#else + /* big endian version */ + __u64 k_type: 4; + __u64 k_offset:60; +#endif +} __attribute__ ((__packed__)); + /* Key of an item determines its location in the S+tree, and is composed of 4 components */ struct reiserfs_key { @@ -445,9 +462,18 @@ struct reiserfs_key { } __attribute__ ((__packed__)) u; } __attribute__ ((__packed__)); +struct in_core_key { + __u32 k_dir_id; /* packing locality: by default parent + directory object id */ + __u32 k_objectid; /* object identifier */ + union { + struct in_core_offset_v1 k_offset_v1; + struct in_core_offset_v2 k_offset_v2; + } __attribute__ ((__packed__)) u; +} __attribute__ ((__packed__)); struct cpu_key { - struct reiserfs_key on_disk_key; + struct in_core_key on_disk_key; int version; int key_length; /* 3 in all cases but direct2indirect and indirect2direct conversion */ @@ -1476,7 +1502,7 @@ struct tree_balance int fs_gen; /* saved value of `reiserfs_generation' counter see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */ #ifdef DISPLACE_NEW_PACKING_LOCALITIES - struct reiserfs_key key; /* key pointer, to pass to block allocator or + struct in_core_key key; /* key pointer, to pass to block allocator or another low-level subsystem */ #endif } ; @@ -2117,7 +2143,7 @@ struct buffer_head * get_FEB (struct tree_balance *); struct __reiserfs_blocknr_hint { struct inode * inode; /* inode passed to allocator, if we allocate unf. nodes */ long block; /* file offset, in blocks */ - struct reiserfs_key key; + struct in_core_key key; struct path * path; /* search path, used by allocator to deternine search_start by * various ways */ struct reiserfs_transaction_handle * th; /* transaction handle is needed to log super blocks and -- cgit v0.10.2 From 3e8962be915bacc1d70e4849a075041838d60a3f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 1 May 2005 08:59:18 -0700 Subject: [PATCH] reiserfs endianness: annotate little-endian objects little-endian objects annotated as such; again, obviously no changes of resulting code, we only replace __u16 with __le16, etc. in relevant places. Signed-off-by: Al Viro Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index f4f16fa..49c479c 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -260,8 +260,9 @@ static inline int block_group_used(struct super_block *s, u32 id) { /* * the packing is returned in disk byte order */ -u32 reiserfs_choose_packing(struct inode *dir) { - u32 packing; +__le32 reiserfs_choose_packing(struct inode *dir) +{ + __le32 packing; if (TEST_OPTION(packing_groups, dir->i_sb)) { u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id); /* @@ -655,7 +656,7 @@ static int get_left_neighbor(reiserfs_blocknr_hint_t *hint) struct buffer_head * bh; struct item_head * ih; int pos_in_item; - __u32 * item; + __le32 * item; int ret = 0; if (!hint->path) /* reiserfs code can call this function w/o pointer to path diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index d1514a9..fbde4b0 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c @@ -209,8 +209,8 @@ static int reiserfs_readdir (struct file * filp, void * dirent, filldir_t filldi /* compose directory item containing "." and ".." entries (entries are not aligned to 4 byte boundary) */ /* the last four params are LE */ -void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid, - __u32 par_dirid, __u32 par_objid) +void make_empty_dir_item_v1 (char * body, __le32 dirid, __le32 objid, + __le32 par_dirid, __le32 par_objid) { struct reiserfs_de_head * deh; @@ -242,8 +242,8 @@ void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid, } /* compose directory item containing "." and ".." entries */ -void make_empty_dir_item (char * body, __u32 dirid, __u32 objid, - __u32 par_dirid, __u32 par_objid) +void make_empty_dir_item (char * body, __le32 dirid, __le32 objid, + __le32 par_dirid, __le32 par_objid) { struct reiserfs_de_head * deh; diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index f6860e8..2230aff 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -166,7 +166,7 @@ static int reiserfs_allocate_blocks_for_region( struct cpu_key key; // cpu key of item that we are going to deal with struct item_head *ih; // pointer to item head that we are going to deal with struct buffer_head *bh; // Buffer head that contains items that we are going to deal with - __u32 * item; // pointer to item we are going to deal with + __le32 * item; // pointer to item we are going to deal with INITIALIZE_PATH(path); // path to item, that we are going to deal with. b_blocknr_t *allocated_blocks; // Pointer to a place where allocated blocknumbers would be stored. reiserfs_blocknr_hint_t hint; // hint structure for block allocator. @@ -891,7 +891,7 @@ static int reiserfs_prepare_file_region_for_write( struct item_head *ih = NULL; // pointer to item head that we are going to deal with struct buffer_head *itembuf=NULL; // Buffer head that contains items that we are going to deal with INITIALIZE_PATH(path); // path to item, that we are going to deal with. - __u32 * item=NULL; // pointer to item we are going to deal with + __le32 * item=NULL; // pointer to item we are going to deal with int item_pos=-1; /* Position in indirect item */ diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 7543031..5fdb9f9 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -173,7 +173,7 @@ static inline void fix_tail_page_for_writing(struct page *page) { done already or non-hole position has been found in the indirect item */ static inline int allocation_needed (int retval, b_blocknr_t allocated, struct item_head * ih, - __u32 * item, int pos_in_item) + __le32 * item, int pos_in_item) { if (allocated) return 0; @@ -278,7 +278,7 @@ research: bh = get_last_bh (&path); ih = get_ih (&path); if (is_indirect_le_ih (ih)) { - __u32 * ind_item = (__u32 *)B_I_PITEM (bh, ih); + __le32 * ind_item = (__le32 *)B_I_PITEM (bh, ih); /* FIXME: here we could cache indirect item or part of it in the inode to avoid search_by_key in case of subsequent @@ -581,7 +581,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block, struct cpu_key key; struct buffer_head * bh, * unbh = NULL; struct item_head * ih, tmp_ih; - __u32 * item; + __le32 * item; int done; int fs_gen; struct reiserfs_transaction_handle *th = NULL; @@ -746,7 +746,7 @@ start_trans: done = 0; do { if (is_statdata_le_ih (ih)) { - __u32 unp = 0; + __le32 unp = 0; struct cpu_key tmp_key; /* indirect item has to be inserted */ @@ -2067,7 +2067,7 @@ static int map_block_for_writepage(struct inode *inode, struct item_head tmp_ih ; struct item_head *ih ; struct buffer_head *bh ; - __u32 *item ; + __le32 *item ; struct cpu_key key ; INITIALIZE_PATH(path) ; int pos_in_item ; diff --git a/fs/reiserfs/item_ops.c b/fs/reiserfs/item_ops.c index 9cf7c13..0ce33db 100644 --- a/fs/reiserfs/item_ops.c +++ b/fs/reiserfs/item_ops.c @@ -296,10 +296,11 @@ static void print_sequence (__u32 start, int len) static void indirect_print_item (struct item_head * ih, char * item) { int j; - __u32 * unp, prev = INT_MAX; + __le32 * unp; + __u32 prev = INT_MAX; int num; - unp = (__u32 *)item; + unp = (__le32 *)item; if (ih_item_len(ih) % UNFM_P_SIZE) reiserfs_warning (NULL, "indirect_print_item: invalid item len"); diff --git a/fs/reiserfs/objectid.c b/fs/reiserfs/objectid.c index 0785c43..bfe8e25 100644 --- a/fs/reiserfs/objectid.c +++ b/fs/reiserfs/objectid.c @@ -11,13 +11,13 @@ // find where objectid map starts #define objectid_map(s,rs) (old_format_only (s) ? \ - (__u32 *)((struct reiserfs_super_block_v1 *)(rs) + 1) :\ - (__u32 *)((rs) + 1)) + (__le32 *)((struct reiserfs_super_block_v1 *)(rs) + 1) :\ + (__le32 *)((rs) + 1)) #ifdef CONFIG_REISERFS_CHECK -static void check_objectid_map (struct super_block * s, __u32 * map) +static void check_objectid_map (struct super_block * s, __le32 * map) { if (le32_to_cpu (map[0]) != 1) reiserfs_panic (s, "vs-15010: check_objectid_map: map corrupted: %lx", @@ -27,7 +27,7 @@ static void check_objectid_map (struct super_block * s, __u32 * map) } #else -static void check_objectid_map (struct super_block * s, __u32 * map) +static void check_objectid_map (struct super_block * s, __le32 * map) {;} #endif @@ -52,7 +52,7 @@ __u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th) { struct super_block * s = th->t_super; struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s); - __u32 * map = objectid_map (s, rs); + __le32 * map = objectid_map (s, rs); __u32 unused_objectid; BUG_ON (!th->t_trans_id); @@ -97,7 +97,7 @@ void reiserfs_release_objectid (struct reiserfs_transaction_handle *th, { struct super_block * s = th->t_super; struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s); - __u32 * map = objectid_map (s, rs); + __le32 * map = objectid_map (s, rs); int i = 0; BUG_ON (!th->t_trans_id); @@ -172,12 +172,12 @@ int reiserfs_convert_objectid_map_v1(struct super_block *s) { int new_size = (s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2 ; int old_max = sb_oid_maxsize(disk_sb); struct reiserfs_super_block_v1 *disk_sb_v1 ; - __u32 *objectid_map, *new_objectid_map ; + __le32 *objectid_map, *new_objectid_map ; int i ; disk_sb_v1=(struct reiserfs_super_block_v1 *)(SB_BUFFER_WITH_SB(s)->b_data); - objectid_map = (__u32 *)(disk_sb_v1 + 1) ; - new_objectid_map = (__u32 *)(disk_sb + 1) ; + objectid_map = (__le32 *)(disk_sb_v1 + 1) ; + new_objectid_map = (__le32 *)(disk_sb + 1) ; if (cur_size > new_size) { /* mark everyone used that was listed as free at the end of the objectid diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c index f4ea81a..e242ebc 100644 --- a/fs/reiserfs/procfs.c +++ b/fs/reiserfs/procfs.c @@ -73,8 +73,8 @@ int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset, #define DFL( x ) D4C( rs -> s_v1.x ) #define objectid_map( s, rs ) (old_format_only (s) ? \ - (__u32 *)((struct reiserfs_super_block_v1 *)rs + 1) : \ - (__u32 *)(rs + 1)) + (__le32 *)((struct reiserfs_super_block_v1 *)rs + 1) : \ + (__le32 *)(rs + 1)) #define MAP( i ) D4C( objectid_map( sb, rs )[ i ] ) #define DJF( x ) le32_to_cpu( rs -> x ) diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 1d380a5..15fa4cb 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -87,10 +87,11 @@ inline void copy_item_head(struct item_head * p_v_to, inline int comp_short_keys (const struct reiserfs_key * le_key, const struct cpu_key * cpu_key) { - __u32 * p_s_le_u32, * p_s_cpu_u32; + __le32 * p_s_le_u32; + __u32 * p_s_cpu_u32; int n_key_length = REISERFS_SHORT_KEY_LEN; - p_s_le_u32 = (__u32 *)le_key; + p_s_le_u32 = (__le32 *)le_key; p_s_cpu_u32 = (__u32 *)&cpu_key->on_disk_key; for( ; n_key_length--; ++p_s_le_u32, ++p_s_cpu_u32 ) { if ( le32_to_cpu (*p_s_le_u32) < *p_s_cpu_u32 ) @@ -228,7 +229,12 @@ extern struct tree_balance * cur_tb; const struct reiserfs_key MIN_KEY = {0, 0, {{0, 0},}}; /* Maximal possible key. It is never in the tree. */ -const struct reiserfs_key MAX_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}}; +const struct reiserfs_key MAX_KEY = { + __constant_cpu_to_le32(0xffffffff), + __constant_cpu_to_le32(0xffffffff), + {{__constant_cpu_to_le32(0xffffffff), + __constant_cpu_to_le32(0xffffffff)},} +}; const struct in_core_key MAX_IN_CORE_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}}; @@ -998,7 +1004,7 @@ static char prepare_for_delete_or_cut( int n_unfm_number, /* Number of the item unformatted nodes. */ n_counter, n_blk_size; - __u32 * p_n_unfm_pointer; /* Pointer to the unformatted node number. */ + __le32 * p_n_unfm_pointer; /* Pointer to the unformatted node number. */ __u32 tmp; struct item_head s_ih; /* Item header. */ char c_mode; /* Returned mode of the balance. */ @@ -1060,7 +1066,7 @@ static char prepare_for_delete_or_cut( /* pointers to be cut */ n_unfm_number -= pos_in_item (p_s_path); /* Set pointer to the last unformatted node pointer that is to be cut. */ - p_n_unfm_pointer = (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1 - *p_n_removed; + p_n_unfm_pointer = (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1 - *p_n_removed; /* We go through the unformatted nodes pointers of the indirect @@ -1082,8 +1088,8 @@ static char prepare_for_delete_or_cut( need_research = 1 ; break; } - RFALSE( p_n_unfm_pointer < (__u32 *)B_I_PITEM(p_s_bh, &s_ih) || - p_n_unfm_pointer > (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1, + RFALSE( p_n_unfm_pointer < (__le32 *)B_I_PITEM(p_s_bh, &s_ih) || + p_n_unfm_pointer > (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1, "vs-5265: pointer out of range"); /* Hole, nothing to remove. */ @@ -1432,7 +1438,7 @@ int reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode #if defined( USE_INODE_GENERATION_COUNTER ) if( !old_format_only ( th -> t_super ) ) { - __u32 *inode_generation; + __le32 *inode_generation; inode_generation = &REISERFS_SB(th -> t_super) -> s_rs -> s_inode_generation; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index d6d1d7e..2283f18 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -216,7 +216,7 @@ static int finish_unfinished (struct super_block * s) /* reiserfs_iget needs k_dirid and k_objectid only */ item = B_I_PITEM (bh, ih); - obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__u32 *)item); + obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__le32 *)item); obj_key.on_disk_key.k_objectid = le32_to_cpu (ih->ih_key.k_objectid); obj_key.on_disk_key.u.k_offset_v1.k_offset = 0; obj_key.on_disk_key.u.k_offset_v1.k_uniqueness = 0; @@ -304,7 +304,7 @@ void add_save_link (struct reiserfs_transaction_handle * th, int retval; struct cpu_key key; struct item_head ih; - __u32 link; + __le32 link; BUG_ON (!th->t_trans_id); @@ -1336,7 +1336,7 @@ static int read_super_block (struct super_block * s, int offset) return 1; } - if ( rs->s_v1.s_root_block == -1 ) { + if ( rs->s_v1.s_root_block == cpu_to_le32(-1) ) { brelse(bh) ; reiserfs_warning (s, "Unfinished reiserfsck --rebuild-tree run detected. Please run\n" "reiserfsck --rebuild-tree and wait for a completion. If that fails\n" diff --git a/include/linux/reiserfs_acl.h b/include/linux/reiserfs_acl.h index a57e973..2aef9c3 100644 --- a/include/linux/reiserfs_acl.h +++ b/include/linux/reiserfs_acl.h @@ -5,18 +5,18 @@ #define REISERFS_ACL_VERSION 0x0001 typedef struct { - __u16 e_tag; - __u16 e_perm; - __u32 e_id; + __le16 e_tag; + __le16 e_perm; + __le32 e_id; } reiserfs_acl_entry; typedef struct { - __u16 e_tag; - __u16 e_perm; + __le16 e_tag; + __le16 e_perm; } reiserfs_acl_entry_short; typedef struct { - __u32 a_version; + __le32 a_version; } reiserfs_acl_header; static inline size_t reiserfs_acl_size(int count) diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index d086787..cc39c53 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -114,47 +114,47 @@ if( !( cond ) ) \ struct journal_params { - __u32 jp_journal_1st_block; /* where does journal start from on its + __le32 jp_journal_1st_block; /* where does journal start from on its * device */ - __u32 jp_journal_dev; /* journal device st_rdev */ - __u32 jp_journal_size; /* size of the journal */ - __u32 jp_journal_trans_max; /* max number of blocks in a transaction. */ - __u32 jp_journal_magic; /* random value made on fs creation (this + __le32 jp_journal_dev; /* journal device st_rdev */ + __le32 jp_journal_size; /* size of the journal */ + __le32 jp_journal_trans_max; /* max number of blocks in a transaction. */ + __le32 jp_journal_magic; /* random value made on fs creation (this * was sb_journal_block_count) */ - __u32 jp_journal_max_batch; /* max number of blocks to batch into a + __le32 jp_journal_max_batch; /* max number of blocks to batch into a * trans */ - __u32 jp_journal_max_commit_age; /* in seconds, how old can an async + __le32 jp_journal_max_commit_age; /* in seconds, how old can an async * commit be */ - __u32 jp_journal_max_trans_age; /* in seconds, how old can a transaction + __le32 jp_journal_max_trans_age; /* in seconds, how old can a transaction * be */ }; /* this is the super from 3.5.X, where X >= 10 */ struct reiserfs_super_block_v1 { - __u32 s_block_count; /* blocks count */ - __u32 s_free_blocks; /* free blocks count */ - __u32 s_root_block; /* root block number */ + __le32 s_block_count; /* blocks count */ + __le32 s_free_blocks; /* free blocks count */ + __le32 s_root_block; /* root block number */ struct journal_params s_journal; - __u16 s_blocksize; /* block size */ - __u16 s_oid_maxsize; /* max size of object id array, see + __le16 s_blocksize; /* block size */ + __le16 s_oid_maxsize; /* max size of object id array, see * get_objectid() commentary */ - __u16 s_oid_cursize; /* current size of object id array */ - __u16 s_umount_state; /* this is set to 1 when filesystem was + __le16 s_oid_cursize; /* current size of object id array */ + __le16 s_umount_state; /* this is set to 1 when filesystem was * umounted, to 2 - when not */ char s_magic[10]; /* reiserfs magic string indicates that * file system is reiserfs: * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */ - __u16 s_fs_state; /* it is set to used by fsck to mark which + __le16 s_fs_state; /* it is set to used by fsck to mark which * phase of rebuilding is done */ - __u32 s_hash_function_code; /* indicate, what hash function is being use + __le32 s_hash_function_code; /* indicate, what hash function is being use * to sort names in a directory*/ - __u16 s_tree_height; /* height of disk tree */ - __u16 s_bmap_nr; /* amount of bitmap blocks needed to address + __le16 s_tree_height; /* height of disk tree */ + __le16 s_bmap_nr; /* amount of bitmap blocks needed to address * each block of file system */ - __u16 s_version; /* this field is only reliable on filesystem + __le16 s_version; /* this field is only reliable on filesystem * with non-standard journal */ - __u16 s_reserved_for_journal; /* size in blocks of journal area on main + __le16 s_reserved_for_journal; /* size in blocks of journal area on main * device, we need to keep after * making fs with non-standard journal */ } __attribute__ ((__packed__)); @@ -165,8 +165,8 @@ struct reiserfs_super_block_v1 struct reiserfs_super_block { struct reiserfs_super_block_v1 s_v1; - __u32 s_inode_generation; - __u32 s_flags; /* Right now used only by inode-attributes, if enabled */ + __le32 s_inode_generation; + __le32 s_flags; /* Right now used only by inode-attributes, if enabled */ unsigned char s_uuid[16]; /* filesystem unique identifier */ unsigned char s_label[16]; /* filesystem volume label */ char s_unused[88] ; /* zero filled by mkreiserfs and @@ -269,7 +269,7 @@ int is_reiserfs_jr (struct reiserfs_super_block * rs); #define QUOTA_EXCEEDED -6 typedef __u32 b_blocknr_t; -typedef __u32 unp_t; +typedef __le32 unp_t; struct unfm_nodeinfo { unp_t unfm_nodenum; @@ -376,8 +376,8 @@ static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb) // directories use this key as well as old files // struct offset_v1 { - __u32 k_offset; - __u32 k_uniqueness; + __le32 k_offset; + __le32 k_uniqueness; } __attribute__ ((__packed__)); struct offset_v2 { @@ -453,9 +453,9 @@ struct in_core_offset_v2 { /* Key of an item determines its location in the S+tree, and is composed of 4 components */ struct reiserfs_key { - __u32 k_dir_id; /* packing locality: by default parent + __le32 k_dir_id; /* packing locality: by default parent directory object id */ - __u32 k_objectid; /* object identifier */ + __le32 k_objectid; /* object identifier */ union { struct offset_v1 k_offset_v1; struct offset_v2 k_offset_v2; @@ -534,15 +534,15 @@ struct item_head item. Note that the key, not this field, is used to determine the item type, and thus which field this union contains. */ - __u16 ih_free_space_reserved; + __le16 ih_free_space_reserved; /* Iff this is a directory item, this field equals the number of directory entries in the directory item. */ - __u16 ih_entry_count; + __le16 ih_entry_count; } __attribute__ ((__packed__)) u; - __u16 ih_item_len; /* total size of the item body */ - __u16 ih_item_location; /* an offset to the item body + __le16 ih_item_len; /* total size of the item body */ + __le16 ih_item_location; /* an offset to the item body * within the block */ - __u16 ih_version; /* 0 for all old items, 2 for new + __le16 ih_version; /* 0 for all old items, 2 for new ones. Highest bit is set by fsck temporary, cleaned after all done */ @@ -778,10 +778,10 @@ extern struct reiserfs_key root_key; /* Header of a disk block. More precisely, header of a formatted leaf or internal node, and not the header of an unformatted node. */ struct block_head { - __u16 blk_level; /* Level of a block in the tree. */ - __u16 blk_nr_item; /* Number of keys/items in a block. */ - __u16 blk_free_space; /* Block free space in bytes. */ - __u16 blk_reserved; + __le16 blk_level; /* Level of a block in the tree. */ + __le16 blk_nr_item; /* Number of keys/items in a block. */ + __le16 blk_free_space; /* Block free space in bytes. */ + __le16 blk_reserved; /* dump this in v4/planA */ struct reiserfs_key blk_right_delim_key; /* kept only for compatibility */ }; @@ -845,19 +845,19 @@ struct block_head { // struct stat_data_v1 { - __u16 sd_mode; /* file type, permissions */ - __u16 sd_nlink; /* number of hard links */ - __u16 sd_uid; /* owner */ - __u16 sd_gid; /* group */ - __u32 sd_size; /* file size */ - __u32 sd_atime; /* time of last access */ - __u32 sd_mtime; /* time file was last modified */ - __u32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ + __le16 sd_mode; /* file type, permissions */ + __le16 sd_nlink; /* number of hard links */ + __le16 sd_uid; /* owner */ + __le16 sd_gid; /* group */ + __le32 sd_size; /* file size */ + __le32 sd_atime; /* time of last access */ + __le32 sd_mtime; /* time file was last modified */ + __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ union { - __u32 sd_rdev; - __u32 sd_blocks; /* number of blocks file uses */ + __le32 sd_rdev; + __le32 sd_blocks; /* number of blocks file uses */ } __attribute__ ((__packed__)) u; - __u32 sd_first_direct_byte; /* first byte of file which is stored + __le32 sd_first_direct_byte; /* first byte of file which is stored in a direct item: except that if it equals 1 it is a symlink and if it equals ~(__u32)0 there is no @@ -923,20 +923,20 @@ struct stat_data_v1 /* Stat Data on disk (reiserfs version of UFS disk inode minus the address blocks) */ struct stat_data { - __u16 sd_mode; /* file type, permissions */ - __u16 sd_attrs; /* persistent inode flags */ - __u32 sd_nlink; /* number of hard links */ - __u64 sd_size; /* file size */ - __u32 sd_uid; /* owner */ - __u32 sd_gid; /* group */ - __u32 sd_atime; /* time of last access */ - __u32 sd_mtime; /* time file was last modified */ - __u32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ - __u32 sd_blocks; + __le16 sd_mode; /* file type, permissions */ + __le16 sd_attrs; /* persistent inode flags */ + __le32 sd_nlink; /* number of hard links */ + __le64 sd_size; /* file size */ + __le32 sd_uid; /* owner */ + __le32 sd_gid; /* group */ + __le32 sd_atime; /* time of last access */ + __le32 sd_mtime; /* time file was last modified */ + __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ + __le32 sd_blocks; union { - __u32 sd_rdev; - __u32 sd_generation; - //__u32 sd_first_direct_byte; + __le32 sd_rdev; + __le32 sd_generation; + //__le32 sd_first_direct_byte; /* first byte of file which is stored in a direct item: except that if it equals 1 it is a symlink and if it equals @@ -1019,12 +1019,12 @@ struct stat_data { struct reiserfs_de_head { - __u32 deh_offset; /* third component of the directory entry key */ - __u32 deh_dir_id; /* objectid of the parent directory of the object, that is referenced + __le32 deh_offset; /* third component of the directory entry key */ + __le32 deh_dir_id; /* objectid of the parent directory of the object, that is referenced by directory entry */ - __u32 deh_objectid; /* objectid of the object, that is referenced by directory entry */ - __u16 deh_location; /* offset of name in the whole item */ - __u16 deh_state; /* whether 1) entry contains stat data (for future), and 2) whether + __le32 deh_objectid; /* objectid of the object, that is referenced by directory entry */ + __le16 deh_location; /* offset of name in the whole item */ + __le16 deh_state; /* whether 1) entry contains stat data (for future), and 2) whether entry is hidden (unlinked) */ } __attribute__ ((__packed__)); #define DEH_SIZE sizeof(struct reiserfs_de_head) @@ -1084,10 +1084,10 @@ struct reiserfs_de_head #define de_visible(deh) test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) #define de_hidden(deh) !test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) -extern void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid, - __u32 par_dirid, __u32 par_objid); -extern void make_empty_dir_item (char * body, __u32 dirid, __u32 objid, - __u32 par_dirid, __u32 par_objid); +extern void make_empty_dir_item_v1 (char * body, __le32 dirid, __le32 objid, + __le32 par_dirid, __le32 par_objid); +extern void make_empty_dir_item (char * body, __le32 dirid, __le32 objid, + __le32 par_dirid, __le32 par_objid); /* array of the entry headers */ /* get item body */ @@ -1186,9 +1186,9 @@ struct reiserfs_dir_entry /* Disk child pointer: The pointer from an internal node of the tree to a node that is on disk. */ struct disk_child { - __u32 dc_block_number; /* Disk child's block number. */ - __u16 dc_size; /* Disk child's used space. */ - __u16 dc_reserved; + __le32 dc_block_number; /* Disk child's block number. */ + __le16 dc_size; /* Disk child's used space. */ + __le16 dc_reserved; }; #define DC_SIZE (sizeof(struct disk_child)) @@ -1656,10 +1656,10 @@ struct reiserfs_iget_args { /* first block written in a commit. */ struct reiserfs_journal_desc { - __u32 j_trans_id ; /* id of commit */ - __u32 j_len ; /* length of commit. len +1 is the commit block */ - __u32 j_mount_id ; /* mount id of this trans*/ - __u32 j_realblock[1] ; /* real locations for each block */ + __le32 j_trans_id ; /* id of commit */ + __le32 j_len ; /* length of commit. len +1 is the commit block */ + __le32 j_mount_id ; /* mount id of this trans*/ + __le32 j_realblock[1] ; /* real locations for each block */ } ; #define get_desc_trans_id(d) le32_to_cpu((d)->j_trans_id) @@ -1672,9 +1672,9 @@ struct reiserfs_journal_desc { /* last block written in a commit */ struct reiserfs_journal_commit { - __u32 j_trans_id ; /* must match j_trans_id from the desc block */ - __u32 j_len ; /* ditto */ - __u32 j_realblock[1] ; /* real locations for each block */ + __le32 j_trans_id ; /* must match j_trans_id from the desc block */ + __le32 j_len ; /* ditto */ + __le32 j_realblock[1] ; /* real locations for each block */ } ; #define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id) @@ -1689,9 +1689,9 @@ struct reiserfs_journal_commit { ** and this transaction does not need to be replayed. */ struct reiserfs_journal_header { - __u32 j_last_flush_trans_id ; /* id of last fully flushed transaction */ - __u32 j_first_unflushed_offset ; /* offset in the log of where to start replay after a crash */ - __u32 j_mount_id ; + __le32 j_last_flush_trans_id ; /* id of last fully flushed transaction */ + __le32 j_first_unflushed_offset ; /* offset in the log of where to start replay after a crash */ + __le32 j_mount_id ; /* 12 */ struct journal_params jh_journal; } ; @@ -2170,7 +2170,7 @@ void reiserfs_init_alloc_options (struct super_block *s); * to use for a new object underneat it. The locality is returned * in disk byte order (le). */ -u32 reiserfs_choose_packing(struct inode *dir); +__le32 reiserfs_choose_packing(struct inode *dir); int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value); void reiserfs_free_block (struct reiserfs_transaction_handle *th, struct inode *, b_blocknr_t, int for_unformatted); diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h index 1eaa48e..9244c57 100644 --- a/include/linux/reiserfs_xattr.h +++ b/include/linux/reiserfs_xattr.h @@ -10,8 +10,8 @@ #define REISERFS_XATTR_MAGIC 0x52465841 /* "RFXA" */ struct reiserfs_xattr_header { - __u32 h_magic; /* magic number for identification */ - __u32 h_hash; /* hash of the value */ + __le32 h_magic; /* magic number for identification */ + __le32 h_hash; /* hash of the value */ }; #ifdef __KERNEL__ -- cgit v0.10.2 From b8cc936f6295bba23513a49d858ea82f64982faf Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 1 May 2005 08:59:18 -0700 Subject: [PATCH] reiserfs endianness: fix endianness bugs fixes for a couple of bugs exposed by the above: le32_to_cpu() used on 16bit value and missing conversion in comparison of host- and little-endian values. Signed-off-by: Al Viro Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index b16d65a..3072cfd 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2391,7 +2391,7 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo jh = (struct reiserfs_journal_header *)(bhjh->b_data); /* make sure that journal matches to the super block */ - if (is_reiserfs_jr(rs) && (jh->jh_journal.jp_journal_magic != sb_jp_journal_magic(rs))) { + if (is_reiserfs_jr(rs) && (le32_to_cpu(jh->jh_journal.jp_journal_magic) != sb_jp_journal_magic(rs))) { reiserfs_warning (p_s_sb, "sh-460: journal header magic %x " "(device %s) does not match to magic found in super " "block %x", diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index cc39c53..2f7a34d 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -225,7 +225,7 @@ struct reiserfs_super_block #define SB_ONDISK_JOURNAL_DEVICE(s) \ le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev)) #define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \ - le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal)) + le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal)) #define is_block_in_log_or_reserved_area(s, block) \ block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \ -- cgit v0.10.2 From 6b9f5829e6e3af44f20c681e26524c637d4f82ff Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 1 May 2005 08:59:19 -0700 Subject: [PATCH] reiserfs endianness: comp_short_keys() cleanup comp_short_keys() massaged into sane form, which kills the last place where pointer to in_core_key (or any object containing such) would be cast to or from something else. At that point we are free to change layout of in_core_key - nothing depends on it anymore. So we drop the mess with union in there and simply use (unconditional) __u64 k_offset and __u8 k_type instead; places using in_core_key switched to those. That gives _far_ better code than current mess - on all platforms. Signed-off-by: Al Viro Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 5fdb9f9..2711dff 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1341,8 +1341,8 @@ void reiserfs_read_locked_inode (struct inode * inode, struct reiserfs_iget_args key.version = KEY_FORMAT_3_5; key.on_disk_key.k_dir_id = dirino; key.on_disk_key.k_objectid = inode->i_ino; - key.on_disk_key.u.k_offset_v1.k_offset = SD_OFFSET; - key.on_disk_key.u.k_offset_v1.k_uniqueness = SD_UNIQUENESS; + key.on_disk_key.k_offset = 0; + key.on_disk_key.k_type = 0; /* look for the object's stat data */ retval = search_item (inode->i_sb, &key, &path_to_sd); diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 15fa4cb..da23ba7 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -87,23 +87,20 @@ inline void copy_item_head(struct item_head * p_v_to, inline int comp_short_keys (const struct reiserfs_key * le_key, const struct cpu_key * cpu_key) { - __le32 * p_s_le_u32; - __u32 * p_s_cpu_u32; - int n_key_length = REISERFS_SHORT_KEY_LEN; - - p_s_le_u32 = (__le32 *)le_key; - p_s_cpu_u32 = (__u32 *)&cpu_key->on_disk_key; - for( ; n_key_length--; ++p_s_le_u32, ++p_s_cpu_u32 ) { - if ( le32_to_cpu (*p_s_le_u32) < *p_s_cpu_u32 ) + __u32 n; + n = le32_to_cpu(le_key->k_dir_id); + if (n < cpu_key->on_disk_key.k_dir_id) return -1; - if ( le32_to_cpu (*p_s_le_u32) > *p_s_cpu_u32 ) + if (n > cpu_key->on_disk_key.k_dir_id) + return 1; + n = le32_to_cpu(le_key->k_objectid); + if (n < cpu_key->on_disk_key.k_objectid) + return -1; + if (n > cpu_key->on_disk_key.k_objectid) return 1; - } - return 0; } - /* k1 is pointer to on-disk structure which is stored in little-endian form. k2 is pointer to cpu variable. Compare keys using all 4 key fields. @@ -153,18 +150,15 @@ inline int comp_short_le_keys (const struct reiserfs_key * key1, const struct re inline void le_key2cpu_key (struct cpu_key * to, const struct reiserfs_key * from) { + int version; to->on_disk_key.k_dir_id = le32_to_cpu (from->k_dir_id); to->on_disk_key.k_objectid = le32_to_cpu (from->k_objectid); // find out version of the key - to->version = le_key_version (from); - if (to->version == KEY_FORMAT_3_5) { - to->on_disk_key.u.k_offset_v1.k_offset = le32_to_cpu (from->u.k_offset_v1.k_offset); - to->on_disk_key.u.k_offset_v1.k_uniqueness = le32_to_cpu (from->u.k_offset_v1.k_uniqueness); - } else { - to->on_disk_key.u.k_offset_v2.k_offset = offset_v2_k_offset(&from->u.k_offset_v2); - to->on_disk_key.u.k_offset_v2.k_type = offset_v2_k_type(&from->u.k_offset_v2); - } + version = le_key_version (from); + to->version = version; + to->on_disk_key.k_offset = le_key_k_offset(version, from); + to->on_disk_key.k_type = le_key_k_type(version, from); } @@ -235,8 +229,8 @@ const struct reiserfs_key MAX_KEY = { {{__constant_cpu_to_le32(0xffffffff), __constant_cpu_to_le32(0xffffffff)},} }; -const struct in_core_key MAX_IN_CORE_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}}; +const struct in_core_key MAX_IN_CORE_KEY = {~0U, ~0U, ~0ULL>>4, 15}; /* Get delimiting key of the buffer by looking for it in the buffers in the path, starting from the bottom of the path, and going upwards. We must check the path's validity at each step. If the key is not in diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 2283f18..31e7512 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -218,8 +218,8 @@ static int finish_unfinished (struct super_block * s) item = B_I_PITEM (bh, ih); obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__le32 *)item); obj_key.on_disk_key.k_objectid = le32_to_cpu (ih->ih_key.k_objectid); - obj_key.on_disk_key.u.k_offset_v1.k_offset = 0; - obj_key.on_disk_key.u.k_offset_v1.k_uniqueness = 0; + obj_key.on_disk_key.k_offset = 0; + obj_key.on_disk_key.k_type = 0; pathrelse (&path); diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index 2f7a34d..d445b68 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -433,23 +433,6 @@ static inline void set_offset_v2_k_offset( struct offset_v2 *v2, loff_t offset ) # define set_offset_v2_k_offset(v2,val) (offset_v2_k_offset(v2) = (val)) #endif -struct in_core_offset_v1 { - __u32 k_offset; - __u32 k_uniqueness; -} __attribute__ ((__packed__)); - -struct in_core_offset_v2 { -#ifdef __LITTLE_ENDIAN - /* little endian version */ - __u64 k_offset:60; - __u64 k_type: 4; -#else - /* big endian version */ - __u64 k_type: 4; - __u64 k_offset:60; -#endif -} __attribute__ ((__packed__)); - /* Key of an item determines its location in the S+tree, and is composed of 4 components */ struct reiserfs_key { @@ -466,11 +449,9 @@ struct in_core_key { __u32 k_dir_id; /* packing locality: by default parent directory object id */ __u32 k_objectid; /* object identifier */ - union { - struct in_core_offset_v1 k_offset_v1; - struct in_core_offset_v2 k_offset_v2; - } __attribute__ ((__packed__)) u; -} __attribute__ ((__packed__)); + __u64 k_offset; + __u8 k_type; +}; struct cpu_key { struct in_core_key on_disk_key; @@ -696,43 +677,29 @@ static inline void set_le_ih_k_type (struct item_head * ih, int type) // static inline loff_t cpu_key_k_offset (const struct cpu_key * key) { - return (key->version == KEY_FORMAT_3_5) ? - key->on_disk_key.u.k_offset_v1.k_offset : - key->on_disk_key.u.k_offset_v2.k_offset; + return key->on_disk_key.k_offset; } static inline loff_t cpu_key_k_type (const struct cpu_key * key) { - return (key->version == KEY_FORMAT_3_5) ? - uniqueness2type (key->on_disk_key.u.k_offset_v1.k_uniqueness) : - key->on_disk_key.u.k_offset_v2.k_type; + return key->on_disk_key.k_type; } static inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset) { - (key->version == KEY_FORMAT_3_5) ? - (key->on_disk_key.u.k_offset_v1.k_offset = offset) : - (key->on_disk_key.u.k_offset_v2.k_offset = offset); + key->on_disk_key.k_offset = offset; } - static inline void set_cpu_key_k_type (struct cpu_key * key, int type) { - (key->version == KEY_FORMAT_3_5) ? - (key->on_disk_key.u.k_offset_v1.k_uniqueness = type2uniqueness (type)): - (key->on_disk_key.u.k_offset_v2.k_type = type); + key->on_disk_key.k_type = type; } - static inline void cpu_key_k_offset_dec (struct cpu_key * key) { - if (key->version == KEY_FORMAT_3_5) - key->on_disk_key.u.k_offset_v1.k_offset --; - else - key->on_disk_key.u.k_offset_v2.k_offset --; + key->on_disk_key.k_offset --; } - #define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY) #define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT) #define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT) -- cgit v0.10.2 From f8e08a8466c4ac5f61b4bdb6338fd97eedb9c9e8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 1 May 2005 08:59:19 -0700 Subject: [PATCH] reiserfs endianness: sanitize reiserfs_key union Since we only access reiserfs_key ->u.k_offset_v2 guts in four helper functions, we are free to sanitize those, as long as - layout of the structure is unchanged (it's on-disk object) - behaviour of these helpers is same as before. Patch kills the mess with endianness-dependent bitfields and replaces them with a single __le64. Helpers are switched to straightforward shift/and/or. Benefits: - exact same definitions for little- and big-endian architectures; no ifdefs in sight. - generate the same code on little-endian and improved on big-endian. - doesn't rely on lousy bitfields handling in gcc codegenerator. - happens to be standard C (unsigned long long is not a valid type for a bitfield; it's a gccism and not well-implemented one, at that). Signed-off-by: Al Viro Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index d445b68..3214862 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -381,57 +381,29 @@ struct offset_v1 { } __attribute__ ((__packed__)); struct offset_v2 { -#ifdef __LITTLE_ENDIAN - /* little endian version */ - __u64 k_offset:60; - __u64 k_type: 4; -#else - /* big endian version */ - __u64 k_type: 4; - __u64 k_offset:60; -#endif + __le64 v; } __attribute__ ((__packed__)); -#ifndef __LITTLE_ENDIAN -typedef union { - struct offset_v2 offset_v2; - __u64 linear; -} __attribute__ ((__packed__)) offset_v2_esafe_overlay; - static inline __u16 offset_v2_k_type( const struct offset_v2 *v2 ) { - offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2; - tmp.linear = le64_to_cpu( tmp.linear ); - return (tmp.offset_v2.k_type <= TYPE_MAXTYPE)?tmp.offset_v2.k_type:TYPE_ANY; + __u8 type = le64_to_cpu(v2->v) >> 60; + return (type <= TYPE_MAXTYPE)?type:TYPE_ANY; } static inline void set_offset_v2_k_type( struct offset_v2 *v2, int type ) { - offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2; - tmp->linear = le64_to_cpu(tmp->linear); - tmp->offset_v2.k_type = type; - tmp->linear = cpu_to_le64(tmp->linear); + v2->v = (v2->v & cpu_to_le64(~0ULL>>4)) | cpu_to_le64((__u64)type<<60); } static inline loff_t offset_v2_k_offset( const struct offset_v2 *v2 ) { - offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2; - tmp.linear = le64_to_cpu( tmp.linear ); - return tmp.offset_v2.k_offset; + return le64_to_cpu(v2->v) & (~0ULL>>4); } static inline void set_offset_v2_k_offset( struct offset_v2 *v2, loff_t offset ){ - offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2; - tmp->linear = le64_to_cpu(tmp->linear); - tmp->offset_v2.k_offset = offset; - tmp->linear = cpu_to_le64(tmp->linear); + offset &= (~0ULL>>4); + v2->v = (v2->v & cpu_to_le64(15ULL<<60)) | cpu_to_le64(offset); } -#else -# define offset_v2_k_type(v2) ((v2)->k_type) -# define set_offset_v2_k_type(v2,val) (offset_v2_k_type(v2) = (val)) -# define offset_v2_k_offset(v2) ((v2)->k_offset) -# define set_offset_v2_k_offset(v2,val) (offset_v2_k_offset(v2) = (val)) -#endif /* Key of an item determines its location in the S+tree, and is composed of 4 components */ -- cgit v0.10.2 From 1622c3fcf4c1c6c8267938f366ecd2a348d67d93 Mon Sep 17 00:00:00 2001 From: Gerd Knorr Date: Sun, 1 May 2005 08:59:19 -0700 Subject: [PATCH] cx88-dvb oops fix Fixup error path, without that one the driver kills the machine by oopsing in the IRQ handler in case the frontend initialization fails. Signed-off-by: Gerd Knorr Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index bc6f18c..84d1743 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -243,10 +243,8 @@ static int dvb_register(struct cx8802_dev *dev) break; #endif default: - printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n" - "%s: you might want to look out for patches here:\n" - "%s: http://dl.bytesex.org/patches/\n", - dev->core->name, dev->core->name, dev->core->name); + printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", + dev->core->name); break; } if (NULL == dev->dvb.frontend) { @@ -308,9 +306,11 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev, dev); err = dvb_register(dev); if (0 != err) - goto fail_free; + goto fail_fini; return 0; + fail_fini: + cx8802_fini_common(dev); fail_free: kfree(dev); fail_core: -- cgit v0.10.2 From 9990d744bea7d28e83c420e2c9d524c7a8a2d136 Mon Sep 17 00:00:00 2001 From: Gerd Knorr Date: Sun, 1 May 2005 08:59:20 -0700 Subject: [PATCH] dvb: cx22702 frontend driver update update cx22702 fe driver, add support for using the dvb pll lib, enable cx22702 support in cx88-dvb. Signed-off-by: Gerd Knorr Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 1930b51..011860c 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -32,6 +32,7 @@ #include #include #include "dvb_frontend.h" +#include "dvb-pll.h" #include "cx22702.h" @@ -203,7 +204,19 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet /* set PLL */ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); - state->config->pll_set(fe, p); + if (state->config->pll_set) { + state->config->pll_set(fe, p); + } else if (state->config->pll_desc) { + u8 pllbuf[4]; + struct i2c_msg msg = { .addr = state->config->pll_address, + .buf = pllbuf, .len = 4 }; + dvb_pll_configure(state->config->pll_desc, pllbuf, + p->frequency, + p->u.ofdm.bandwidth); + i2c_transfer(state->i2c, &msg, 1); + } else { + BUG(); + } cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); /* set inversion */ diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h index 6e34f99..559fdb9 100644 --- a/drivers/media/dvb/frontends/cx22702.h +++ b/drivers/media/dvb/frontends/cx22702.h @@ -36,6 +36,9 @@ struct cx22702_config u8 demod_address; /* PLL maintenance */ + u8 pll_address; + struct dvb_pll_desc *pll_desc; + int (*pll_init)(struct dvb_frontend* fe); int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c1b3542..d3dd422 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -252,6 +252,7 @@ config VIDEO_SAA7134_DVB depends on VIDEO_SAA7134 && DVB_CORE select VIDEO_BUF_DVB select DVB_MT352 + select DVB_CX22702 ---help--- This adds support for DVB cards based on the Philips saa7134 chip. diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 84d1743..1ca3731 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -31,7 +31,7 @@ #include /* those two frontends need merging via linuxtv cvs ... */ -#define HAVE_CX22702 0 +#define HAVE_CX22702 1 #define HAVE_OR51132 1 #include "cx88.h" -- cgit v0.10.2 From faf8b24968ce6392ea68d9afc7de1ffbc38c1f6c Mon Sep 17 00:00:00 2001 From: Gerd Knorr Date: Sun, 1 May 2005 08:59:20 -0700 Subject: [PATCH] v4l: msp3400 update msp3400 update: Fix and enable "simpler" mode, some other minor fixes. Signed-off-by: Gerd Knorr Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index c97df70..7fbb858 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -380,7 +380,9 @@ static void msp3400c_setvolume(struct i2c_client *client, int val = 0, bal = 0; if (!muted) { - val = (volume * 0x7F / 65535) << 8; + /* 0x7f instead if 0x73 here has sound quality issues, + * probably due to overmodulation + clipping ... */ + val = (volume * 0x73 / 65535) << 8; } if (val) { bal = (balance / 256) - 128; @@ -997,7 +999,13 @@ static int msp34xx_modus(int norm) { switch (norm) { case VIDEO_MODE_PAL: +#if 1 + /* experimental: not sure this works with all chip versions */ + return 0x7003; +#else + /* previous value, try this if it breaks ... */ return 0x1003; +#endif case VIDEO_MODE_NTSC: /* BTSC */ return 0x2003; case VIDEO_MODE_SECAM: @@ -1264,6 +1272,7 @@ static int msp34xxg_thread(void *data) int val, std, i; printk("msp34xxg: daemon started\n"); + msp->source = 1; /* default */ for (;;) { d2printk(KERN_DEBUG "msp34xxg: thread: sleep\n"); msp34xx_sleep(msp,-1); @@ -1334,8 +1343,9 @@ static void msp34xxg_set_source(struct i2c_client *client, int source) /* fix matrix mode to stereo and let the msp choose what * to output according to 'source', as recommended + * for MONO (source==0) downmixing set bit[7:0] to 0x30 */ - int value = (source&0x07)<<8|(source==0 ? 0x00:0x20); + int value = (source&0x07)<<8|(source==0 ? 0x30:0x20); dprintk("msp34xxg: set source to %d (0x%x)\n", source, value); msp3400c_write(client, I2C_MSP3400C_DFP, @@ -1359,7 +1369,7 @@ static void msp34xxg_set_source(struct i2c_client *client, int source) msp3400c_write(client, I2C_MSP3400C_DEM, 0x22, /* a2 threshold for stereo/bilingual */ - source==0 ? 0x7f0:stereo_threshold); + stereo_threshold); msp->source=source; } @@ -1394,7 +1404,7 @@ static void msp34xxg_detect_stereo(struct i2c_client *client) static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) { struct msp3400c *msp = i2c_get_clientdata(client); - int source = 0; + int source; switch (audmode) { case V4L2_TUNER_MODE_MONO: @@ -1410,9 +1420,10 @@ static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) case V4L2_TUNER_MODE_LANG2: source=4; /* stereo or B */ break; - default: /* doing nothing: a safe, sane default */ + default: audmode = 0; - return; + source = 1; + break; } msp->audmode = audmode; msp34xxg_set_source(client, source); @@ -1514,12 +1525,9 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) msp->opmode = opmode; if (OPMODE_AUTO == msp->opmode) { -#if 0 /* seems to work for ivtv only, disable by default for now ... */ if (HAVE_SIMPLER(msp)) msp->opmode = OPMODE_SIMPLER; - else -#endif - if (HAVE_SIMPLE(msp)) + else if (HAVE_SIMPLE(msp)) msp->opmode = OPMODE_SIMPLE; else msp->opmode = OPMODE_MANUAL; diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 065eb40..80dc34f 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -991,7 +991,7 @@ static int tda9874a_initialize(struct CHIPSTATE *chip) { if (tda9874a_SIF > 2) tda9874a_SIF = 1; - if (tda9874a_STD >= 8) + if (tda9874a_STD > 8) tda9874a_STD = 0; if(tda9874a_AMSEL > 1) tda9874a_AMSEL = 0; -- cgit v0.10.2 From fe55c452368af263a9beec38ed29f6be85280524 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Sun, 1 May 2005 08:59:20 -0700 Subject: [PATCH] ext3: remove unnecessary race then retry in ext3_get_block The extra race-with-truncate-then-retry logic around ext3_get_block_handle(), which was inherited from ext2, becomes unecessary for ext3, since we have already obtained the ei->truncate_sem in ext3_get_block_handle() before calling ext3_alloc_branch(). The ei->truncate_sem is already there to block concurrent truncate and block allocation on the same inode. So the inode's indirect addressing tree won't be changed after we grab that semaphore. We could, after get the semaphore, re-verify the branch is up-to-date or not. If it has been changed, then get the updated branch. If we still need block allocation, we will have a safe version of the branch to work with in the ext3_find_goal()/ext3_splice_branch(). The code becomes more readable after remove those retry logic. The patch also clean up some gotos in ext3_get_block_handle() to make it more readable. Signed-off-by: Mingming Cao Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 040eb28..ea58886 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -455,12 +455,11 @@ static unsigned long ext3_find_near(struct inode *inode, Indirect *ind) * @goal: place to store the result. * * Normally this function find the prefered place for block allocation, - * stores it in *@goal and returns zero. If the branch had been changed - * under us we return -EAGAIN. + * stores it in *@goal and returns zero. */ -static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4], - Indirect *partial, unsigned long *goal) +static unsigned long ext3_find_goal(struct inode *inode, long block, + Indirect chain[4], Indirect *partial) { struct ext3_block_alloc_info *block_i = EXT3_I(inode)->i_block_alloc_info; @@ -470,15 +469,10 @@ static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4], */ if (block_i && (block == block_i->last_alloc_logical_block + 1) && (block_i->last_alloc_physical_block != 0)) { - *goal = block_i->last_alloc_physical_block + 1; - return 0; + return block_i->last_alloc_physical_block + 1; } - if (verify_chain(chain, partial)) { - *goal = ext3_find_near(inode, partial); - return 0; - } - return -EAGAIN; + return ext3_find_near(inode, partial); } /** @@ -582,12 +576,9 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, * @where: location of missing link * @num: number of blocks we are adding * - * This function verifies that chain (up to the missing link) had not - * changed, fills the missing link and does all housekeeping needed in + * This function fills the missing link and does all housekeeping needed in * inode (->i_blocks, etc.). In case of success we end up with the full - * chain to new block and return 0. Otherwise (== chain had been changed) - * we free the new blocks (forgetting their buffer_heads, indeed) and - * return -EAGAIN. + * chain to new block and return 0. */ static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block, @@ -608,12 +599,6 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block, if (err) goto err_out; } - /* Verify that place we are splicing to is still there and vacant */ - - if (!verify_chain(chain, where-1) || *where->p) - /* Writer: end */ - goto changed; - /* That's it */ *where->p = where->key; @@ -657,26 +642,11 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block, } return err; -changed: - /* - * AKPM: if where[i].bh isn't part of the current updating - * transaction then we explode nastily. Test this code path. - */ - jbd_debug(1, "the chain changed: try again\n"); - err = -EAGAIN; - err_out: for (i = 1; i < num; i++) { BUFFER_TRACE(where[i].bh, "call journal_forget"); ext3_journal_forget(handle, where[i].bh); } - /* For the normal collision cleanup case, we free up the blocks. - * On genuine filesystem errors we don't even think about doing - * that. */ - if (err == -EAGAIN) - for (i = 0; i < num; i++) - ext3_free_blocks(handle, inode, - le32_to_cpu(where[i].key), 1); return err; } @@ -708,7 +678,7 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock, unsigned long goal; int left; int boundary = 0; - int depth = ext3_block_to_path(inode, iblock, offsets, &boundary); + const int depth = ext3_block_to_path(inode, iblock, offsets, &boundary); struct ext3_inode_info *ei = EXT3_I(inode); J_ASSERT(handle != NULL || create == 0); @@ -716,54 +686,55 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock, if (depth == 0) goto out; -reread: partial = ext3_get_branch(inode, depth, offsets, chain, &err); /* Simplest case - block found, no allocation needed */ if (!partial) { clear_buffer_new(bh_result); -got_it: - map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); - if (boundary) - set_buffer_boundary(bh_result); - /* Clean up and exit */ - partial = chain+depth-1; /* the whole chain */ - goto cleanup; + goto got_it; } /* Next simple case - plain lookup or failed read of indirect block */ - if (!create || err == -EIO) { -cleanup: + if (!create || err == -EIO) + goto cleanup; + + down(&ei->truncate_sem); + + /* + * If the indirect block is missing while we are reading + * the chain(ext3_get_branch() returns -EAGAIN err), or + * if the chain has been changed after we grab the semaphore, + * (either because another process truncated this branch, or + * another get_block allocated this branch) re-grab the chain to see if + * the request block has been allocated or not. + * + * Since we already block the truncate/other get_block + * at this point, we will have the current copy of the chain when we + * splice the branch into the tree. + */ + if (err == -EAGAIN || !verify_chain(chain, partial)) { while (partial > chain) { - BUFFER_TRACE(partial->bh, "call brelse"); brelse(partial->bh); partial--; } - BUFFER_TRACE(bh_result, "returned"); -out: - return err; + partial = ext3_get_branch(inode, depth, offsets, chain, &err); + if (!partial) { + up(&ei->truncate_sem); + if (err) + goto cleanup; + clear_buffer_new(bh_result); + goto got_it; + } } /* - * Indirect block might be removed by truncate while we were - * reading it. Handling of that case (forget what we've got and - * reread) is taken out of the main path. - */ - if (err == -EAGAIN) - goto changed; - - goal = 0; - down(&ei->truncate_sem); - - /* lazy initialize the block allocation info here if necessary */ - if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) { + * Okay, we need to do block allocation. Lazily initialize the block + * allocation info here if necessary + */ + if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) ext3_init_block_alloc_info(inode); - } - if (ext3_find_goal(inode, iblock, chain, partial, &goal) < 0) { - up(&ei->truncate_sem); - goto changed; - } + goal = ext3_find_goal(inode, iblock, chain, partial); left = (chain + depth) - partial; @@ -771,38 +742,45 @@ out: * Block out ext3_truncate while we alter the tree */ err = ext3_alloc_branch(handle, inode, left, goal, - offsets+(partial-chain), partial); + offsets + (partial - chain), partial); - /* The ext3_splice_branch call will free and forget any buffers + /* + * The ext3_splice_branch call will free and forget any buffers * on the new chain if there is a failure, but that risks using * up transaction credits, especially for bitmaps where the * credits cannot be returned. Can we handle this somehow? We - * may need to return -EAGAIN upwards in the worst case. --sct */ + * may need to return -EAGAIN upwards in the worst case. --sct + */ if (!err) err = ext3_splice_branch(handle, inode, iblock, chain, partial, left); - /* i_disksize growing is protected by truncate_sem - * don't forget to protect it if you're about to implement - * concurrent ext3_get_block() -bzzz */ + /* + * i_disksize growing is protected by truncate_sem. Don't forget to + * protect it if you're about to implement concurrent + * ext3_get_block() -bzzz + */ if (!err && extend_disksize && inode->i_size > ei->i_disksize) ei->i_disksize = inode->i_size; up(&ei->truncate_sem); - if (err == -EAGAIN) - goto changed; if (err) goto cleanup; set_buffer_new(bh_result); - goto got_it; - -changed: +got_it: + map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); + if (boundary) + set_buffer_boundary(bh_result); + /* Clean up and exit */ + partial = chain + depth - 1; /* the whole chain */ +cleanup: while (partial > chain) { - jbd_debug(1, "buffer chain changed, retrying\n"); - BUFFER_TRACE(partial->bh, "brelsing"); + BUFFER_TRACE(partial->bh, "call brelse"); brelse(partial->bh); partial--; } - goto reread; + BUFFER_TRACE(bh_result, "returned"); +out: + return err; } static int ext3_get_block(struct inode *inode, sector_t iblock, -- cgit v0.10.2 From 10e92060295ded7b8feac1ee57bb2135ea9ac207 Mon Sep 17 00:00:00 2001 From: Peter Missel Date: Sun, 1 May 2005 08:59:21 -0700 Subject: [PATCH] saa7134: Add OEM version of already supported card Add device table support for the LR214WF card. The driver will say it's a FlyTV, simply because the name strings are stored with the card design data, not the device ID data. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 72a7b24..c51eb7f 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1628,11 +1628,17 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, + .subvendor = 0x5168, /* Animation Technologies (LifeView) */ .subdevice = 0x0214, /* Standard PCI, LR214WF */ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, },{ .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1489, /* KYE */ + .subdevice = 0x0214, /* Genius VideoWonder ProTV */ + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */ + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x16be, .subdevice = 0x0003, -- cgit v0.10.2 From 149733d4e274ce1add3399cabdb243116ebfdf79 Mon Sep 17 00:00:00 2001 From: Patrick Gefre Date: Sun, 1 May 2005 08:59:21 -0700 Subject: [PATCH] Altix ioc4 serial - set hfc from ioctl Allow hardware flow control to be set from an ioctl. Signed-off-by: Patrick Gefre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index d054f12..f94d2e7 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -1765,8 +1765,11 @@ ioc4_change_speed(struct uart_port *the_port, the_port->ignore_status_mask &= ~N_DATA_READY; } - if (cflag & CRTSCTS) + if (cflag & CRTSCTS) { info->flags |= ASYNC_CTS_FLOW; + port->ip_sscr |= IOC4_SSCR_HFC_EN; + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + } else info->flags &= ~ASYNC_CTS_FLOW; @@ -1825,12 +1828,6 @@ static inline int ic4_startup_local(struct uart_port *the_port) /* set the speed of the serial port */ ioc4_change_speed(the_port, info->tty->termios, (struct termios *)0); - /* enable hardware flow control - after ioc4_change_speed because - * ASYNC_CTS_FLOW is set there */ - if (info->flags & ASYNC_CTS_FLOW) { - port->ip_sscr |= IOC4_SSCR_HFC_EN; - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - } info->flags |= UIF_INITIALIZED; return 0; } -- cgit v0.10.2 From 6cb2875f8d7e392982229094ad3b6d2f213f48da Mon Sep 17 00:00:00 2001 From: Patrick Gefre Date: Sun, 1 May 2005 08:59:21 -0700 Subject: [PATCH] Altix ioc4 serial - set a better timeout/threshold Set the timeout and threshold to better values. Signed-off-by: Patrick Gefre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index f94d2e7..d3f4542 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -1272,8 +1272,9 @@ static inline int set_rx_timeout(struct ioc4_port *port, int timeout) * and set the rx threshold to that amount. There are 4 chars * per ring entry, so we'll divide the number of chars that will * arrive in timeout by 4. + * So .... timeout * baud / 10 / HZ / 4, with HZ = 100. */ - threshold = timeout * port->ip_baud / 10 / HZ / 4; + threshold = timeout * port->ip_baud / 4000; if (threshold == 0) threshold = 1; /* otherwise we'll intr all the time! */ @@ -1285,8 +1286,10 @@ static inline int set_rx_timeout(struct ioc4_port *port, int timeout) writel(port->ip_sscr, &port->ip_serial_regs->sscr); - /* Now set the rx timeout to the given value */ - timeout = timeout * IOC4_SRTR_HZ / HZ; + /* Now set the rx timeout to the given value + * again timeout * IOC4_SRTR_HZ / HZ + */ + timeout = timeout * IOC4_SRTR_HZ / 100; if (timeout > IOC4_SRTR_CNT) timeout = IOC4_SRTR_CNT; @@ -1380,7 +1383,7 @@ config_port(struct ioc4_port *port, if (port->ip_tx_lowat == 0) port->ip_tx_lowat = 1; - set_rx_timeout(port, port->ip_rx_timeout); + set_rx_timeout(port, 2); return 0; } -- cgit v0.10.2 From 68985e486b708671a7c7d0b4de6d94a1547d1351 Mon Sep 17 00:00:00 2001 From: Patrick Gefre Date: Sun, 1 May 2005 08:59:21 -0700 Subject: [PATCH] Altix ioc4 serial - small uart setup mods Small mods for setting up the uart - parity, flow control Signed-off-by: Patrick Gefre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index d3f4542..d9629ee 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -1688,8 +1688,8 @@ ioc4_change_speed(struct uart_port *the_port, { struct ioc4_port *port = get_ioc4_port(the_port); int baud, bits; - unsigned cflag, cval; - int new_parity = 0, new_parity_enable = 0, new_stop = 1, new_data = 8; + unsigned cflag; + int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8; struct uart_info *info = the_port->info; cflag = new_termios->c_cflag; @@ -1697,48 +1697,35 @@ ioc4_change_speed(struct uart_port *the_port, switch (cflag & CSIZE) { case CS5: new_data = 5; - cval = 0x00; bits = 7; break; case CS6: new_data = 6; - cval = 0x01; bits = 8; break; case CS7: new_data = 7; - cval = 0x02; bits = 9; break; case CS8: new_data = 8; - cval = 0x03; bits = 10; break; default: /* cuz we always need a default ... */ new_data = 5; - cval = 0x00; bits = 7; break; } if (cflag & CSTOPB) { - cval |= 0x04; bits++; new_stop = 1; } if (cflag & PARENB) { - cval |= UART_LCR_PARITY; bits++; new_parity_enable = 1; - } - if (cflag & PARODD) { - cval |= UART_LCR_EPAR; - new_parity = 1; - } - if (cflag & IGNPAR) { - cval &= ~UART_LCR_PARITY; - new_parity_enable = 0; + if (cflag & PARODD) + new_parity = 1; } baud = uart_get_baud_rate(the_port, new_termios, old_termios, MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED); @@ -1771,10 +1758,12 @@ ioc4_change_speed(struct uart_port *the_port, if (cflag & CRTSCTS) { info->flags |= ASYNC_CTS_FLOW; port->ip_sscr |= IOC4_SSCR_HFC_EN; - writel(port->ip_sscr, &port->ip_serial_regs->sscr); } - else + else { info->flags &= ~ASYNC_CTS_FLOW; + port->ip_sscr &= ~IOC4_SSCR_HFC_EN; + } + writel(port->ip_sscr, &port->ip_serial_regs->sscr); /* Set the configuration and proper notification call */ DPRINT_CONFIG(("%s : port 0x%p cflag 0%o " @@ -1847,7 +1836,6 @@ static void ioc4_cb_output_lowat(struct ioc4_port *port) } } - /** * handle_intr - service any interrupts for the given port - 2nd level * called via sd_intr -- cgit v0.10.2 From 5b052d8bb3ad9108489e7475868e14372774ca08 Mon Sep 17 00:00:00 2001 From: Patrick Gefre Date: Sun, 1 May 2005 08:59:22 -0700 Subject: [PATCH] Altix ioc4 serial - Arm the read timeout timer before the first read Arm the read timeout timer before the first read. Signed-off-by: Patrick Gefre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index d9629ee..ba4e13a 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -838,7 +838,7 @@ static int inline port_init(struct ioc4_port *port) port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK; writel(port->ip_tx_prod, &port->ip_serial_regs->stpir); port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; - writel(port->ip_rx_cons, &port->ip_serial_regs->srcir); + writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir); /* Disable interrupts for this 16550 */ uart = port->ip_uart_regs; -- cgit v0.10.2 From 7149437669f79b497830e643a2b13d26a017b038 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 1 May 2005 08:59:22 -0700 Subject: [PATCH] fbdev: Batch cmap changes at driver level This patch adds to the fbdev interface a set_cmap callback that allow the driver to "batch" palette changes. This is useful for drivers like radeonfb which might require lenghtly workarounds on palette accesses, thus allowing to factor out those workarounds efficiently. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index e8eb124..ee25b9e 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -1057,13 +1057,14 @@ static int radeonfb_blank (int blank, struct fb_info *info) return radeon_screen_blank(rinfo, blank, 0); } -static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, struct fb_info *info) +static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct radeonfb_info *rinfo) { - struct radeonfb_info *rinfo = info->par; u32 pindex; unsigned int i; - + + if (regno > 255) return 1; @@ -1078,20 +1079,7 @@ static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, pindex = regno; if (!rinfo->asleep) { - u32 dac_cntl2, vclk_cntl = 0; - radeon_fifo_wait(9); - if (rinfo->is_mobility) { - vclk_cntl = INPLL(VCLK_ECP_CNTL); - OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb); - } - - /* Make sure we are on first palette */ - if (rinfo->has_CRTC2) { - dac_cntl2 = INREG(DAC_CNTL2); - dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL; - OUTREG(DAC_CNTL2, dac_cntl2); - } if (rinfo->bpp == 16) { pindex = regno * 8; @@ -1101,24 +1089,27 @@ static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, if (rinfo->depth == 15 && regno > 31) return 1; - /* For 565, the green component is mixed one order below */ + /* For 565, the green component is mixed one order + * below + */ if (rinfo->depth == 16) { OUTREG(PALETTE_INDEX, pindex>>1); - OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) | - (green << 8) | (rinfo->palette[regno>>1].blue)); + OUTREG(PALETTE_DATA, + (rinfo->palette[regno>>1].red << 16) | + (green << 8) | + (rinfo->palette[regno>>1].blue)); green = rinfo->palette[regno<<1].green; } } if (rinfo->depth != 16 || regno < 32) { OUTREG(PALETTE_INDEX, pindex); - OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue); + OUTREG(PALETTE_DATA, (red << 16) | + (green << 8) | blue); } - if (rinfo->is_mobility) - OUTPLL(VCLK_ECP_CNTL, vclk_cntl); } if (regno < 16) { - u32 *pal = info->pseudo_palette; + u32 *pal = rinfo->info->pseudo_palette; switch (rinfo->depth) { case 15: pal[regno] = (regno << 10) | (regno << 5) | regno; @@ -1138,6 +1129,84 @@ static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, return 0; } +static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + u32 dac_cntl2, vclk_cntl = 0; + int rc; + + if (!rinfo->asleep) { + if (rinfo->is_mobility) { + vclk_cntl = INPLL(VCLK_ECP_CNTL); + OUTPLL(VCLK_ECP_CNTL, + vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb); + } + + /* Make sure we are on first palette */ + if (rinfo->has_CRTC2) { + dac_cntl2 = INREG(DAC_CNTL2); + dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL; + OUTREG(DAC_CNTL2, dac_cntl2); + } + } + + rc = radeon_setcolreg (regno, red, green, blue, transp, rinfo); + + if (!rinfo->asleep && rinfo->is_mobility) + OUTPLL(VCLK_ECP_CNTL, vclk_cntl); + + return rc; +} + +static int radeonfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) +{ + struct radeonfb_info *rinfo = info->par; + u16 *red, *green, *blue, *transp; + u32 dac_cntl2, vclk_cntl = 0; + int i, start, rc = 0; + + if (!rinfo->asleep) { + if (rinfo->is_mobility) { + vclk_cntl = INPLL(VCLK_ECP_CNTL); + OUTPLL(VCLK_ECP_CNTL, + vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb); + } + + /* Make sure we are on first palette */ + if (rinfo->has_CRTC2) { + dac_cntl2 = INREG(DAC_CNTL2); + dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL; + OUTREG(DAC_CNTL2, dac_cntl2); + } + } + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + + for (i = 0; i < cmap->len; i++) { + u_int hred, hgreen, hblue, htransp = 0xffff; + + hred = *red++; + hgreen = *green++; + hblue = *blue++; + if (transp) + htransp = *transp++; + rc = radeon_setcolreg (start++, hred, hgreen, hblue, htransp, + rinfo); + if (rc) + break; + } + + if (!rinfo->asleep && rinfo->is_mobility) + OUTPLL(VCLK_ECP_CNTL, vclk_cntl); + + return rc; +} static void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *save) @@ -1796,6 +1865,7 @@ static struct fb_ops radeonfb_ops = { .fb_check_var = radeonfb_check_var, .fb_set_par = radeonfb_set_par, .fb_setcolreg = radeonfb_setcolreg, + .fb_setcmap = radeonfb_setcmap, .fb_pan_display = radeonfb_pan_display, .fb_blank = radeonfb_blank, .fb_ioctl = radeonfb_ioctl, diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index c51f8fb..4e5ce8f 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c @@ -222,8 +222,11 @@ int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info) transp = cmap->transp; start = cmap->start; - if (start < 0 || !info->fbops->fb_setcolreg) + if (start < 0 || (!info->fbops->fb_setcolreg && + !info->fbops->fb_setcmap)) return -EINVAL; + if (info->fbops->fb_setcmap) + return info->fbops->fb_setcmap(cmap, info); for (i = 0; i < cmap->len; i++) { hred = *red++; hgreen = *green++; @@ -250,8 +253,33 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info) transp = cmap->transp; start = cmap->start; - if (start < 0 || !info->fbops->fb_setcolreg) + if (start < 0 || (!info->fbops->fb_setcolreg && + !info->fbops->fb_setcmap)) return -EINVAL; + + /* If we can batch, do it */ + if (info->fbops->fb_setcmap && cmap->len > 1) { + struct fb_cmap umap; + int size = cmap->len * sizeof(u16); + int rc; + + memset(&umap, 0, sizeof(struct fb_cmap)); + rc = fb_alloc_cmap(&umap, cmap->len, transp != NULL); + if (rc) + return rc; + if (copy_from_user(umap.red, red, size) || + copy_from_user(umap.green, green, size) || + copy_from_user(umap.blue, blue, size) || + (transp && copy_from_user(umap.transp, transp, size))) { + rc = -EFAULT; + } + umap.start = start; + if (rc == 0) + rc = info->fbops->fb_setcmap(&umap, info); + fb_dealloc_cmap(&umap); + return rc; + } + for (i = 0; i < cmap->len; i++, red++, blue++, green++) { if (get_user(hred, red) || get_user(hgreen, green) || diff --git a/include/linux/fb.h b/include/linux/fb.h index b45d3e2..b468bf4 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -563,6 +563,9 @@ struct fb_ops { int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info); + /* set color registers in batch */ + int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info); + /* blank display */ int (*fb_blank)(int blank, struct fb_info *info); -- cgit v0.10.2 From 917bb0771aa077f62a3de75028a45f243d3954a8 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" Date: Sun, 1 May 2005 08:59:22 -0700 Subject: [PATCH] nvidiafb: ioremap and i2c fixes - Add 'vram' option to specify amount of video RAM to remap - Limit remap size to 64 MIB - Use info->screen_size for remapped RAM - Fix misplaced label in failure path Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 3a6555a..47733f5 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -408,6 +408,7 @@ static int hwcur __devinitdata = 0; static int noaccel __devinitdata = 0; static int noscale __devinitdata = 0; static int paneltweak __devinitdata = 0; +static int vram __devinitdata = 0; #ifdef CONFIG_MTRR static int nomtrr __devinitdata = 0; #endif @@ -1180,7 +1181,7 @@ static int nvidiafb_check_var(struct fb_var_screeninfo *var, var->xres_virtual = (var->xres_virtual + 63) & ~63; - vramlen = info->fix.smem_len; + vramlen = info->screen_size; pitch = ((var->xres_virtual * var->bits_per_pixel) + 7) / 8; memlen = pitch * var->yres_virtual; @@ -1343,7 +1344,7 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info) /* maximize virtual vertical length */ lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); - info->var.yres_virtual = info->fix.smem_len / lpitch; + info->var.yres_virtual = info->screen_size / lpitch; info->pixmap.scan_align = 4; info->pixmap.buf_align = 4; @@ -1507,12 +1508,20 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, par->FbAddress = nvidiafb_fix.smem_start; par->FbMapSize = par->RamAmountKBytes * 1024; + if (vram && vram * 1024 * 1024 < par->FbMapSize) + par->FbMapSize = vram * 1024 * 1024; + + /* Limit amount of vram to 64 MB */ + if (par->FbMapSize > 64 * 1024 * 1024) + par->FbMapSize = 64 * 1024 * 1024; + par->FbUsableSize = par->FbMapSize - (128 * 1024); par->ScratchBufferSize = (par->Architecture < NV_ARCH_10) ? 8 * 1024 : 16 * 1024; par->ScratchBufferStart = par->FbUsableSize - par->ScratchBufferSize; info->screen_base = ioremap(nvidiafb_fix.smem_start, par->FbMapSize); - nvidiafb_fix.smem_len = par->FbUsableSize; + info->screen_size = par->FbUsableSize; + nvidiafb_fix.smem_len = par->RamAmountKBytes * 1024; if (!info->screen_base) { printk(KERN_ERR PFX "cannot ioremap FB base\n"); @@ -1524,7 +1533,8 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, #ifdef CONFIG_MTRR if (!nomtrr) { par->mtrr.vram = mtrr_add(nvidiafb_fix.smem_start, - par->FbMapSize, MTRR_TYPE_WRCOMB, 1); + par->RamAmountKBytes * 1024, + MTRR_TYPE_WRCOMB, 1); if (par->mtrr.vram < 0) { printk(KERN_ERR PFX "unable to setup MTRR\n"); } else { @@ -1566,9 +1576,9 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, err_out_iounmap_fb: iounmap(info->screen_base); + err_out_free_base1: fb_destroy_modedb(info->monspecs.modedb); nvidia_delete_i2c_busses(par); - err_out_free_base1: iounmap(par->REGS); err_out_free_base0: pci_release_regions(pd); @@ -1645,6 +1655,8 @@ static int __devinit nvidiafb_setup(char *options) noscale = 1; } else if (!strncmp(this_opt, "paneltweak:", 11)) { paneltweak = simple_strtoul(this_opt+11, NULL, 0); + } else if (!strncmp(this_opt, "vram:", 5)) { + vram = simple_strtoul(this_opt+5, NULL, 0); #ifdef CONFIG_MTRR } else if (!strncmp(this_opt, "nomtrr", 6)) { nomtrr = 1; @@ -1716,6 +1728,10 @@ module_param(forceCRTC, int, 0); MODULE_PARM_DESC(forceCRTC, "Forces usage of a particular CRTC in case autodetection " "fails. (0 or 1) (default=autodetect)"); +module_param(vram, int, 0); +MODULE_PARM_DESC(vram, + "amount of framebuffer memory to remap in MiB" + "(default=0 - remap entire memory)"); #ifdef CONFIG_MTRR module_param(nomtrr, bool, 0); MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) " -- cgit v0.10.2 From 5f76be80d96f60adfc91f2acf22b146ce0e3072f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 1 May 2005 08:59:23 -0700 Subject: [PATCH] fbdev: edid.h cleanups This patch removes some completely unused code. Signed-off-by: Adrian Bunk Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c index fa67045..cedc55c 100644 --- a/arch/i386/boot/compressed/misc.c +++ b/arch/i386/boot/compressed/misc.c @@ -12,7 +12,6 @@ #include #include #include -#include