diff options
| author | Dave Jones <davej@tetrachloride.(none)> | 2003-01-08 08:39:06 -0100 |
|---|---|---|
| committer | Dave Jones <davej@tetrachloride.(none)> | 2003-01-08 08:39:06 -0100 |
| commit | d72c8aafbe183a8745419b3e2221d9513c1df3f6 (patch) | |
| tree | 5ca60e8778f6339db0a6025cc713e4d7028aeadb | |
| parent | 2c3929fa0a5827140e032d661e43c75c62e5bdd4 (diff) | |
| parent | 9a0a4cb166a73286c4991c212425bc8f3cdc11db (diff) | |
Merge tetrachloride.(none):/mnt/stuff/kernel/2.5/bk-linus
into tetrachloride.(none):/mnt/stuff/kernel/2.5/agpgart
77 files changed, 1031 insertions, 705 deletions
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index e26819f478ba..568d9e228146 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -456,11 +456,6 @@ config NR_CPUS This is purely to save memory - each supported CPU adds approximately eight kilobytes to the kernel image. -config CLUSTERED_APIC - bool - depends on X86_NUMAQ || X86_SUMMIT - default y - # Common NUMA Features config NUMA bool "Numa Memory Allocation Support" diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 3f42c6e3f011..4a77837cca8b 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -23,7 +23,6 @@ #include <asm/mtrr.h> #include <asm/pgalloc.h> #include <asm/tlbflush.h> -#include <asm/smpboot.h> #include <mach_ipi.h> /* diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 1330f0d33bf7..c393236ad8e5 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -47,12 +47,12 @@ #include <linux/mc146818rtc.h> #include <asm/pgalloc.h> #include <asm/tlbflush.h> -#include <asm/smpboot.h> #include <asm/desc.h> #include <asm/arch_hooks.h> #include "smpboot_hooks.h" #include <mach_apic.h> +#include <mach_wakecpu.h> /* Set if we find a B stepping CPU */ static int __initdata smp_b_stepping; @@ -348,8 +348,7 @@ void __init smp_callin(void) * our local APIC. We have to wait for the IPI or we'll * lock up on an APIC access. */ - if (!clustered_apic_mode) - while (!atomic_read(&init_deasserted)); + wait_for_init_deassert(&init_deasserted); /* * (This works even if the APIC is not enabled.) @@ -398,13 +397,9 @@ void __init smp_callin(void) */ Dprintk("CALLIN, before setup_local_APIC().\n"); - /* - * Because we use NMIs rather than the INIT-STARTUP sequence to - * bootstrap the CPUs, the APIC may be in a weird state. Kick it. - */ - if (clustered_apic_mode) - clear_local_APIC(); + smp_callin_clear_local_apic(); setup_local_APIC(); + map_cpu_to_logical_apicid(); local_irq_enable(); @@ -503,63 +498,58 @@ static struct task_struct * __init fork_by_hand(void) return do_fork(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); } -/* which physical APIC ID maps to which logical CPU number */ -volatile int physical_apicid_2_cpu[MAX_APICID]; -/* which logical CPU number maps to which physical APIC ID */ -volatile int cpu_2_physical_apicid[NR_CPUS]; +#ifdef CONFIG_NUMA -/* which logical APIC ID maps to which logical CPU number */ -volatile int logical_apicid_2_cpu[MAX_APICID]; -/* which logical CPU number maps to which logical APIC ID */ -volatile int cpu_2_logical_apicid[NR_CPUS]; +/* which logical CPUs are on which nodes */ +volatile unsigned long node_2_cpu_mask[MAX_NR_NODES] = + { [0 ... MAX_NR_NODES-1] = 0 }; +/* which node each logical CPU is on */ +volatile int cpu_2_node[NR_CPUS] = { [0 ... NR_CPUS-1] = 0 }; -static inline void init_cpu_to_apicid(void) -/* Initialize all maps between cpu number and apicids */ +/* set up a mapping between cpu and node. */ +static inline void map_cpu_to_node(int cpu, int node) { - int apicid, cpu; + printk("Mapping cpu %d to node %d\n", cpu, node); + node_2_cpu_mask[node] |= (1 << cpu); + cpu_2_node[cpu] = node; +} - for (apicid = 0; apicid < MAX_APICID; apicid++) { - physical_apicid_2_cpu[apicid] = -1; - logical_apicid_2_cpu[apicid] = -1; - } - for (cpu = 0; cpu < NR_CPUS; cpu++) { - cpu_2_physical_apicid[cpu] = -1; - cpu_2_logical_apicid[cpu] = -1; - } +/* undo a mapping between cpu and node. */ +static inline void unmap_cpu_to_node(int cpu) +{ + int node; + + printk("Unmapping cpu %d from all nodes\n", cpu); + for (node = 0; node < MAX_NR_NODES; node ++) + node_2_cpu_mask[node] &= ~(1 << cpu); + cpu_2_node[cpu] = -1; } +#else /* !CONFIG_NUMA */ -static inline void map_cpu_to_boot_apicid(int cpu, int apicid) -/* - * set up a mapping between cpu and apicid. Uses logical apicids for multiquad, - * else physical apic ids - */ +#define map_cpu_to_node(cpu, node) ({}) +#define unmap_cpu_to_node(cpu) ({}) + +#endif /* CONFIG_NUMA */ + +volatile u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; + +void map_cpu_to_logical_apicid(void) { - if (clustered_apic_mode) { - logical_apicid_2_cpu[apicid] = cpu; - cpu_2_logical_apicid[cpu] = apicid; - } else { - physical_apicid_2_cpu[apicid] = cpu; - cpu_2_physical_apicid[cpu] = apicid; - } + int cpu = smp_processor_id(); + int apicid = logical_smp_processor_id(); + + cpu_2_logical_apicid[cpu] = apicid; + map_cpu_to_node(cpu, apicid_to_node(apicid)); } -static inline void unmap_cpu_to_boot_apicid(int cpu, int apicid) -/* - * undo a mapping between cpu and apicid. Uses logical apicids for multiquad, - * else physical apic ids - */ +void unmap_cpu_to_logical_apicid(int cpu) { - if (clustered_apic_mode) { - logical_apicid_2_cpu[apicid] = -1; - cpu_2_logical_apicid[cpu] = -1; - } else { - physical_apicid_2_cpu[apicid] = -1; - cpu_2_physical_apicid[cpu] = -1; - } + cpu_2_logical_apicid[cpu] = BAD_APICID; + unmap_cpu_to_node(cpu); } #if APIC_DEBUG -static inline void inquire_remote_apic(int apicid) +static inline void __inquire_remote_apic(int apicid) { int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; char *names[] = { "ID", "VERSION", "SPIV" }; @@ -654,6 +644,15 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) unsigned long send_status = 0, accept_status = 0; int maxlvt, timeout, num_starts, j; + /* + * Be paranoid about clearing APIC errors. + */ + if (APIC_INTEGRATED(apic_version[phys_apicid])) { + apic_read_around(APIC_SPIV); + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + } + Dprintk("Asserting INIT.\n"); /* @@ -775,17 +774,18 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) extern unsigned long cpu_initialized; -static void __init do_boot_cpu (int apicid) +static int __init do_boot_cpu(int apicid) /* * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad * (ie clustered apic addressing mode), this is a LOGICAL apic ID. + * Returns zero if CPU booted OK, else error code from wakeup_secondary_cpu. */ { struct task_struct *idle; - unsigned long boot_error = 0; + unsigned long boot_error; int timeout, cpu; unsigned long start_eip; - unsigned short nmi_high, nmi_low; + unsigned short nmi_high = 0, nmi_low = 0; cpu = ++cpucount; /* @@ -802,8 +802,6 @@ static void __init do_boot_cpu (int apicid) */ init_idle(idle, cpu); - map_cpu_to_boot_apicid(cpu, apicid); - idle->thread.eip = (unsigned long) start_secondary; unhash_process(idle); @@ -825,11 +823,7 @@ static void __init do_boot_cpu (int apicid) Dprintk("Setting warm reset code and vector.\n"); - if (clustered_apic_mode) { - /* stash the current NMI vector, so we can put things back */ - nmi_high = *((volatile unsigned short *) TRAMPOLINE_HIGH); - nmi_low = *((volatile unsigned short *) TRAMPOLINE_LOW); - } + store_NMI_vector(&nmi_high, &nmi_low); CMOS_WRITE(0xa, 0xf); local_flush_tlb(); @@ -840,23 +834,9 @@ static void __init do_boot_cpu (int apicid) Dprintk("3.\n"); /* - * Be paranoid about clearing APIC errors. - */ - if (!clustered_apic_mode && APIC_INTEGRATED(apic_version[apicid])) { - apic_read_around(APIC_SPIV); - apic_write(APIC_ESR, 0); - apic_read(APIC_ESR); - } - - /* - * Status is now clean - */ - boot_error = 0; - - /* * Starting actual IPI sequence... */ - wakeup_secondary_cpu(apicid, start_eip); + boot_error = wakeup_secondary_cpu(apicid, start_eip); if (!boot_error) { /* @@ -890,15 +870,12 @@ static void __init do_boot_cpu (int apicid) else /* trampoline code not run */ printk("Not responding.\n"); -#if APIC_DEBUG - if (!clustered_apic_mode) - inquire_remote_apic(apicid); -#endif + inquire_remote_apic(apicid); } } if (boot_error) { /* Try to put things back the way they were before ... */ - unmap_cpu_to_boot_apicid(cpu, apicid); + unmap_cpu_to_logical_apicid(cpu); clear_bit(cpu, &cpu_callout_map); /* was set here (do_boot_cpu()) */ clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */ cpucount--; @@ -907,11 +884,7 @@ static void __init do_boot_cpu (int apicid) /* mark "stuck" area as not stuck */ *((volatile unsigned long *)trampoline_base) = 0; - if(clustered_apic_mode) { - printk("Restoring NMI vector\n"); - *((volatile unsigned short *) TRAMPOLINE_HIGH) = nmi_high; - *((volatile unsigned short *) TRAMPOLINE_LOW) = nmi_low; - } + return boot_error; } cycles_t cacheflush_time; @@ -987,8 +960,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus) prof_multiplier[cpu] = 1; } - init_cpu_to_apicid(); - /* * Setup boot CPU information */ @@ -997,7 +968,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus) print_cpu_info(&cpu_data[0]); boot_cpu_logical_apicid = logical_smp_processor_id(); - map_cpu_to_boot_apicid(0, boot_cpu_apicid); current_thread_info()->cpu = 0; smp_tune_scheduling(); @@ -1021,10 +991,9 @@ static void __init smp_boot_cpus(unsigned int max_cpus) * CPU too, but we do it for the sake of robustness anyway. * Makes no sense to do this check in clustered apic mode, so skip it */ - if (!clustered_apic_mode && - !test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map)) { + if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { printk("weird, boot CPU (#%d) not listed by the BIOS.\n", - boot_cpu_physical_apicid); + boot_cpu_physical_apicid); phys_cpu_present_map |= (1 << hard_smp_processor_id()); } @@ -1055,6 +1024,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) connect_bsp_APIC(); setup_local_APIC(); + map_cpu_to_logical_apicid(); if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid) BUG(); @@ -1083,13 +1053,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) if (max_cpus <= cpucount+1) continue; - do_boot_cpu(apicid); - - /* - * Make sure we unmap all failed CPUs - */ - if ((boot_apicid_to_cpu(apicid) == -1) && - (phys_cpu_present_map & (1 << bit))) + if (do_boot_cpu(apicid)) printk("CPU #%d not responding - cannot use it.\n", apicid); } diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c index fe3569203ce6..cdbc7915b438 100644 --- a/arch/i386/mach-voyager/voyager_smp.c +++ b/arch/i386/mach-voyager/voyager_smp.c @@ -28,7 +28,6 @@ #include <asm/mtrr.h> #include <asm/pgalloc.h> #include <asm/tlbflush.h> -#include <asm/smpboot.h> #include <asm/desc.h> #include <asm/arch_hooks.h> diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c index 58123c0e0cdb..433e1bbc577c 100644 --- a/arch/i386/pci/numa.c +++ b/arch/i386/pci/numa.c @@ -127,7 +127,7 @@ static int __init pci_numa_init(void) return 0; pci_root_bus = pcibios_scan_root(0); - if (clustered_apic_mode && (numnodes > 1)) { + if (numnodes > 1) { for (quad = 1; quad < numnodes; ++quad) { printk("Scanning PCI bus %d for quad %d\n", QUADLOCAL2BUS(quad,0), quad); diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index d18415e983c9..140141c99c74 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -53,6 +53,7 @@ #include <linux/security.h> #include <linux/compat.h> #include <linux/vfs.h> +#include <linux/netfilter_ipv4/ip_tables.h> #include <asm/types.h> #include <asm/ipc.h> @@ -2527,6 +2528,78 @@ out: extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen); +static int do_netfilter_replace(int fd, int level, int optname, + char *optval, int optlen) +{ + struct ipt_replace32 { + char name[IPT_TABLE_MAXNAMELEN]; + __u32 valid_hooks; + __u32 num_entries; + __u32 size; + __u32 hook_entry[NF_IP_NUMHOOKS]; + __u32 underflow[NF_IP_NUMHOOKS]; + __u32 num_counters; + __u32 counters; + struct ipt_entry entries[0]; + } *repl32 = (struct ipt_replace32 *)optval; + struct ipt_replace *krepl; + struct ipt_counters *counters32; + __u32 origsize; + unsigned int kreplsize, kcountersize; + mm_segment_t old_fs; + int ret; + + if (optlen < sizeof(repl32)) + return -EINVAL; + + if (copy_from_user(&origsize, + &repl32->size, + sizeof(origsize))) + return -EFAULT; + + kreplsize = sizeof(*krepl) + origsize; + kcountersize = krepl->num_counters * sizeof(struct ipt_counters); + + /* Hack: Causes ipchains to give correct error msg --RR */ + if (optlen != kreplsize) + return -ENOPROTOOPT; + + krepl = (struct ipt_replace *)kmalloc(kreplsize, GFP_KERNEL); + if (krepl == NULL) + return -ENOMEM; + + if (copy_from_user(krepl, optval, kreplsize)) { + kfree(krepl); + return -EFAULT; + } + + counters32 = (struct ipt_counters *)AA( + ((struct ipt_replace32 *)krepl)->counters); + + kcountersize = krepl->num_counters * sizeof(struct ipt_counters); + krepl->counters = (struct ipt_counters *)kmalloc( + kcountersize, GFP_KERNEL); + if (krepl->counters == NULL) { + kfree(krepl); + return -ENOMEM; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_setsockopt(fd, level, optname, + (char *)krepl, kreplsize); + set_fs(old_fs); + + if (ret == 0 && + copy_to_user(counters32, krepl->counters, kcountersize)) + ret = -EFAULT; + + kfree(krepl->counters); + kfree(krepl); + + return ret; +} + static int do_set_attach_filter(int fd, int level, int optname, char *optval, int optlen) { @@ -2620,6 +2693,9 @@ static int do_set_sock_timeout(int fd, int level, int optname, char *optval, int asmlinkage int sys32_setsockopt(int fd, int level, int optname, char *optval, int optlen) { + if (optname == IPT_SO_SET_REPLACE) + return do_netfilter_replace(fd, level, optname, + optval, optlen); if (optname == SO_ATTACH_FILTER) return do_set_attach_filter(fd, level, optname, optval, optlen); diff --git a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c index e99063f226db..2fec0d5c4e80 100644 --- a/drivers/hotplug/ibmphp_core.c +++ b/drivers/hotplug/ibmphp_core.c @@ -769,11 +769,11 @@ static struct pci_func *ibm_slot_find (u8 busno, u8 device, u8 function) * Parameters: bus number * Returns : pci_bus * or NULL if not found */ -static struct pci_bus *find_bus (u8 busno) +static struct pci_bus *ibmphp_find_bus (u8 busno) { const struct list_head *tmp; struct pci_bus *bus; - debug ("inside find_bus, busno = %x \n", busno); + debug ("inside %s, busno = %x \n", __FUNCTION__, busno); list_for_each (tmp, &pci_root_buses) { bus = (struct pci_bus *) pci_bus_b (tmp); @@ -1002,7 +1002,7 @@ static u8 bus_structure_fixup (u8 busno) struct pci_dev *dev; u16 l; - if (find_bus (busno) || !(ibmphp_find_same_bus_num (busno))) + if (ibmphp_find_bus (busno) || !(ibmphp_find_same_bus_num (busno))) return 1; bus = kmalloc (sizeof (*bus), GFP_KERNEL); @@ -1056,7 +1056,7 @@ static int ibm_configure_device (struct pci_func *func) func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7)); if (func->dev == NULL) { - dev0.bus = find_bus (func->busno); + dev0.bus = ibmphp_find_bus (func->busno); dev0.devfn = ((func->device << 3) + (func->function & 0x7)); dev0.sysdata = dev0.bus->sysdata; @@ -1636,7 +1636,7 @@ static int __init ibmphp_init (void) return -ENOMEM; } - bus = find_bus (0); + bus = ibmphp_find_bus (0); if (!bus) { err ("Can't find the root pci bus, can not continue\n"); return -ENODEV; diff --git a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c index 5e4c1748b7d1..b6426a2277c8 100644 --- a/drivers/hotplug/pci_hotplug_core.c +++ b/drivers/hotplug/pci_hotplug_core.c @@ -561,7 +561,7 @@ static void fs_remove_file (struct dentry *dentry) up(&parent->d_inode->i_sem); } -/* yuck, WFT is this? */ +/* Weee, fun with macros... */ #define GET_STATUS(name,type) \ static int get_##name (struct hotplug_slot *slot, type *value) \ { \ @@ -661,29 +661,26 @@ static ssize_t power_write_file (struct file *file, const char *ubuff, size_t co power = (u8)(lpower & 0xff); dbg ("power = %d\n", power); + if (!try_module_get(slot->ops->owner)) { + retval = -ENODEV; + goto exit; + } switch (power) { case 0: - if (!slot->ops->disable_slot) - break; - if (try_module_get(slot->ops->owner)) { + if (slot->ops->disable_slot) retval = slot->ops->disable_slot(slot); - module_put(slot->ops->owner); - } break; case 1: - if (!slot->ops->enable_slot) - break; - if (try_module_get(slot->ops->owner)) { + if (slot->ops->enable_slot) retval = slot->ops->enable_slot(slot); - module_put(slot->ops->owner); - } break; default: err ("Illegal value specified for power\n"); retval = -EINVAL; } + module_put(slot->ops->owner); exit: kfree (buff); @@ -770,12 +767,13 @@ static ssize_t attention_write_file (struct file *file, const char *ubuff, size_ attention = (u8)(lattention & 0xff); dbg (" - attention = %d\n", attention); - if (slot->ops->set_attention_status) { - if (try_module_get(slot->ops->owner)) { - retval = slot->ops->set_attention_status(slot, attention); - module_put(slot->ops->owner); - } + if (!try_module_get(slot->ops->owner)) { + retval = -ENODEV; + goto exit; } + if (slot->ops->set_attention_status) + retval = slot->ops->set_attention_status(slot, attention); + module_put(slot->ops->owner); exit: kfree (buff); @@ -1007,12 +1005,13 @@ static ssize_t test_write_file (struct file *file, const char *ubuff, size_t cou test = (u32)(ltest & 0xffffffff); dbg ("test = %d\n", test); - if (slot->ops->hardware_test) { - if (try_module_get(slot->ops->owner)) { - retval = slot->ops->hardware_test(slot, test); - module_put(slot->ops->owner); - } + if (!try_module_get(slot->ops->owner)) { + retval = -ENODEV; + goto exit; } + if (slot->ops->hardware_test) + retval = slot->ops->hardware_test(slot, test); + module_put(slot->ops->owner); exit: kfree (buff); diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 5e125088f47c..8f6f9bde40a8 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2850,6 +2850,7 @@ static int __devinit gem_get_device_address(struct gem *gp) printk(KERN_ERR "%s: can't get mac-address\n", dev->name); return -1; } +#warning MAX_ADDR_LEN is now 32 bytes instead of 8, please fix this as appropriate memcpy(dev->dev_addr, addr, MAX_ADDR_LEN); #else get_gem_mac_nonobp(gp->pdev, gp->dev->dev_addr); diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 1aca6c7d187f..a483c4ff4e93 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -105,7 +105,7 @@ pci_free_resources(struct pci_dev *dev) void pci_remove_device(struct pci_dev *dev) { - put_device(&dev->dev); + device_unregister(&dev->dev); list_del(&dev->bus_list); list_del(&dev->global_list); pci_free_resources(dev); diff --git a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile index ebd922a22c97..7b404a1f051f 100644 --- a/drivers/scsi/aic7xxx/Makefile +++ b/drivers/scsi/aic7xxx/Makefile @@ -1,7 +1,7 @@ # # Makefile for the Linux aic7xxx SCSI driver. # -# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Makefile#3 $ +# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Makefile#5 $ # # Let kbuild descend into aicasm when cleaning @@ -44,40 +44,39 @@ clean-files += aic79xx_seq.h aic79xx_reg.h aic79xx_reg_print.c $(obj)/aic7xxx_core.o: $(obj)/aic7xxx_seq.h $(obj)/aic79xx_core.o: $(obj)/aic79xx_seq.h +$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped +$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped $(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_reg.h $(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_reg.h +aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE) := $(obj)/aic7xxx_seq.h \ + $(obj)/aic7xxx_reg.h +aic7xxx-gen-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) += $(obj)/aic7xxx_reg_print.c + +aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) := \ + -p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h + ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) -aic7xxx_gen = $(obj)/aic7xxx_seq.h $(obj)/aic7xxx_reg.h -ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y) -aic7xxx_gen += $(obj)/aic7xxx_reg_print.c -aic7xxx_asm_cmd = $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \ - -p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h \ - -o $(obj)/aic7xxx_seq.h $(src)/aic7xxx.seq -else -aic7xxx_asm_cmd = $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \ - -o $(obj)/aic7xxx_seq.h $(src)/aic7xxx.seq +$(aic7xxx-gen-y): $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm + $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \ + $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \ + $(src)/aic7xxx.seq endif -$(aic7xxx_gen): $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm - $(aic7xxx_asm_cmd) -endif +aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE) := $(obj)/aic79xx_seq.h \ + $(obj)/aic79xx_reg.h +aic79xx-gen-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) += $(obj)/aic79xx_reg_print.c + +aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) := \ + -p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y) -aic79xx_gen = $(obj)/aic79xx_seq.h $(obj)/aic79xx_reg.h -ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y) -aic79xx_gen += $(obj)/aic79xx_reg_print.c -aic79xx_asm_cmd = $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \ - -p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h \ - -o $(obj)/aic79xx_seq.h $(src)/aic79xx.seq -else -aic79xx_asm_cmd = $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \ - -o $(obj)/aic79xx_seq.h $(src)/aic79xx.seq +$(aic79xx-gen-y): $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm + $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \ + $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \ + $(src)/aic79xx.seq endif -$(aic79xx_gen): $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm - $(aic79xx_asm_cmd) -endif $(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl] $(MAKE) -C $(src)/aicasm diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index a288ed9f9b3e..1cd5afa6ebcd 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#148 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#150 $ * * $FreeBSD$ */ @@ -2321,13 +2321,13 @@ ahd_find_syncrate(struct ahd_softc *ahd, u_int *period, /* Skip all PACED only entries if IU is not available */ if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0 - && maxsync < AHD_SYNCRATE_DT) - maxsync = AHD_SYNCRATE_DT; + && *period < AHD_SYNCRATE_DT) + *period = AHD_SYNCRATE_DT; /* Skip all DT only entries if DT is not available */ if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && maxsync < AHD_SYNCRATE_ULTRA2) - maxsync = AHD_SYNCRATE_ULTRA2; + && *period < AHD_SYNCRATE_ULTRA2) + *period = AHD_SYNCRATE_ULTRA2; } /* @@ -5680,7 +5680,8 @@ ahd_init(struct ahd_softc *ahd) /*lowaddr*/BUS_SPACE_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/MAXBSIZE, /*nsegments*/AHD_NSEG, + /*maxsize*/(AHD_NSEG - 1) * PAGE_SIZE, + /*nsegments*/AHD_NSEG, /*maxsegsz*/AHD_MAXTRANSFER_SIZE, /*flags*/BUS_DMA_ALLOCNOW, &ahd->buffer_dmat) != 0) { @@ -7856,7 +7857,8 @@ ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) { ahd_print_path(ahd, scb); - printf("Handled Residual of %d bytes\n", resid); + printf("Handled %sResidual of %d bytes\n", + (scb->flags & SCB_SENSE) ? "Sense " : "", resid); } #endif } diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 02a7612a7efd..05edbed59319 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1,7 +1,7 @@ /* * Adaptec AIC79xx device driver for Linux. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#103 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#104 $ * * -------------------------------------------------------------------------- * Copyright (c) 1994-2000 Justin T. Gibbs. @@ -2058,7 +2058,7 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) * negotiation will occur for the first command, and DV * will comence should that first command be successful. */ - for (target = 0; target < AHD_NUM_TARGETS; target++) + for (target = 0; target < host->max_id; target++) ahd_linux_alloc_target(ahd, 0, target); ahd_intr_enable(ahd, TRUE); ahd_linux_start_dv(ahd); @@ -2883,6 +2883,23 @@ ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, break; } +#ifdef AHD_DEBUG + if (ahd_debug & AHD_SHOW_DV) { + int i; + + ahd_print_devinfo(ahd, devinfo); + printf("Inquiry buffer mismatch:"); + for (i = 0; i < AHD_LINUX_DV_INQ_LEN; i++) { + if ((i & 0xF) == 0) + printf("\n "); + printf("0x%x:0x0%x ", + ((uint8_t *)targ->inq_data)[i], + targ->dv_buffer[i]); + } + printf("\n"); + } +#endif + if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); break; @@ -3525,6 +3542,8 @@ ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) targ->dv_next_narrow_period = MAX(period, AHD_SYNCRATE_ULTRA2); if (targ->dv_next_wide_period == 0) targ->dv_next_wide_period = period; + if (targ->dv_max_width == 0) + targ->dv_max_width = width; if (targ->dv_max_ppr_options == 0) targ->dv_max_ppr_options = ppr_options; if (targ->dv_last_ppr_options == 0) @@ -3619,7 +3638,7 @@ ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) period++; } } else if ((ahd->features & AHD_WIDE) != 0 - && tinfo->user.width != 0 + && targ->dv_max_width != 0 && wide_speed >= fallback_speed && (targ->dv_next_wide_period <= AHD_ASYNC_XFER_PERIOD || period >= AHD_ASYNC_XFER_PERIOD)) { diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index a3377dcc6f50..ecf6fdf9ef01 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#99 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#102 $ * */ #ifndef _AIC79XX_LINUX_H_ @@ -288,7 +288,7 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec) #include <linux/smp.h> #endif -#define AIC79XX_DRIVER_VERSION "1.3.0.ALPHA6" +#define AIC79XX_DRIVER_VERSION "1.3.0.BETA2" /**************************** Front End Queues ********************************/ /* @@ -458,10 +458,11 @@ struct ahd_linux_target { /* * The next "fallback" period to use for narrow/wide transfers. */ - u_int dv_next_narrow_period; - u_int dv_next_wide_period; - u_int dv_max_ppr_options; - u_int dv_last_ppr_options; + uint8_t dv_next_narrow_period; + uint8_t dv_next_wide_period; + uint8_t dv_max_width; + uint8_t dv_max_ppr_options; + uint8_t dv_last_ppr_options; u_int dv_echo_size; ahd_dv_state dv_state; u_int dv_state_retry; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 115fcbf89e65..e8e0261dbf8f 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#19 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#20 $ */ #include "aic79xx_osm.h" @@ -170,6 +170,9 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahd->platform_data->hw_dma_mask = (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0); } + } else { + ahd_pci_set_dma_mask(pdev, 0xFFFFFFFF); + ahd->platform_data->hw_dma_mask = 0xFFFFFFFF; } #endif ahd->dev_softc = pci; diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index 7dd68a3746fd..79b1a172d6be 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -38,7 +38,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#60 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#61 $ * * $FreeBSD$ */ @@ -379,15 +379,20 @@ int ahd_pci_test_register_access(struct ahd_softc *ahd) { ahd_mode_state saved_modes; + uint32_t cmd; int error; - uint8_t seqctl; + uint8_t hcntrl; saved_modes = ahd_save_modes(ahd); error = EIO; - /* Enable PCI error interrupt status */ - seqctl = ahd_inb(ahd, SEQCTL0); - ahd_outb(ahd, SEQCTL0, seqctl & ~FAILDIS); + /* + * Enable PCI error interrupt status, but suppress NMIs + * generated by SERR raised due to target aborts. + */ + cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); + ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, + cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2); /* * First a simple test to see if any @@ -397,7 +402,8 @@ ahd_pci_test_register_access(struct ahd_softc *ahd) * be zero so it is a good register to * use for this test. */ - if (ahd_inb(ahd, HCNTRL) == 0xFF) + hcntrl = ahd_inb(ahd, HCNTRL); + if (hcntrl == 0xFF) goto fail; /* @@ -407,6 +413,10 @@ ahd_pci_test_register_access(struct ahd_softc *ahd) * either, so look for data corruption and/or flaged * PCI errors. */ + ahd_outb(ahd, HCNTRL, hcntrl|PAUSE); + while (ahd_is_paused(ahd) == 0) + ; + ahd_outb(ahd, SEQCTL0, PERRORDIS); ahd_outl(ahd, SRAM_BASE, 0x5aa555aa); if (ahd_inl(ahd, SRAM_BASE) != 0x5aa555aa) goto fail; @@ -440,7 +450,8 @@ fail: } ahd_restore_modes(ahd, saved_modes); - ahd_outb(ahd, SEQCTL0, seqctl); + ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS); + ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); return (error); } diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h index 6fa90708ad8f..2940896d5e3a 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.h +++ b/drivers/scsi/aic7xxx/aic7xxx.h @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#66 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#67 $ * * $FreeBSD$ */ @@ -1053,7 +1053,6 @@ struct ahc_softc { u_int pci_cachesize; u_int stack_size; - uint16_t *saved_stack; /* Per-Unit descriptive information */ const char *description; diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg index 1744f4f9bb54..7dc8f6d9ab69 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.reg +++ b/drivers/scsi/aic7xxx/aic7xxx.reg @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#36 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -673,6 +673,8 @@ register STACK { access_mode RO } +const STACK_SIZE 4 + /* * Board Control (p. 3-43) */ diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq index b7846350c3f2..c8cd622d52b6 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.seq +++ b/drivers/scsi/aic7xxx/aic7xxx.seq @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#52 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#53 $" PATCH_ARG_LIST = "struct ahc_softc *ahc" PREFIX = "ahc_" @@ -70,7 +70,7 @@ bus_free_sel: * Turn off the selection hardware. We need to reset the * selection request in order to perform a new selection. */ - and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; + and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP; and SIMODE1, ~ENBUSFREE; poll_for_work: call clear_target_state; diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index a69c1194203e..75cb92373161 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#105 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#108 $ * * $FreeBSD$ */ @@ -230,7 +230,6 @@ static int ahc_check_patch(struct ahc_softc *ahc, u_int start_instr, u_int *skip_addr); static void ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts); -static int ahc_probe_stack_size(struct ahc_softc *ahc); #ifdef AHC_TARGET_MODE static void ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate, @@ -1166,6 +1165,13 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_name(ahc), scbptr, scb_index); ahc_dump_card_state(ahc); } else { +#ifdef AHC_DEBUG + if ((ahc_debug & AHC_SHOW_SELTO) != 0) { + ahc_print_path(ahc, scb); + printf("Saw Selection Timeout for SCB 0x%x\n", + scb_index); + } +#endif /* * Force a renegotiation with this target just in * case the cable was pulled and will later be @@ -1178,13 +1184,6 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_force_renegotiation(ahc); ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); ahc_freeze_devq(ahc, scb); -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_SELTO) != 0) { - ahc_print_path(ahc, scb); - printf("Saw Selection Timeout for SCB 0x%x\n", - scb_index); - } -#endif } ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_restart(ahc); @@ -4005,8 +4004,6 @@ ahc_free(struct ahc_softc *ahc) free(ahc->name, M_DEVBUF); if (ahc->seep_config != NULL) free(ahc->seep_config, M_DEVBUF); - if (ahc->saved_stack != NULL) - free(ahc->saved_stack, M_DEVBUF); #ifndef __FreeBSD__ free(ahc, M_DEVBUF); #endif @@ -4542,12 +4539,6 @@ ahc_init(struct ahc_softc *ahc) size_t driver_data_size; uint32_t physaddr; - ahc->stack_size = ahc_probe_stack_size(ahc); - ahc->saved_stack = malloc(ahc->stack_size * sizeof(uint16_t), - M_DEVBUF, M_NOWAIT); - if (ahc->saved_stack == NULL) - return (ENOMEM); - #ifdef AHC_DEBUG_SEQUENCER ahc->flags |= AHC_SEQUENCER_DEBUG; #endif @@ -4602,7 +4593,8 @@ ahc_init(struct ahc_softc *ahc) /*lowaddr*/BUS_SPACE_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG, + /*maxsize*/(AHC_NSEG - 1) * PAGE_SIZE, + /*nsegments*/AHC_NSEG, /*maxsegsz*/AHC_MAXTRANSFER_SIZE, /*flags*/BUS_DMA_ALLOCNOW, &ahc->buffer_dmat) != 0) { @@ -6275,7 +6267,8 @@ ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb) #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MISC) != 0) { ahc_print_path(ahc, scb); - printf("Handled Residual of %d bytes\n", resid); + printf("Handled %sResidual of %d bytes\n", + (scb->flags & SCB_SENSE) ? "Sense " : "", resid); } #endif } @@ -6655,41 +6648,6 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts) } } -static int -ahc_probe_stack_size(struct ahc_softc *ahc) -{ - int last_probe; - - last_probe = 0; - while (1) { - int i; - - /* - * We avoid using 0 as a pattern to avoid - * confusion if the stack implementation - * "back-fills" with zeros when "poping' - * entries. - */ - for (i = 1; i <= last_probe+1; i++) { - ahc_outb(ahc, STACK, i & 0xFF); - ahc_outb(ahc, STACK, (i >> 8) & 0xFF); - } - - /* Verify */ - for (i = last_probe+1; i > 0; i--) { - u_int stack_entry; - - stack_entry = ahc_inb(ahc, STACK) - |(ahc_inb(ahc, STACK) << 8); - if (stack_entry != i) - goto sized; - } - last_probe++; - } -sized: - return (last_probe); -} - int ahc_print_register(ahc_reg_parse_entry_t *table, u_int num_entries, const char *name, u_int address, u_int value, @@ -6768,6 +6726,7 @@ ahc_dump_card_state(struct ahc_softc *ahc) cur_col = 0; if ((ahc->features & AHC_DT) != 0) ahc_scsisigi_print(ahc_inb(ahc, SCSISIGI), &cur_col, 50); + ahc_error_print(ahc_inb(ahc, ERROR), &cur_col, 50); ahc_scsiphase_print(ahc_inb(ahc, SCSIPHASE), &cur_col, 50); ahc_scsibusl_print(ahc_inb(ahc, SCSIBUSL), &cur_col, 50); ahc_lastphase_print(ahc_inb(ahc, LASTPHASE), &cur_col, 50); @@ -6787,11 +6746,8 @@ ahc_dump_card_state(struct ahc_softc *ahc) if (cur_col != 0) printf("\n"); printf("STACK:"); - for (i = 0; i < ahc->stack_size; i++) { - ahc->saved_stack[i] = - ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8); - printf(" 0x%x", ahc->saved_stack[i]); - } + for (i = 0; i < STACK_SIZE; i++) + printf(" 0x%x", ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8)); printf("\nSCB count = %d\n", ahc->scb_data->numscbs); printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index e8e2a4e91527..07087d348cd6 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1,7 +1,7 @@ /* * Adaptec AIC7xxx device driver for Linux. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#166 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#169 $ * * Copyright (c) 1994 John Aycock * The University of Calgary Department of Computer Science. @@ -576,6 +576,7 @@ static void ahc_linux_run_device_queue(struct ahc_softc*, static void ahc_linux_setup_tag_info(char *p, char *end, char *s); static void ahc_linux_setup_tag_info_global(char *p); static void ahc_linux_setup_dv(char *p, char *end, char *s); +static int aic7xxx_setup(char *s); static int ahc_linux_next_unit(void); static void ahc_runq_tasklet(unsigned long data); static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf); @@ -1297,6 +1298,7 @@ Scsi_Host_Template aic7xxx_driver_template = { */ .max_sectors = 8192, #endif +#if defined CONFIG_HIGHIO || LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) /* Assume RedHat Distribution with its different HIGHIO conventions. */ .can_dma_32 = 1, @@ -1304,6 +1306,7 @@ Scsi_Host_Template aic7xxx_driver_template = { #else .highmem_io = 1, #endif +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) .name = "aic7xxx", .slave_alloc = ahc_linux_slave_alloc, @@ -1764,7 +1767,7 @@ ahc_linux_setup_dv(char *p, char *end, char *s) * to a parameter with a ':' between the parameter and the value. * ie. aic7xxx=stpwlev:1,extended */ -int +static int aic7xxx_setup(char *s) { int i, n; @@ -1888,7 +1891,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) * negotiation will occur for the first command, and DV * will comence should that first command be successful. */ - for (target = 0; target < AHC_NUM_TARGETS; target++) { + for (target = 0; target < host->max_id*host->max_channel+1; target++) { u_int channel; channel = 0; @@ -2732,6 +2735,22 @@ ahc_linux_dv_transition(struct ahc_softc *ahc, struct scsi_cmnd *cmd, AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); break; } +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOW_DV) { + int i; + + ahc_print_devinfo(ahc, devinfo); + printf("Inquiry buffer mismatch:"); + for (i = 0; i < AHC_LINUX_DV_INQ_LEN; i++) { + if ((i & 0xF) == 0) + printf("\n "); + printf("0x%x:0x0%x ", + ((uint8_t *)targ->inq_data)[i], + targ->dv_buffer[i]); + } + printf("\n"); + } +#endif if (ahc_linux_fallback(ahc, devinfo) != 0) { AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); @@ -3365,6 +3384,8 @@ ahc_linux_fallback(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) targ->dv_next_narrow_period = MAX(period, AHC_SYNCRATE_ULTRA2); if (targ->dv_next_wide_period == 0) targ->dv_next_wide_period = period; + if (targ->dv_max_width == 0) + targ->dv_max_width = width; if (targ->dv_max_ppr_options == 0) targ->dv_max_ppr_options = ppr_options; if (targ->dv_last_ppr_options == 0) @@ -3459,7 +3480,7 @@ ahc_linux_fallback(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) period++; } } else if ((ahc->features & AHC_WIDE) != 0 - && tinfo->user.width != 0 + && targ->dv_max_width != 0 && wide_speed >= fallback_speed && (targ->dv_next_wide_period <= AHC_ASYNC_XFER_PERIOD || period >= AHC_ASYNC_XFER_PERIOD)) { diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 3b4b602f969f..c3a8ceb6fbdf 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -53,7 +53,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#114 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#118 $ * */ #ifndef _AIC7XXX_LINUX_H_ @@ -72,7 +72,6 @@ #endif #include <linux/module.h> #include <asm/byteorder.h> -#include <asm/io.h> #ifndef KERNEL_VERSION #define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) @@ -302,7 +301,7 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec) #include <linux/smp.h> #endif -#define AIC7XXX_DRIVER_VERSION "6.2.25" +#define AIC7XXX_DRIVER_VERSION "6.2.26" /**************************** Front End Queues ********************************/ /* @@ -472,10 +471,11 @@ struct ahc_linux_target { /* * The next "fallback" period to use for narrow/wide transfers. */ - u_int dv_next_narrow_period; - u_int dv_next_wide_period; - u_int dv_max_ppr_options; - u_int dv_last_ppr_options; + uint8_t dv_next_narrow_period; + uint8_t dv_next_wide_period; + uint8_t dv_max_width; + uint8_t dv_max_ppr_options; + uint8_t dv_last_ppr_options; u_int dv_echo_size; ahc_dv_state dv_state; u_int dv_state_retry; @@ -864,6 +864,7 @@ ahc_list_unlock(unsigned long *flags) #define PCIM_CMD_BUSMASTEREN 0x0004 #define PCIM_CMD_MWRICEN 0x0010 #define PCIM_CMD_PERRESPEN 0x0040 +#define PCIM_CMD_SERRESPEN 0x0100 #define PCIR_STATUS 0x06 #define PCIR_REVID 0x08 #define PCIR_PROGIF 0x09 diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index fcc865041b62..5c7bb1a2e002 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#42 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#43 $ */ #include "aic7xxx_osm.h" @@ -167,8 +167,8 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahc->platform_data->hw_dma_mask = (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0); } else { - ahc_pci_set_dma_mask(pdev, 0xffffffffULL); - ahc->platform_data->hw_dma_mask = 0xffffffffULL; + ahc_pci_set_dma_mask(pdev, 0xFFFFFFFF); + ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; } #endif ahc->dev_softc = pci; diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index b335373099f9..3522870b999e 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -39,7 +39,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#54 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#55 $ * * $FreeBSD$ */ @@ -1202,15 +1202,20 @@ done: int ahc_pci_test_register_access(struct ahc_softc *ahc) { - int error; - u_int status1; - uint8_t seqctl; + int error; + u_int status1; + uint32_t cmd; + uint8_t hcntrl; error = EIO; - /* Enable PCI error interrupt status */ - seqctl = ahc_inb(ahc, SEQCTL); - ahc_outb(ahc, SEQCTL, seqctl & ~FAILDIS); + /* + * Enable PCI error interrupt status, but suppress NMIs + * generated by SERR raised due to target aborts. + */ + cmd = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, + cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2); /* * First a simple test to see if any @@ -1220,7 +1225,8 @@ ahc_pci_test_register_access(struct ahc_softc *ahc) * be zero so it is a good register to * use for this test. */ - if (ahc_inb(ahc, HCNTRL) == 0xFF) + hcntrl = ahc_inb(ahc, HCNTRL); + if (hcntrl == 0xFF) goto fail; /* @@ -1230,8 +1236,13 @@ ahc_pci_test_register_access(struct ahc_softc *ahc) * either, so look for data corruption and/or flagged * PCI errors. */ - ahc_outl(ahc, SRAM_BASE, 0x5aa555aa); - if (ahc_inl(ahc, SRAM_BASE) != 0x5aa555aa) + ahc_outb(ahc, HCNTRL, hcntrl|PAUSE); + while (ahc_is_paused(ahc) == 0) + ; + ahc_outb(ahc, SEQCTL, PERRORDIS); + ahc_outb(ahc, SCBPTR, 0); + ahc_outl(ahc, SCB_BASE, 0x5aa555aa); + if (ahc_inl(ahc, SCB_BASE) != 0x5aa555aa) goto fail; status1 = ahc_pci_read_config(ahc->dev_softc, @@ -1248,7 +1259,8 @@ fail: ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, status1, /*bytes*/1); ahc_outb(ahc, CLRINT, CLRPARERR); - ahc_outb(ahc, SEQCTL, seqctl); + ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS); + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); return (error); } diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped index bb46dc495ac4..54a592722f7f 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#52 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#36 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#53 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $ */ typedef int (ahc_reg_print_t)(u_int, u_int *, u_int); typedef struct ahc_reg_parse_entry { @@ -1779,6 +1779,7 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define MAX_OFFSET 0xff #define BUS_16_BIT 0x01 #define SCB_UPLOAD_SIZE 0x20 +#define STACK_SIZE 0x04 /* Downloaded Constant Definitions */ diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped index 0f6df05e0315..1f5ea340c9b3 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#52 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#36 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#53 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $ */ #include "aic7xxx_osm.h" diff --git a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped index 4f97b79f97c1..bea4cd639915 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#52 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#36 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#53 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $ */ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y index 69749944b326..67e046d96625 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y @@ -38,7 +38,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#28 $ + * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#29 $ * * $FreeBSD$ */ @@ -209,7 +209,7 @@ static int is_download_const(expression_t *immed); %type <value> export ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne -%type <value> numerical_value mode_value mode_list macro_arglist +%type <value> mode_value mode_list macro_arglist %left '|' %left '&' @@ -784,17 +784,6 @@ macro_arglist: } ; -numerical_value: - T_NUMBER - { - $$ = $1; - } -| '-' T_NUMBER - { - $$ = -$2; - } -; - scratch_ram: T_SRAM '{' { diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 3871d801407b..e93c8e9b3b7a 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -47,8 +47,6 @@ struct uart_sunsab_port { struct uart_port port; /* Generic UART port */ union sab82532_async_regs *regs; /* Chip registers */ unsigned long irqflags; /* IRQ state flags */ - int xmit_fifo_size; /* TX fifo size */ - int recv_fifo_size; /* RX fifo size */ int dsr; /* Current DSR state */ unsigned int cec_timeout; /* Chip poll timeout... */ unsigned int tec_timeout; /* likewise */ @@ -57,8 +55,6 @@ struct uart_sunsab_port { unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */ unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */ int type; /* SAB82532 version */ - int sab_line; /* Internal numbering */ - unsigned int irq; /* Device interrupt */ }; /* @@ -76,6 +72,9 @@ static char *sab82532_version[16] = { #define SAB82532_MAX_TEC_TIMEOUT 200000 /* 1 character time (at 50 baud) */ #define SAB82532_MAX_CEC_TIMEOUT 50000 /* 2.5 TX CLKs (at 50 baud) */ +#define SAB82532_RECV_FIFO_SIZE 32 /* Standard async fifo sizes */ +#define SAB82532_XMIT_FIFO_SIZE 32 + static __inline__ void sunsab_tec_wait(struct uart_sunsab_port *up) { int timeout = up->tec_timeout; @@ -105,12 +104,12 @@ static void receive_chars(struct uart_sunsab_port *up, /* Read number of BYTES (Character + Status) available. */ if (stat->sreg.isr0 & SAB82532_ISR0_RPF) { - count = up->recv_fifo_size; + count = SAB82532_RECV_FIFO_SIZE; free_fifo++; } if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { - count = readb(&up->regs->r.rbcl) & (up->recv_fifo_size - 1); + count = readb(&up->regs->r.rbcl) & (SAB82532_RECV_FIFO_SIZE - 1); free_fifo++; } @@ -246,13 +245,13 @@ static void transmit_chars(struct uart_sunsab_port *up, return; } - up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS); + up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); writeb(up->interrupt_mask1, &up->regs->w.imr1); clear_bit(SAB82532_ALLS, &up->irqflags); /* Stuff 32 bytes into Transmit FIFO. */ clear_bit(SAB82532_XPR, &up->irqflags); - for (i = 0; i < up->xmit_fifo_size; i++) { + for (i = 0; i < up->port.fifosize; i++) { writeb(xmit->buf[xmit->tail], &up->regs->w.xfifo[i]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -422,15 +421,16 @@ static void sunsab_start_tx(struct uart_port *port, unsigned int tty_start) struct circ_buf *xmit = &up->port.info->xmit; int i; + up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); + writeb(up->interrupt_mask1, &up->regs->w.imr1); + if (!test_bit(SAB82532_XPR, &up->irqflags)) return; - up->interrupt_mask1 &= ~SAB82532_IMR1_XPR; - writeb(up->interrupt_mask1, &up->regs->w.imr1); clear_bit(SAB82532_ALLS, &up->irqflags); clear_bit(SAB82532_XPR, &up->irqflags); - for (i = 0; i < up->xmit_fifo_size; i++) { + for (i = 0; i < up->port.fifosize; i++) { writeb(xmit->buf[xmit->tail], &up->regs->w.xfifo[i]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -533,34 +533,8 @@ static int sunsab_startup(struct uart_port *port) writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4); writeb(SAB82532_MODE_RTS | SAB82532_MODE_FCTS | SAB82532_MODE_RAC, &up->regs->w.mode); - writeb(SAB82532_RFC_DPS | SAB82532_RFC_RFDF, &up->regs->w.rfc); - - switch (up->recv_fifo_size) { - case 1: - tmp = readb(&up->regs->w.rfc); - tmp |= SAB82532_RFC_RFTH_1; - writeb(tmp, &up->regs->w.rfc); - break; - case 4: - tmp = readb(&up->regs->w.rfc); - tmp |= SAB82532_RFC_RFTH_4; - writeb(tmp, &up->regs->w.rfc); - break; - case 16: - tmp = readb(&up->regs->w.rfc); - tmp |= SAB82532_RFC_RFTH_16; - writeb(tmp, &up->regs->w.rfc); - break; - default: - up->recv_fifo_size = 32; - /* fall through */ - case 32: - tmp = readb(&up->regs->w.rfc); - tmp |= SAB82532_RFC_RFTH_32; - writeb(tmp, &up->regs->w.rfc); - break; - }; - + writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc); + tmp = readb(&up->regs->rw.ccr0); tmp |= SAB82532_CCR0_PU; /* power-up */ writeb(tmp, &up->regs->rw.ccr0); @@ -796,7 +770,11 @@ static void sunsab_change_speed(struct uart_port *port, unsigned int cflag, static const char *sunsab_type(struct uart_port *port) { - return "SunSAB"; + struct uart_sunsab_port *up = (void *)port; + static char buf[36]; + + sprintf(buf, "SAB82532 %s", sab82532_version[up->type]); + return buf; } static void sunsab_release_port(struct uart_port *port) @@ -1011,22 +989,25 @@ static void __init sab_attach_callback(struct linux_ebus_device *edev, void *arg unsigned long regs, offset; int i; + /* Note: ports are located in reverse order */ regs = edev->resource[0].start; offset = sizeof(union sab82532_async_regs); for (i = 0; i < 2; i++) { - up = &sunsab_ports[(*instance_p * 2) + i]; + up = &sunsab_ports[(*instance_p * 2) + 1 - i]; memset(up, 0, sizeof(*up)); up->regs = ioremap(regs + offset, sizeof(union sab82532_async_regs)); - up->irq = edev->irqs[0]; - up->sab_line = 1 - i; - up->xmit_fifo_size = 32; - up->recv_fifo_size = 32; + up->port.irq = edev->irqs[0]; + up->port.fifosize = SAB82532_XMIT_FIFO_SIZE; + up->port.mapbase = (unsigned long)up->regs; + up->port.iotype = SERIAL_IO_MEM; writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc); offset -= sizeof(union sab82532_async_regs); } + + (*instance_p)++; } static int __init probe_for_sabs(void) @@ -1066,7 +1047,7 @@ static void __init sunsab_init_hw(void) up->type = readb(&up->regs->r.vstr) & 0x0f; writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr); writeb(0xff, &up->regs->w.pim); - if (up->sab_line == 0) { + if (up->port.line == 0) { up->pvr_dsr_bit = (1 << 0); up->pvr_dtr_bit = (1 << 1); } else { @@ -1082,19 +1063,14 @@ static void __init sunsab_init_hw(void) up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; - if (!(up->sab_line & 0x01)) { - if (request_irq(up->irq, sunsab_interrupt, SA_SHIRQ, - "serial(sab82532)", up)) { + if (!(up->port.line & 0x01)) { + if (request_irq(up->port.irq, sunsab_interrupt, + SA_SHIRQ, "serial(sab82532)", up)) { printk("sunsab%d: can't get IRQ %x\n", - i, up->irq); + i, up->port.irq); continue; } } - - printk(KERN_INFO - "sunsab%d at 0x%lx (irq = %s) is a SAB82532 %s\n", - i, (unsigned long)up->regs, - __irq_itoa(up->irq), sab82532_version[up->type]); } } @@ -1109,8 +1085,6 @@ static int __init sunsab_init(void) sunsab_init_hw(); sunsab_reg.minor = sunserial_current_minor; - sunserial_current_minor += num_channels; - sunsab_reg.nr = num_channels; sunsab_reg.cons = &sunsab_console; @@ -1121,8 +1095,8 @@ static int __init sunsab_init(void) for (i = 0; i < num_channels; i++) { struct uart_sunsab_port *up = &sunsab_ports[i]; - if (!(up->sab_line & 0x01)) - free_irq(up->irq, up); + if (!(up->port.line & 0x01)) + free_irq(up->port.irq, up); iounmap(up->regs); } kfree(sunsab_ports); @@ -1131,6 +1105,8 @@ static int __init sunsab_init(void) return ret; } + sunserial_current_minor += num_channels; + for (i = 0; i < num_channels; i++) { struct uart_sunsab_port *up = &sunsab_ports[i]; @@ -1151,11 +1127,12 @@ static void __exit sunsab_exit(void) uart_remove_one_port(&sunsab_reg, &up->port); - if (!(up->sab_line & 0x01)) - free_irq(up->irq, up); + if (!(up->port.line & 0x01)) + free_irq(up->port.irq, up); iounmap(up->regs); } + sunserial_current_minor -= num_channels; uart_unregister_driver(&sunsab_reg); kfree(sunsab_ports); diff --git a/fs/jfs/file.c b/fs/jfs/file.c index a813a45d8e88..cfc55c2d230a 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -102,6 +102,8 @@ struct file_operations jfs_file_operations = { .llseek = generic_file_llseek, .write = generic_file_write, .read = generic_file_read, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .readv = generic_file_readv, .writev = generic_file_writev, diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 7ef944b90a07..bc5720ac2510 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -184,9 +184,9 @@ static void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag, int cant_ static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag); static int lbmIOWait(struct lbuf * bp, int flag); static bio_end_io_t lbmIODone; +static void lbmStartIO(struct lbuf * bp); +static void lmGCwrite(struct jfs_log * log, int cant_block); -void lbmStartIO(struct lbuf * bp); -void lmGCwrite(struct jfs_log * log, int cant_block); /* @@ -744,7 +744,7 @@ int lmGroupCommit(struct jfs_log * log, struct tblock * tblk) * LOGGC_LOCK must be held by caller. * N.B. LOG_LOCK is NOT held during lmGroupCommit(). */ -void lmGCwrite(struct jfs_log * log, int cant_write) +static void lmGCwrite(struct jfs_log * log, int cant_write) { struct lbuf *bp; struct logpage *lp; @@ -893,8 +893,7 @@ void lmPostGC(struct lbuf * bp) */ if ((tblk = log->cqueue.head) && ((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) || - test_bit(log_SYNCBARRIER, &log->flag) || - test_bit(log_QUIESCE, &log->flag))) + test_bit(log_FLUSH, &log->flag))) /* * Call lmGCwrite with new group leader */ @@ -902,11 +901,13 @@ void lmPostGC(struct lbuf * bp) /* no transaction are ready yet (transactions are only just * queued (GC_QUEUE) and not entered for group commit yet). - * let the first transaction entering group commit - * will elect hetself as new group leader. + * the first transaction entering group commit + * will elect herself as new group leader. */ - else + else { log->cflag &= ~logGC_PAGEOUT; + clear_bit(log_FLUSH, &log->flag); + } //LOGGC_UNLOCK(log); spin_unlock_irqrestore(&log->gclock, flags); @@ -1049,18 +1050,12 @@ int lmLogSync(struct jfs_log * log, int nosyncwait) set_bit(log_SYNCBARRIER, &log->flag); jFYI(1, ("log barrier on: lsn=0x%x syncpt=0x%x\n", lsn, log->syncpt)); + /* + * We may have to initiate group commit + */ + jfs_flush_journal(log, 0); } - /* - * We may have to initiate group commit - */ - LOGGC_LOCK(log); - if (log->cqueue.head && !(log->cflag & logGC_PAGEOUT)) { - log->cflag |= logGC_PAGEOUT; - lmGCwrite(log, 0); - } - LOGGC_UNLOCK(log); - return lsn; } @@ -1416,21 +1411,22 @@ int lmLogClose(struct super_block *sb, struct jfs_log * log) /* - * NAME: lmLogWait() + * NAME: jfs_flush_journal() * - * FUNCTION: wait for all outstanding log records to be written to disk + * FUNCTION: initiate write of any outstanding transactions to the journal + * and optionally wait until they are all written to disk */ -void lmLogWait(struct jfs_log *log) +void jfs_flush_journal(struct jfs_log *log, int wait) { int i; - jFYI(1, ("lmLogWait: log:0x%p\n", log)); + jFYI(1, ("jfs_flush_journal: log:0x%p wait=%d\n", log, wait)); /* * This ensures that we will keep writing to the journal as long * as there are unwritten commit records */ - set_bit(log_QUIESCE, &log->flag); + set_bit(log_FLUSH, &log->flag); /* * Initiate I/O on outstanding transactions @@ -1442,6 +1438,9 @@ void lmLogWait(struct jfs_log *log) } LOGGC_UNLOCK(log); + if (!wait) + return; + if (log->cqueue.head || !list_empty(&log->synclist)) { /* * If there was very recent activity, we may need to wait @@ -1459,7 +1458,7 @@ void lmLogWait(struct jfs_log *log) assert(log->cqueue.head == NULL); assert(list_empty(&log->synclist)); - clear_bit(log_QUIESCE, &log->flag); /* Probably not needed */ + clear_bit(log_FLUSH, &log->flag); } /* @@ -1488,7 +1487,7 @@ int lmLogShutdown(struct jfs_log * log) jFYI(1, ("lmLogShutdown: log:0x%p\n", log)); - lmLogWait(log); + jfs_flush_journal(log, 1); /* * We need to make sure all of the "written" metapages @@ -1946,7 +1945,7 @@ static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag) * * serialization: LCACHE_LOCK() is NOT held during log i/o; */ -void lbmStartIO(struct lbuf * bp) +static void lbmStartIO(struct lbuf * bp) { struct bio *bio; struct jfs_log *log = bp->l_log; diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h index 112877ce045f..45eb3316d991 100644 --- a/fs/jfs/jfs_logmgr.h +++ b/fs/jfs/jfs_logmgr.h @@ -424,6 +424,7 @@ struct jfs_log { #define log_INLINELOG 1 #define log_SYNCBARRIER 2 #define log_QUIESCE 3 +#define log_FLUSH 4 /* * group commit flag @@ -501,11 +502,11 @@ struct logsyncblk { } extern int lmLogOpen(struct super_block *sb, struct jfs_log ** log); -extern void lmLogWait(struct jfs_log * log); extern int lmLogClose(struct super_block *sb, struct jfs_log * log); extern int lmLogSync(struct jfs_log * log, int nosyncwait); extern int lmLogShutdown(struct jfs_log * log); extern int lmLogInit(struct jfs_log * log); extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize); +extern void jfs_flush_journal(struct jfs_log * log, int wait); #endif /* _H_JFS_LOGMGR */ diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index e7971c7dd725..3a9fef349e74 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -158,7 +158,6 @@ struct { * external references */ extern int lmGroupCommit(struct jfs_log *, struct tblock *); -extern int lmGCwrite(struct jfs_log *, int); extern void lmSync(struct jfs_log *); extern int jfs_commit_inode(struct inode *, int); extern int jfs_stop_threads; @@ -2969,12 +2968,7 @@ restart: /* * We may need to kick off the group commit */ - spin_lock_irq(&log->gclock); // LOGGC_LOCK - if (log->cqueue.head && !(log->cflag & logGC_PAGEOUT)) { - log->cflag |= logGC_PAGEOUT; - lmGCwrite(log, 0); - } - spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK + jfs_flush_journal(log, 0); } /* diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c index 88e747f514c1..a81ef8c832bb 100644 --- a/fs/jfs/jfs_umount.c +++ b/fs/jfs/jfs_umount.c @@ -69,7 +69,7 @@ int jfs_umount(struct super_block *sb) /* * Wait for outstanding transactions to be written to log: */ - lmLogWait(log); + jfs_flush_journal(log, 1); /* * close fileset inode allocation map (aka fileset inode) @@ -153,7 +153,7 @@ int jfs_umount_rw(struct super_block *sb) * * remove file system from log active file system list. */ - lmLogWait(log); + jfs_flush_journal(log, 1); /* * Make sure all metadata makes it to disk diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c index 0094be7e0e1b..07cde7e7cad8 100644 --- a/fs/jfs/resize.c +++ b/fs/jfs/resize.c @@ -514,7 +514,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) mark_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh2); wait_on_buffer(bh2); - brelse(bh); + brelse(bh2); } /* write primary superblock */ diff --git a/fs/jfs/super.c b/fs/jfs/super.c index cc2731f0ca6d..fcc1ad80ceba 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -382,6 +382,17 @@ static struct super_block *jfs_get_sb(struct file_system_type *fs_type, return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super); } +static int jfs_sync_fs(struct super_block *sb, int wait) +{ + struct jfs_log *log = JFS_SBI(sb)->log; + + /* log == NULL indicates read-only mount */ + if (log) + jfs_flush_journal(log, wait); + + return 0; +} + static struct super_operations jfs_super_operations = { .alloc_inode = jfs_alloc_inode, .destroy_inode = jfs_destroy_inode, @@ -389,6 +400,7 @@ static struct super_operations jfs_super_operations = { .write_inode = jfs_write_inode, .delete_inode = jfs_delete_inode, .put_super = jfs_put_super, + .sync_fs = jfs_sync_fs, .write_super_lockfs = jfs_write_super_lockfs, .unlockfs = jfs_unlockfs, .statfs = jfs_statfs, diff --git a/include/asm-i386/mach-default/mach_apic.h b/include/asm-i386/mach-default/mach_apic.h index 905bc7a1284d..9405531fb35b 100644 --- a/include/asm-i386/mach-default/mach_apic.h +++ b/include/asm-i386/mach-default/mach_apic.h @@ -10,6 +10,7 @@ #endif #define no_balance_irq (0) +#define esr_disable (0) #define APIC_BROADCAST_ID 0x0F #define check_apicid_used(bitmap, apicid) (bitmap & (1 << apicid)) @@ -53,6 +54,11 @@ static inline int multi_timer_check(int apic, int irq) return 0; } +static inline int apicid_to_node(int logical_apicid) +{ + return 0; +} + static inline int cpu_present_to_apicid(int mps_cpu) { return mps_cpu; @@ -73,10 +79,13 @@ static inline int mpc_apic_id(struct mpc_config_processor *m, int quad) return (m->mpc_apicid); } -#define WAKE_SECONDARY_VIA_INIT - static inline void setup_portio_remap(void) { } +static inline int check_phys_apicid_present(int boot_cpu_physical_apicid) +{ + return test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map); +} + #endif /* __ASM_MACH_APIC_H */ diff --git a/include/asm-i386/mach-default/mach_wakecpu.h b/include/asm-i386/mach-default/mach_wakecpu.h new file mode 100644 index 000000000000..673b85c9b273 --- /dev/null +++ b/include/asm-i386/mach-default/mach_wakecpu.h @@ -0,0 +1,41 @@ +#ifndef __ASM_MACH_WAKECPU_H +#define __ASM_MACH_WAKECPU_H + +/* + * This file copes with machines that wakeup secondary CPUs by the + * INIT, INIT, STARTUP sequence. + */ + +#define WAKE_SECONDARY_VIA_INIT + +#define TRAMPOLINE_LOW phys_to_virt(0x467) +#define TRAMPOLINE_HIGH phys_to_virt(0x469) + +#define boot_cpu_apicid boot_cpu_physical_apicid + +static inline void wait_for_init_deassert(atomic_t *deassert) +{ + while (!atomic_read(deassert)); + return; +} + +/* Nothing to do for most platforms, since cleared by the INIT cycle */ +static inline void smp_callin_clear_local_apic(void) +{ +} + +static inline void store_NMI_vector(unsigned short *high, unsigned short *low) +{ +} + +static inline void restore_NMI_vector(unsigned short *high, unsigned short *low) +{ +} + +#if APIC_DEBUG + #define inquire_remote_apic(apicid) __inquire_remote_apic(apicid) +#else + #define inquire_remote_apic(apicid) {} +#endif + +#endif /* __ASM_MACH_WAKECPU_H */ diff --git a/include/asm-i386/mach-numaq/mach_apic.h b/include/asm-i386/mach-numaq/mach_apic.h index 94d2f5f28275..05c0fd19266d 100644 --- a/include/asm-i386/mach-numaq/mach_apic.h +++ b/include/asm-i386/mach-numaq/mach_apic.h @@ -1,14 +1,15 @@ #ifndef __ASM_MACH_APIC_H #define __ASM_MACH_APIC_H -#define APIC_DFR_VALUE (APIC_DFR_FLAT) +#define APIC_DFR_VALUE (APIC_DFR_CLUSTER) #define TARGET_CPUS (0xf) #define no_balance_irq (1) +#define esr_disable (1) #define APIC_BROADCAST_ID 0x0F -#define check_apicid_used(bitmap, apicid) (bitmap & (1 << apicid)) +#define check_apicid_used(bitmap, apicid) ((bitmap) & (1 << (apicid))) static inline int apic_id_registered(void) { @@ -26,6 +27,10 @@ static inline void clustered_apic_check(void) "NUMA-Q", nr_ioapics); } +/* + * Skip adding the timer int on secondary nodes, which causes + * a small but painful rift in the time-space continuum. + */ static inline int multi_timer_check(int apic, int irq) { return (apic != 0 && irq == 0); @@ -47,14 +52,14 @@ static inline int generate_logical_apicid(int quad, int phys_apicid) return ( (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1) ); } -static inline int apicid_to_quad(int logical_apicid) +static inline int apicid_to_node(int logical_apicid) { return (logical_apicid >> 4); } static inline unsigned long apicid_to_cpu_present(int logical_apicid) { - return ( (logical_apicid&0xf) << (4*apicid_to_quad(logical_apicid)) ); + return ( (logical_apicid&0xf) << (4*apicid_to_node(logical_apicid)) ); } static inline int mpc_apic_id(struct mpc_config_processor *m, int quad) @@ -69,8 +74,6 @@ static inline int mpc_apic_id(struct mpc_config_processor *m, int quad) return logical_apicid; } -#define WAKE_SECONDARY_VIA_NMI - static inline void setup_portio_remap(void) { if (numnodes <= 1) @@ -82,4 +85,9 @@ static inline void setup_portio_remap(void) (u_long) xquad_portio, (u_long) numnodes*XQUAD_PORTIO_QUAD); } +static inline int check_phys_apicid_present(int boot_cpu_physical_apicid) +{ + return (1); +} + #endif /* __ASM_MACH_APIC_H */ diff --git a/include/asm-i386/mach-numaq/mach_wakecpu.h b/include/asm-i386/mach-numaq/mach_wakecpu.h new file mode 100644 index 000000000000..00530041a991 --- /dev/null +++ b/include/asm-i386/mach-numaq/mach_wakecpu.h @@ -0,0 +1,43 @@ +#ifndef __ASM_MACH_WAKECPU_H +#define __ASM_MACH_WAKECPU_H + +/* This file copes with machines that wakeup secondary CPUs by NMIs */ + +#define WAKE_SECONDARY_VIA_NMI + +#define TRAMPOLINE_LOW phys_to_virt(0x8) +#define TRAMPOLINE_HIGH phys_to_virt(0xa) + +#define boot_cpu_apicid boot_cpu_logical_apicid + +/* We don't do anything here because we use NMI's to boot instead */ +static inline void wait_for_init_deassert(atomic_t *deassert) +{ +} + +/* + * Because we use NMIs rather than the INIT-STARTUP sequence to + * bootstrap the CPUs, the APIC may be in a weird state. Kick it. + */ +static inline void smp_callin_clear_local_apic(void) +{ + clear_local_APIC(); +} + +static inline void store_NMI_vector(unsigned short *high, unsigned short *low) +{ + printk("Storing NMI vector\n"); + *high = *((volatile unsigned short *) TRAMPOLINE_HIGH); + *low = *((volatile unsigned short *) TRAMPOLINE_LOW); +} + +static inline void restore_NMI_vector(unsigned short *high, unsigned short *low) +{ + printk("Restoring NMI vector\n"); + *((volatile unsigned short *) TRAMPOLINE_HIGH) = *high; + *((volatile unsigned short *) TRAMPOLINE_LOW) = *low; +} + +#define inquire_remote_apic(apicid) {} + +#endif /* __ASM_MACH_WAKECPU_H */ diff --git a/include/asm-i386/mach-summit/mach_apic.h b/include/asm-i386/mach-summit/mach_apic.h index bf601c3368ad..78f6b26f0ead 100644 --- a/include/asm-i386/mach-summit/mach_apic.h +++ b/include/asm-i386/mach-summit/mach_apic.h @@ -3,6 +3,8 @@ extern int x86_summit; +#define esr_disable (1) + #define XAPIC_DEST_CPUS_MASK 0x0Fu #define XAPIC_DEST_CLUSTER_MASK 0xF0u @@ -32,6 +34,11 @@ static inline void clustered_apic_check(void) (x86_summit ? "Summit" : "Flat"), nr_ioapics); } +static inline int apicid_to_node(int logical_apicid) +{ + return (logical_apicid >> 5); /* 2 clusterids per CEC */ +} + static inline int cpu_present_to_apicid(int mps_cpu) { if (x86_summit) @@ -54,10 +61,13 @@ static inline unsigned long apicid_to_phys_cpu_present(int apicid) return (1ul << apicid); } -#define WAKE_SECONDARY_VIA_INIT - static inline void setup_portio_remap(void) { } +static inline int check_phys_apicid_present(int boot_cpu_physical_apicid) +{ + return (1); +} + #endif /* __ASM_MACH_APIC_H */ diff --git a/include/asm-i386/numaq.h b/include/asm-i386/numaq.h index 6f52745df91c..1d9c8d48f06a 100644 --- a/include/asm-i386/numaq.h +++ b/include/asm-i386/numaq.h @@ -28,8 +28,6 @@ #ifdef CONFIG_X86_NUMAQ -#include <asm/smpboot.h> - /* * for now assume that 64Gb is max amount of RAM for whole system * 64Gb / 4096bytes/page = 16777216 pages diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h index 71d58561d39c..85c61d5f9497 100644 --- a/include/asm-i386/smp.h +++ b/include/asm-i386/smp.h @@ -22,22 +22,12 @@ #endif #endif -#ifdef CONFIG_CLUSTERED_APIC +#ifdef CONFIG_X86_NUMAQ #define INT_DELIVERY_MODE 0 /* physical delivery on LOCAL quad */ #else #define INT_DELIVERY_MODE 1 /* logical delivery broadcast to all procs */ #endif -#ifndef clustered_apic_mode - #ifdef CONFIG_CLUSTERED_APIC - #define clustered_apic_mode (1) - #define esr_disable (1) - #else /* !CONFIG_CLUSTERED_APIC */ - #define clustered_apic_mode (0) - #define esr_disable (0) - #endif /* CONFIG_CLUSTERED_APIC */ -#endif - #define BAD_APICID 0xFFu #ifdef CONFIG_SMP #ifndef __ASSEMBLY__ @@ -62,15 +52,7 @@ extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); extern void zap_low_mappings (void); -/* - * Some lowlevel functions might want to know about - * the real APIC ID <-> CPU # mapping. - */ #define MAX_APICID 256 -extern volatile int cpu_to_physical_apicid[NR_CPUS]; -extern volatile int physical_apicid_to_cpu[MAX_APICID]; -extern volatile int cpu_to_logical_apicid[NR_CPUS]; -extern volatile int logical_apicid_to_cpu[MAX_APICID]; /* * This function is needed by all SMP systems. It must _always_ be valid @@ -100,6 +82,15 @@ static inline int num_booting_cpus(void) return hweight32(cpu_callout_map); } +/* Mapping from cpu number to logical apicid */ +extern volatile u8 cpu_2_logical_apicid[]; +static inline int cpu_to_logical_apicid(int cpu) +{ + return (int)cpu_2_logical_apicid[cpu]; +} +extern void map_cpu_to_logical_apicid(void); +extern void unmap_cpu_to_logical_apicid(int cpu); + extern inline int any_online_cpu(unsigned int mask) { if (mask & cpu_online_map) diff --git a/include/asm-i386/smpboot.h b/include/asm-i386/smpboot.h deleted file mode 100644 index a3840aa6eca8..000000000000 --- a/include/asm-i386/smpboot.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __ASM_SMPBOOT_H -#define __ASM_SMPBOOT_H - -#ifndef clustered_apic_mode - #ifdef CONFIG_CLUSTERED_APIC - #define clustered_apic_mode (1) - #else /* !CONFIG_CLUSTERED_APIC */ - #define clustered_apic_mode (0) - #endif /* CONFIG_CLUSTERED_APIC */ -#endif - -#ifdef CONFIG_CLUSTERED_APIC - #define TRAMPOLINE_LOW phys_to_virt(0x8) - #define TRAMPOLINE_HIGH phys_to_virt(0xa) -#else /* !CONFIG_CLUSTERED_APIC */ - #define TRAMPOLINE_LOW phys_to_virt(0x467) - #define TRAMPOLINE_HIGH phys_to_virt(0x469) -#endif /* CONFIG_CLUSTERED_APIC */ - -#ifdef CONFIG_CLUSTERED_APIC - #define boot_cpu_apicid boot_cpu_logical_apicid -#else /* !CONFIG_CLUSTERED_APIC */ - #define boot_cpu_apicid boot_cpu_physical_apicid -#endif /* CONFIG_CLUSTERED_APIC */ - -/* - * Mappings between logical cpu number and logical / physical apicid - * The first four macros are trivial, but it keeps the abstraction consistent - */ -extern volatile int logical_apicid_2_cpu[]; -extern volatile int cpu_2_logical_apicid[]; -extern volatile int physical_apicid_2_cpu[]; -extern volatile int cpu_2_physical_apicid[]; - -#define logical_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid] -#define cpu_to_logical_apicid(cpu) cpu_2_logical_apicid[cpu] -#define physical_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid] -#define cpu_to_physical_apicid(cpu) cpu_2_physical_apicid[cpu] -#ifdef CONFIG_CLUSTERED_APIC /* use logical IDs to bootstrap */ -#define boot_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid] -#define cpu_to_boot_apicid(cpu) cpu_2_logical_apicid[cpu] -#else /* !CONFIG_CLUSTERED_APIC */ /* use physical IDs to bootstrap */ -#define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid] -#define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu] -#endif /* CONFIG_CLUSTERED_APIC */ - - -#endif diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h index d3bdbb0c40c6..3609d59e8c30 100644 --- a/include/asm-i386/topology.h +++ b/include/asm-i386/topology.h @@ -27,12 +27,17 @@ #ifndef _ASM_I386_TOPOLOGY_H #define _ASM_I386_TOPOLOGY_H -#ifdef CONFIG_X86_NUMAQ +#ifdef CONFIG_NUMA -#include <asm/smpboot.h> +/* Mappings between logical cpu number and node number */ +extern volatile unsigned long node_2_cpu_mask[]; +extern volatile int cpu_2_node[]; /* Returns the number of the node containing CPU 'cpu' */ -#define __cpu_to_node(cpu) (cpu_to_logical_apicid(cpu) >> 4) +static inline int __cpu_to_node(int cpu) +{ + return cpu_2_node[cpu]; +} /* Returns the number of the node containing MemBlk 'memblk' */ #define __memblk_to_node(memblk) (memblk) @@ -41,49 +46,22 @@ so it is a pretty simple function! */ #define __parent_node(node) (node) -/* Returns the number of the first CPU on Node 'node'. - * This should be changed to a set of cached values - * but this will do for now. - */ -static inline int __node_to_first_cpu(int node) -{ - int i, cpu, logical_apicid = node << 4; - - for(i = 1; i < 16; i <<= 1) - /* check to see if the cpu is in the system */ - if ((cpu = logical_apicid_to_cpu(logical_apicid | i)) >= 0) - /* if yes, return it to caller */ - return cpu; - - BUG(); /* couldn't find a cpu on given node */ - return -1; -} - -/* Returns a bitmask of CPUs on Node 'node'. - * This should be changed to a set of cached bitmasks - * but this will do for now. - */ +/* Returns a bitmask of CPUs on Node 'node'. */ static inline unsigned long __node_to_cpu_mask(int node) { - int i, cpu, logical_apicid = node << 4; - unsigned long mask = 0UL; - - if (sizeof(unsigned long) * 8 < NR_CPUS) - BUG(); - - for(i = 1; i < 16; i <<= 1) - /* check to see if the cpu is in the system */ - if ((cpu = logical_apicid_to_cpu(logical_apicid | i)) >= 0) - /* if yes, add to bitmask */ - mask |= 1 << cpu; + return node_2_cpu_mask[node]; +} - return mask; +/* Returns the number of the first CPU on Node 'node'. */ +static inline int __node_to_first_cpu(int node) +{ + return __ffs(__node_to_cpu_mask(node)); } /* Returns the number of the first MemBlk on Node 'node' */ #define __node_to_memblk(node) (node) -#else /* !CONFIG_X86_NUMAQ */ +#else /* !CONFIG_NUMA */ /* * Other i386 platforms should define their own version of the * above macros here. @@ -91,6 +69,6 @@ static inline unsigned long __node_to_cpu_mask(int node) #include <asm-generic/topology.h> -#endif /* CONFIG_X86_NUMAQ */ +#endif /* CONFIG_NUMA */ #endif /* _ASM_I386_TOPOLOGY_H */ diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index dd936fe6180e..77906e130efd 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -40,6 +40,7 @@ #define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ #define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */ #define ARPHRD_EUI64 27 /* EUI-64 */ +#define ARPHRD_INFINIBAND 32 /* InfiniBand */ /* Dummy types for non ARP hardware */ #define ARPHRD_SLIP 256 diff --git a/include/linux/module.h b/include/linux/module.h index 54214da9a651..8b0084419604 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -328,7 +328,7 @@ search_module_extables(unsigned long addr) } /* Is this address in a module? */ -static int module_text_address(unsigned long addr) +static inline int module_text_address(unsigned long addr) { return 0; } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 888d520fd319..2a6e10e6e598 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -66,7 +66,7 @@ struct vlan_group; #endif -#define MAX_ADDR_LEN 8 /* Largest hardware address length */ +#define MAX_ADDR_LEN 32 /* Largest hardware address length */ /* * Compute the worst case header length according to the protocols diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 57296f48dc02..40ceec333586 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -17,6 +17,7 @@ #define RTM_NEWLINK (RTM_BASE+0) #define RTM_DELLINK (RTM_BASE+1) #define RTM_GETLINK (RTM_BASE+2) +#define RTM_SETLINK (RTM_BASE+3) #define RTM_NEWADDR (RTM_BASE+4) #define RTM_DELADDR (RTM_BASE+5) diff --git a/include/net/icmp.h b/include/net/icmp.h index f757af415632..2e11a0b2355c 100644 --- a/include/net/icmp.h +++ b/include/net/icmp.h @@ -23,6 +23,7 @@ #include <net/sock.h> #include <net/protocol.h> +#include <net/snmp.h> #include <linux/ip.h> struct icmp_err { @@ -31,10 +32,22 @@ struct icmp_err { }; extern struct icmp_err icmp_err_convert[]; -extern struct icmp_mib icmp_statistics[NR_CPUS*2]; +DECLARE_SNMP_STAT(struct icmp_mib, icmp_statistics); #define ICMP_INC_STATS(field) SNMP_INC_STATS(icmp_statistics, field) #define ICMP_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmp_statistics, field) #define ICMP_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmp_statistics, field) +#define ICMP_INC_STATS_FIELD(offt) \ + (*((unsigned long *) ((void *) \ + per_cpu_ptr(icmp_statistics[!in_softirq()],\ + smp_processor_id())) + offt))++; +#define ICMP_INC_STATS_BH_FIELD(offt) \ + (*((unsigned long *) ((void *) \ + per_cpu_ptr(icmp_statistics[0], \ + smp_processor_id())) + offt))++; +#define ICMP_INC_STATS_USER_FIELD(offt) \ + (*((unsigned long *) ((void *) \ + per_cpu_ptr(icmp_statistics[1], \ + smp_processor_id())) + offt))++; extern void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info); extern int icmp_rcv(struct sk_buff *skb); diff --git a/include/net/ip.h b/include/net/ip.h index 7b365788fe00..f3c975e75409 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -149,14 +149,16 @@ struct ipv4_config }; extern struct ipv4_config ipv4_config; -extern struct ip_mib ip_statistics[NR_CPUS*2]; +DECLARE_SNMP_STAT(struct ip_mib, ip_statistics); #define IP_INC_STATS(field) SNMP_INC_STATS(ip_statistics, field) #define IP_INC_STATS_BH(field) SNMP_INC_STATS_BH(ip_statistics, field) #define IP_INC_STATS_USER(field) SNMP_INC_STATS_USER(ip_statistics, field) -extern struct linux_mib net_statistics[NR_CPUS*2]; +DECLARE_SNMP_STAT(struct linux_mib, net_statistics); #define NET_INC_STATS(field) SNMP_INC_STATS(net_statistics, field) #define NET_INC_STATS_BH(field) SNMP_INC_STATS_BH(net_statistics, field) #define NET_INC_STATS_USER(field) SNMP_INC_STATS_USER(net_statistics, field) +#define NET_ADD_STATS_BH(field, adnd) SNMP_ADD_STATS_BH(net_statistics, field, adnd) +#define NET_ADD_STATS_USER(field, adnd) SNMP_ADD_STATS_USER(net_statistics, field, adnd) extern int sysctl_local_port_range[2]; extern int sysctl_ip_default_ttl; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 5b4af83c5b52..e9ee8854929e 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -19,6 +19,7 @@ #include <asm/hardirq.h> #include <net/ndisc.h> #include <net/flow.h> +#include <net/snmp.h> #define SIN6_LEN_RFC2133 24 @@ -105,15 +106,19 @@ struct frag_hdr { /* sysctls */ extern int sysctl_ipv6_bindv6only; -extern struct ipv6_mib ipv6_statistics[NR_CPUS*2]; +DECLARE_SNMP_STAT(struct ipv6_mib, ipv6_statistics); #define IP6_INC_STATS(field) SNMP_INC_STATS(ipv6_statistics, field) #define IP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(ipv6_statistics, field) #define IP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(ipv6_statistics, field) -extern struct icmpv6_mib icmpv6_statistics[NR_CPUS*2]; +DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); #define ICMP6_INC_STATS(field) SNMP_INC_STATS(icmpv6_statistics, field) #define ICMP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmpv6_statistics, field) #define ICMP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmpv6_statistics, field) -extern struct udp_mib udp_stats_in6[NR_CPUS*2]; +#define ICMP6_STATS_PTR_BH(field) \ + (& \ + ((per_cpu_ptr(icmpv6_statistics[0], smp_processor_id()))-> \ + field)) +DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6); #define UDP6_INC_STATS(field) SNMP_INC_STATS(udp_stats_in6, field) #define UDP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_stats_in6, field) #define UDP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_stats_in6, field) diff --git a/include/net/route.h b/include/net/route.h index 593311a57fca..ba15b5140798 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -102,7 +102,11 @@ struct rt_cache_stat unsigned int gc_ignored; unsigned int gc_goal_miss; unsigned int gc_dst_overflow; -} ____cacheline_aligned_in_smp; +}; + +extern struct rt_cache_stat *rt_cache_stat; +#define RT_CACHE_STAT_INC(field) \ + (per_cpu_ptr(rt_cache_stat, smp_processor_id())->field++) extern struct ip_rt_acct *ip_rt_acct; diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index f12e54cd4919..297e83dc6c25 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -203,7 +203,7 @@ extern void sctp_hash_digest(const char *secret, const int secret_len, #define SCTP_SOCK_SLEEP_POST(sk) SOCK_SLEEP_POST(sk) /* SCTP SNMP MIB stats handlers */ -extern struct sctp_mib sctp_statistics[NR_CPUS * 2]; +DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics); #define SCTP_INC_STATS(field) SNMP_INC_STATS(sctp_statistics, field) #define SCTP_INC_STATS_BH(field) SNMP_INC_STATS_BH(sctp_statistics, field) #define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(sctp_statistics, field) diff --git a/include/net/snmp.h b/include/net/snmp.h index 553e8c0eedce..3b3ed7252d38 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -62,7 +62,7 @@ struct ip_mib unsigned long IpFragFails; unsigned long IpFragCreates; unsigned long __pad[0]; -} ____cacheline_aligned; +}; struct ipv6_mib { @@ -89,7 +89,7 @@ struct ipv6_mib unsigned long Ip6InMcastPkts; unsigned long Ip6OutMcastPkts; unsigned long __pad[0]; -} ____cacheline_aligned; +}; struct icmp_mib { @@ -121,7 +121,7 @@ struct icmp_mib unsigned long IcmpOutAddrMaskReps; unsigned long dummy; unsigned long __pad[0]; -} ____cacheline_aligned; +}; struct icmpv6_mib { @@ -159,7 +159,7 @@ struct icmpv6_mib unsigned long Icmp6OutGroupMembResponses; unsigned long Icmp6OutGroupMembReductions; unsigned long __pad[0]; -} ____cacheline_aligned; +}; struct tcp_mib { @@ -178,7 +178,7 @@ struct tcp_mib unsigned long TcpInErrs; unsigned long TcpOutRsts; unsigned long __pad[0]; -} ____cacheline_aligned; +}; struct udp_mib { @@ -187,7 +187,7 @@ struct udp_mib unsigned long UdpInErrors; unsigned long UdpOutDatagrams; unsigned long __pad[0]; -} ____cacheline_aligned; +}; /* draft-ietf-sigtran-sctp-mib-07.txt */ struct sctp_mib @@ -216,7 +216,7 @@ struct sctp_mib unsigned long SctpValCookieLife; unsigned long SctpMaxInitRetr; unsigned long __pad[0]; -} ____cacheline_aligned; +}; struct linux_mib { @@ -286,7 +286,7 @@ struct linux_mib unsigned long TCPAbortFailed; unsigned long TCPMemoryPressures; unsigned long __pad[0]; -} ____cacheline_aligned; +}; /* @@ -294,8 +294,25 @@ struct linux_mib * addl $1,memory is atomic against interrupts (but atomic_inc would be overkill because of the lock * cycles). Wants new nonlocked_atomic_inc() primitives -AK */ -#define SNMP_INC_STATS(mib, field) ((mib)[2*smp_processor_id()+!in_softirq()].field++) -#define SNMP_INC_STATS_BH(mib, field) ((mib)[2*smp_processor_id()].field++) -#define SNMP_INC_STATS_USER(mib, field) ((mib)[2*smp_processor_id()+1].field++) +#define DEFINE_SNMP_STAT(type, name) \ + __typeof__(type) *name[2] +#define DECLARE_SNMP_STAT(type, name) \ + extern __typeof__(type) *name[2] + +#define SNMP_STAT_USRPTR(name) (name[0]) +#define SNMP_STAT_BHPTR(name) (name[1]) + +#define SNMP_INC_STATS_BH(mib, field) \ + (per_cpu_ptr(mib[0], smp_processor_id())->field++) +#define SNMP_INC_STATS_USER(mib, field) \ + (per_cpu_ptr(mib[1], smp_processor_id())->field++) +#define SNMP_INC_STATS(mib, field) \ + (per_cpu_ptr(mib[!in_softirq()], smp_processor_id())->field++) +#define SNMP_DEC_STATS(mib, field) \ + (per_cpu_ptr(mib[!in_softirq()], smp_processor_id())->field--) +#define SNMP_ADD_STATS_BH(mib, field, addend) \ + (per_cpu_ptr(mib[0], smp_processor_id())->field += addend) +#define SNMP_ADD_STATS_USER(mib, field, addend) \ + (per_cpu_ptr(mib[1], smp_processor_id())->field += addend) #endif diff --git a/include/net/tcp.h b/include/net/tcp.h index 38cc0e90793b..052621f03bc8 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -28,6 +28,7 @@ #include <linux/tcp.h> #include <linux/slab.h> #include <linux/cache.h> +#include <linux/percpu.h> #include <net/checksum.h> #include <net/sock.h> #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) @@ -630,10 +631,11 @@ extern __inline int between(__u32 seq1, __u32 seq2, __u32 seq3) extern struct proto tcp_prot; -extern struct tcp_mib tcp_statistics[NR_CPUS*2]; +DECLARE_SNMP_STAT(struct tcp_mib, tcp_statistics); #define TCP_INC_STATS(field) SNMP_INC_STATS(tcp_statistics, field) #define TCP_INC_STATS_BH(field) SNMP_INC_STATS_BH(tcp_statistics, field) #define TCP_INC_STATS_USER(field) SNMP_INC_STATS_USER(tcp_statistics, field) +#define TCP_DEC_STATS(field) SNMP_DEC_STATS(tcp_statistics, field) extern void tcp_put_port(struct sock *sk); extern void __tcp_put_port(struct sock *sk); @@ -1399,7 +1401,7 @@ static __inline__ void tcp_set_state(struct sock *sk, int state) /* fall through */ default: if (oldstate==TCP_ESTABLISHED) - tcp_statistics[smp_processor_id()*2+!in_softirq()].TcpCurrEstab--; + TCP_DEC_STATS(TcpCurrEstab); } /* Change state AFTER socket is unhashed to avoid closed diff --git a/include/net/udp.h b/include/net/udp.h index 63a24bdd3b06..4684cba23be2 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -25,6 +25,7 @@ #include <linux/udp.h> #include <linux/ip.h> #include <net/sock.h> +#include <net/snmp.h> #define UDP_HTABLE_SIZE 128 @@ -71,7 +72,7 @@ extern int udp_rcv(struct sk_buff *skb); extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern int udp_disconnect(struct sock *sk, int flags); -extern struct udp_mib udp_statistics[NR_CPUS*2]; +DECLARE_SNMP_STAT(struct udp_mib, udp_statistics); #define UDP_INC_STATS(field) SNMP_INC_STATS(udp_statistics, field) #define UDP_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_statistics, field) #define UDP_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_statistics, field) diff --git a/net/core/dev.c b/net/core/dev.c index 9b5ee08067eb..227e6d24e0ae 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2133,7 +2133,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) case SIOCGIFHWADDR: memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, - MAX_ADDR_LEN); + min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); ifr->ifr_hwaddr.sa_family = dev->type; return 0; @@ -2154,7 +2154,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) if (ifr->ifr_hwaddr.sa_family != dev->type) return -EINVAL; memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, - MAX_ADDR_LEN); + min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return 0; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1702d8aa0ad0..e324ae6f75f3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -220,6 +220,40 @@ int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +{ + struct ifinfomsg *ifm = NLMSG_DATA(nlh); + struct rtattr **ida = arg; + struct net_device *dev; + int err; + + dev = dev_get_by_index(ifm->ifi_index); + if (!dev) + return -ENODEV; + + err = -EINVAL; + + if (ida[IFLA_ADDRESS - 1]) { + if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len)) + goto out; + memcpy(dev->dev_addr, RTA_DATA(ida[IFLA_ADDRESS - 1]), + dev->addr_len); + } + + if (ida[IFLA_BROADCAST - 1]) { + if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len)) + goto out; + memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]), + dev->addr_len); + } + + err = 0; + +out: + dev_put(dev); + return err; +} + int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb) { int idx; @@ -457,33 +491,15 @@ static void rtnetlink_rcv(struct sock *sk, int len) static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] = { - { NULL, NULL, }, - { NULL, NULL, }, - { NULL, rtnetlink_dump_ifinfo, }, - { NULL, NULL, }, - - { NULL, NULL, }, - { NULL, NULL, }, - { NULL, rtnetlink_dump_all, }, - { NULL, NULL, }, - - { NULL, NULL, }, - { NULL, NULL, }, - { NULL, rtnetlink_dump_all, }, - { NULL, NULL, }, - - { neigh_add, NULL, }, - { neigh_delete, NULL, }, - { NULL, neigh_dump_info, }, - { NULL, NULL, }, - - { NULL, NULL, }, - { NULL, NULL, }, - { NULL, NULL, }, - { NULL, NULL, }, + [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, + [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, + [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, + [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, + [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, + [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete }, + [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info } }; - static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index f4d80a269118..9d2ff54b8ecb 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -324,7 +324,9 @@ void __kfree_skb(struct sk_buff *skb) } dst_release(skb->dst); +#ifdef CONFIG_INET secpath_put(skb->sp); +#endif if(skb->destructor) { if (in_irq()) printk(KERN_WARNING "Warning: kfree_skb on " @@ -378,7 +380,9 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) C(dst); dst_clone(n->dst); C(sp); +#ifdef CONFIG_INET secpath_get(n->sp); +#endif memcpy(n->cb, skb->cb, sizeof(skb->cb)); C(len); C(data_len); @@ -438,7 +442,9 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->priority = old->priority; new->protocol = old->protocol; new->dst = dst_clone(old->dst); +#ifdef CONFIG_INET new->sp = secpath_get(old->sp); +#endif new->h.raw = old->h.raw + offset; new->nh.raw = old->nh.raw + offset; new->mac.raw = old->mac.raw + offset; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 6d5a73065d48..941737af67f0 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -113,7 +113,7 @@ #include <linux/mroute.h> #endif -struct linux_mib net_statistics[NR_CPUS * 2]; +DEFINE_SNMP_STAT(struct linux_mib, net_statistics); #ifdef INET_REFCNT_DEBUG atomic_t inet_sock_nr; @@ -1053,6 +1053,59 @@ static struct inet_protocol icmp_protocol = { .handler = icmp_rcv, }; +static int __init init_ipv4_mibs(void) +{ + int i; + + net_statistics[0] = + kmalloc_percpu(sizeof (struct linux_mib), GFP_KERNEL); + net_statistics[1] = + kmalloc_percpu(sizeof (struct linux_mib), GFP_KERNEL); + ip_statistics[0] = kmalloc_percpu(sizeof (struct ip_mib), GFP_KERNEL); + ip_statistics[1] = kmalloc_percpu(sizeof (struct ip_mib), GFP_KERNEL); + icmp_statistics[0] = + kmalloc_percpu(sizeof (struct icmp_mib), GFP_KERNEL); + icmp_statistics[1] = + kmalloc_percpu(sizeof (struct icmp_mib), GFP_KERNEL); + tcp_statistics[0] = kmalloc_percpu(sizeof (struct tcp_mib), GFP_KERNEL); + tcp_statistics[1] = kmalloc_percpu(sizeof (struct tcp_mib), GFP_KERNEL); + udp_statistics[0] = kmalloc_percpu(sizeof (struct udp_mib), GFP_KERNEL); + udp_statistics[1] = kmalloc_percpu(sizeof (struct udp_mib), GFP_KERNEL); + if (! + (net_statistics[0] && net_statistics[1] && ip_statistics[0] + && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] + && udp_statistics[0] && udp_statistics[1])) + return -ENOMEM; + + /* Set all the per cpu copies of the mibs to zero */ + for (i = 0; i < NR_CPUS; i++) { + if (cpu_possible(i)) { + memset(per_cpu_ptr(net_statistics[0], i), 0, + sizeof (struct linux_mib)); + memset(per_cpu_ptr(net_statistics[1], i), 0, + sizeof (struct linux_mib)); + memset(per_cpu_ptr(ip_statistics[0], i), 0, + sizeof (struct ip_mib)); + memset(per_cpu_ptr(ip_statistics[1], i), 0, + sizeof (struct ip_mib)); + memset(per_cpu_ptr(icmp_statistics[0], i), 0, + sizeof (struct icmp_mib)); + memset(per_cpu_ptr(icmp_statistics[1], i), 0, + sizeof (struct icmp_mib)); + memset(per_cpu_ptr(tcp_statistics[0], i), 0, + sizeof (struct tcp_mib)); + memset(per_cpu_ptr(tcp_statistics[1], i), 0, + sizeof (struct tcp_mib)); + memset(per_cpu_ptr(udp_statistics[0], i), 0, + sizeof (struct udp_mib)); + memset(per_cpu_ptr(udp_statistics[1], i), 0, + sizeof (struct udp_mib)); + } + } + + return 0; +} + int ipv4_proc_init(void); static int __init inet_init(void) @@ -1148,7 +1201,13 @@ static int __init inet_init(void) #if defined(CONFIG_IP_MROUTE) ip_mr_init(); #endif + /* + * Initialise per-cpu ipv4 mibs + */ + if(init_ipv4_mibs()) + printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ; + ipv4_proc_init(); return 0; } diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 6be6e91d01cf..1db9547314c4 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -113,7 +113,7 @@ struct icmp_bxm { /* * Statistics */ -struct icmp_mib icmp_statistics[NR_CPUS * 2]; +DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics); /* An array of errno for error messages from dest unreach. */ /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOS_UNREACH and SR_FAIELD MUST be considered 'transient errs'. */ @@ -213,12 +213,11 @@ int sysctl_icmp_ratemask = 0x1818; * ICMP control array. This specifies what to do with each ICMP. */ -struct icmp_control -{ - unsigned long *output; /* Address to increment on output */ - unsigned long *input; /* Address to increment on input */ +struct icmp_control { + int output_off; /* Field offset for increment on output */ + int input_off; /* Field offset for increment on input */ void (*handler)(struct sk_buff *skb); - short error; /* This ICMP is classed as an error message */ + short error; /* This ICMP is classed as an error message */ }; static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; @@ -343,10 +342,7 @@ out: static void icmp_out_count(int type) { if (type <= NR_ICMP_TYPES) { - (icmp_pointers[type].output)[(smp_processor_id() * 2 + - !in_softirq()) * - sizeof(struct icmp_mib) / - sizeof(unsigned long)]++; + ICMP_INC_STATS_FIELD(icmp_pointers[type].output_off); ICMP_INC_STATS(IcmpOutMsgs); } } @@ -1005,9 +1001,7 @@ int icmp_rcv(struct sk_buff *skb) } } - icmp_pointers[icmph->type].input[smp_processor_id() * 2 * - sizeof(struct icmp_mib) / - sizeof(unsigned long)]++; + ICMP_INC_STATS_BH_FIELD(icmp_pointers[icmph->type].input_off); (icmp_pointers[icmph->type].handler)(skb); drop: @@ -1024,122 +1018,122 @@ error: static struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { /* ECHO REPLY (0) */ [0] = { - .output = &icmp_statistics[0].IcmpOutEchoReps, - .input = &icmp_statistics[0].IcmpInEchoReps, + .output_off = offsetof(struct icmp_mib, IcmpOutEchoReps), + .input_off = offsetof(struct icmp_mib, IcmpInEchoReps), .handler = icmp_discard, }, [1] = { - .output = &icmp_statistics[0].dummy, - .input = &icmp_statistics[0].IcmpInErrors, + .output_off = offsetof(struct icmp_mib, dummy), + .input_off = offsetof(struct icmp_mib,IcmpInErrors), .handler = icmp_discard, .error = 1, }, [2] = { - .output = &icmp_statistics[0].dummy, - .input = &icmp_statistics[0].IcmpInErrors, + .output_off = offsetof(struct icmp_mib, dummy), + .input_off = offsetof(struct icmp_mib,IcmpInErrors), .handler = icmp_discard, .error = 1, }, /* DEST UNREACH (3) */ [3] = { - .output = &icmp_statistics[0].IcmpOutDestUnreachs, - .input = &icmp_statistics[0].IcmpInDestUnreachs, + .output_off = offsetof(struct icmp_mib, IcmpOutDestUnreachs), + .input_off = offsetof(struct icmp_mib, IcmpInDestUnreachs), .handler = icmp_unreach, .error = 1, }, /* SOURCE QUENCH (4) */ [4] = { - .output = &icmp_statistics[0].IcmpOutSrcQuenchs, - .input = &icmp_statistics[0].IcmpInSrcQuenchs, + .output_off = offsetof(struct icmp_mib, IcmpOutSrcQuenchs), + .input_off = offsetof(struct icmp_mib, IcmpInSrcQuenchs), icmp_unreach, .error = 1, }, /* REDIRECT (5) */ [5] = { - .output = &icmp_statistics[0].IcmpOutRedirects, - .input = &icmp_statistics[0].IcmpInRedirects, + .output_off = offsetof(struct icmp_mib, IcmpOutRedirects), + .input_off = offsetof(struct icmp_mib, IcmpInRedirects), .handler = icmp_redirect, .error = 1, }, [6] = { - .output = &icmp_statistics[0].dummy, - .input = &icmp_statistics[0].IcmpInErrors, + .output_off = offsetof(struct icmp_mib, dummy), + .input_off = offsetof(struct icmp_mib, IcmpInErrors), .handler = icmp_discard, .error = 1, }, [7] = { - .output = &icmp_statistics[0].dummy, - .input = &icmp_statistics[0].IcmpInErrors, + .output_off = offsetof(struct icmp_mib, dummy), + .input_off = offsetof(struct icmp_mib, IcmpInErrors), .handler = icmp_discard, .error = 1, }, /* ECHO (8) */ [8] = { - .output = &icmp_statistics[0].IcmpOutEchos, - .input = &icmp_statistics[0].IcmpInEchos, + .output_off = offsetof(struct icmp_mib, IcmpOutEchos), + .input_off = offsetof(struct icmp_mib, IcmpInEchos), .handler = icmp_echo, .error = 0, }, [9] = { - .output = &icmp_statistics[0].dummy, - .input = &icmp_statistics[0].IcmpInErrors, + .output_off = offsetof(struct icmp_mib, dummy), + .input_off = offsetof(struct icmp_mib, IcmpInErrors), .handler = icmp_discard, .error = 1, }, [10] = { - .output = &icmp_statistics[0].dummy, - .input = &icmp_statistics[0].IcmpInErrors, + .output_off = offsetof(struct icmp_mib, dummy), + .input_off = offsetof(struct icmp_mib, IcmpInErrors), .handler = icmp_discard, .error = 1, }, /* TIME EXCEEDED (11) */ [11] = { - .output = &icmp_statistics[0].IcmpOutTimeExcds, - .input = &icmp_statistics[0].IcmpInTimeExcds, + .output_off = offsetof(struct icmp_mib, IcmpOutTimeExcds), + .input_off = offsetof(struct icmp_mib,IcmpInTimeExcds), .handler = icmp_unreach, .error = 1, }, /* PARAMETER PROBLEM (12) */ [12] = { - .output = &icmp_statistics[0].IcmpOutParmProbs, - .input = &icmp_statistics[0].IcmpInParmProbs, + .output_off = offsetof(struct icmp_mib, IcmpOutParmProbs), + .input_off = offsetof(struct icmp_mib, IcmpInParmProbs), .handler = icmp_unreach, .error = 1, }, /* TIMESTAMP (13) */ [13] = { - .output = &icmp_statistics[0].IcmpOutTimestamps, - .input = &icmp_statistics[0].IcmpInTimestamps, + .output_off = offsetof(struct icmp_mib, IcmpOutTimestamps), + .input_off = offsetof(struct icmp_mib, IcmpInTimestamps), .handler = icmp_timestamp, }, /* TIMESTAMP REPLY (14) */ [14] = { - .output = &icmp_statistics[0].IcmpOutTimestampReps, - .input = &icmp_statistics[0].IcmpInTimestampReps, + .output_off = offsetof(struct icmp_mib, IcmpOutTimestampReps), + .input_off = offsetof(struct icmp_mib, IcmpInTimestampReps), .handler = icmp_discard, }, /* INFO (15) */ [15] = { - .output = &icmp_statistics[0].dummy, - .input = &icmp_statistics[0].dummy, + .output_off = offsetof(struct icmp_mib, dummy), + .input_off = offsetof(struct icmp_mib, dummy), .handler = icmp_discard, }, /* INFO REPLY (16) */ [16] = { - .output = &icmp_statistics[0].dummy, - .input = &icmp_statistics[0].dummy, + .output_off = offsetof(struct icmp_mib, dummy), + .input_off = offsetof(struct icmp_mib, dummy), .handler = icmp_discard, }, /* ADDR MASK (17) */ [17] = { - .output = &icmp_statistics[0].IcmpOutAddrMasks, - .input = &icmp_statistics[0].IcmpInAddrMasks, + .output_off = offsetof(struct icmp_mib, IcmpOutAddrMasks), + .input_off = offsetof(struct icmp_mib, IcmpInAddrMasks), .handler = icmp_address, }, /* ADDR MASK REPLY (18) */ [18] = { - .output = &icmp_statistics[0].IcmpOutAddrMaskReps, - .input = &icmp_statistics[0].IcmpInAddrMaskReps, + .output_off = offsetof(struct icmp_mib, IcmpOutAddrMaskReps), + .input_off = offsetof(struct icmp_mib, IcmpInAddrMaskReps), .handler = icmp_address_reply, } }; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 6c67950d4b4b..092f0a2e52fd 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -149,7 +149,7 @@ * SNMP management statistics */ -struct ip_mib ip_statistics[NR_CPUS*2]; +DEFINE_SNMP_STAT(struct ip_mib, ip_statistics); /* * Process Router Attention IP option diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 8869781ad6d6..2971828644e4 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -86,16 +86,21 @@ static struct file_operations sockstat_seq_fops = { .release = single_release, }; -static unsigned long fold_field(unsigned long *begin, int sz, int nr) +static unsigned long +fold_field(void *mib[], int nr) { unsigned long res = 0; int i; - sz /= sizeof(unsigned long); - for (i = 0; i < NR_CPUS; i++) { - res += begin[2 * i * sz + nr]; - res += begin[(2 * i + 1) * sz + nr]; + if (!cpu_possible(i)) + continue; + res += + *((unsigned long *) (((void *) per_cpu_ptr(mib[0], i)) + + sizeof (unsigned long) * nr)); + res += + *((unsigned long *) (((void *) per_cpu_ptr(mib[0], i)) + + sizeof (unsigned long) * nr)); } return res; } @@ -118,8 +123,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) for (i = 0; i < offsetof(struct ip_mib, __pad) / sizeof(unsigned long); i++) seq_printf(seq, " %lu", - fold_field((unsigned long *)ip_statistics, - sizeof(struct ip_mib), i)); + fold_field((void **) ip_statistics, i)); seq_printf(seq, "\nIcmp: InMsgs InErrors InDestUnreachs InTimeExcds " "InParmProbs InSrcQuenchs InRedirects InEchos " @@ -132,8 +136,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) for (i = 0; i < offsetof(struct icmp_mib, dummy) / sizeof(unsigned long); i++) seq_printf(seq, " %lu", - fold_field((unsigned long *)icmp_statistics, - sizeof(struct icmp_mib), i)); + fold_field((void **) icmp_statistics, i)); seq_printf(seq, "\nTcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens " "PassiveOpens AttemptFails EstabResets CurrEstab " @@ -142,17 +145,15 @@ static int snmp_seq_show(struct seq_file *seq, void *v) for (i = 0; i < offsetof(struct tcp_mib, __pad) / sizeof(unsigned long); i++) seq_printf(seq, " %lu", - fold_field((unsigned long *)tcp_statistics, - sizeof(struct tcp_mib), i)); + fold_field((void **) tcp_statistics, i)); seq_printf(seq, "\nUdp: InDatagrams NoPorts InErrors OutDatagrams\n" "Udp:"); for (i = 0; i < offsetof(struct udp_mib, __pad) / sizeof(unsigned long); i++) - seq_printf(seq, " %lu", - fold_field((unsigned long *)udp_statistics, - sizeof(struct udp_mib), i)); + seq_printf(seq, " %lu", + fold_field((void **) udp_statistics, i)); seq_putc(seq, '\n'); return 0; @@ -206,10 +207,10 @@ static int netstat_seq_show(struct seq_file *seq, void *v) " TCPAbortFailed TCPMemoryPressures\n" "TcpExt:"); for (i = 0; - i < offsetof(struct linux_mib, __pad) / sizeof(unsigned long); i++) - seq_printf(seq, " %lu", - fold_field((unsigned long *)net_statistics, - sizeof(struct linux_mib), i)); + i < offsetof(struct linux_mib, __pad) / sizeof(unsigned long); + i++) + seq_printf(seq, " %lu", + fold_field((void **) net_statistics, i)); seq_putc(seq, '\n'); return 0; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 9ca1db5863ad..eefd475dad53 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -196,7 +196,7 @@ static struct rt_hash_bucket *rt_hash_table; static unsigned rt_hash_mask; static int rt_hash_log; -struct rt_cache_stat rt_cache_stat[NR_CPUS]; +struct rt_cache_stat *rt_cache_stat; static int rt_intern_hash(unsigned hash, struct rtable *rth, struct rtable **res); @@ -318,24 +318,26 @@ static int rt_cache_stat_get_info(char *buffer, char **start, off_t offset, int int len = 0; for (i = 0; i < NR_CPUS; i++) { + if (!cpu_possible(i)) + continue; len += sprintf(buffer+len, "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x \n", dst_entries, - rt_cache_stat[i].in_hit, - rt_cache_stat[i].in_slow_tot, - rt_cache_stat[i].in_slow_mc, - rt_cache_stat[i].in_no_route, - rt_cache_stat[i].in_brd, - rt_cache_stat[i].in_martian_dst, - rt_cache_stat[i].in_martian_src, - - rt_cache_stat[i].out_hit, - rt_cache_stat[i].out_slow_tot, - rt_cache_stat[i].out_slow_mc, - - rt_cache_stat[i].gc_total, - rt_cache_stat[i].gc_ignored, - rt_cache_stat[i].gc_goal_miss, - rt_cache_stat[i].gc_dst_overflow + per_cpu_ptr(rt_cache_stat, i)->in_hit, + per_cpu_ptr(rt_cache_stat, i)->in_slow_tot, + per_cpu_ptr(rt_cache_stat, i)->in_slow_mc, + per_cpu_ptr(rt_cache_stat, i)->in_no_route, + per_cpu_ptr(rt_cache_stat, i)->in_brd, + per_cpu_ptr(rt_cache_stat, i)->in_martian_dst, + per_cpu_ptr(rt_cache_stat, i)->in_martian_src, + + per_cpu_ptr(rt_cache_stat, i)->out_hit, + per_cpu_ptr(rt_cache_stat, i)->out_slow_tot, + per_cpu_ptr(rt_cache_stat, i)->out_slow_mc, + + per_cpu_ptr(rt_cache_stat, i)->gc_total, + per_cpu_ptr(rt_cache_stat, i)->gc_ignored, + per_cpu_ptr(rt_cache_stat, i)->gc_goal_miss, + per_cpu_ptr(rt_cache_stat, i)->gc_dst_overflow ); } @@ -591,11 +593,11 @@ static int rt_garbage_collect(void) * do not make it too frequently. */ - rt_cache_stat[smp_processor_id()].gc_total++; + RT_CACHE_STAT_INC(gc_total); if (now - last_gc < ip_rt_gc_min_interval && atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size) { - rt_cache_stat[smp_processor_id()].gc_ignored++; + RT_CACHE_STAT_INC(gc_ignored); goto out; } @@ -663,7 +665,7 @@ static int rt_garbage_collect(void) We will not spin here for long time in any case. */ - rt_cache_stat[smp_processor_id()].gc_goal_miss++; + RT_CACHE_STAT_INC(gc_goal_miss); if (expire == 0) break; @@ -682,7 +684,7 @@ static int rt_garbage_collect(void) goto out; if (net_ratelimit()) printk(KERN_WARNING "dst cache overflow\n"); - rt_cache_stat[smp_processor_id()].gc_dst_overflow++; + RT_CACHE_STAT_INC(gc_dst_overflow); return 1; work_done: @@ -1400,7 +1402,7 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr, if (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev)) rth->u.dst.input = ip_mr_input; #endif - rt_cache_stat[smp_processor_id()].in_slow_mc++; + RT_CACHE_STAT_INC(in_slow_mc); in_dev_put(in_dev); hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos); @@ -1485,7 +1487,7 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, } free_res = 1; - rt_cache_stat[smp_processor_id()].in_slow_tot++; + RT_CACHE_STAT_INC(in_slow_tot); #ifdef CONFIG_IP_ROUTE_NAT /* Policy is applied before mapping destination, @@ -1642,7 +1644,7 @@ brd_input: } flags |= RTCF_BROADCAST; res.type = RTN_BROADCAST; - rt_cache_stat[smp_processor_id()].in_brd++; + RT_CACHE_STAT_INC(in_brd); local_input: rth = dst_alloc(&ipv4_dst_ops); @@ -1687,7 +1689,7 @@ local_input: goto intern; no_route: - rt_cache_stat[smp_processor_id()].in_no_route++; + RT_CACHE_STAT_INC(in_no_route); spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); res.type = RTN_UNREACHABLE; goto local_input; @@ -1696,7 +1698,7 @@ no_route: * Do not cache martian addresses: they should be logged (RFC1812) */ martian_destination: - rt_cache_stat[smp_processor_id()].in_martian_dst++; + RT_CACHE_STAT_INC(in_martian_dst); #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) printk(KERN_WARNING "martian destination %u.%u.%u.%u from " @@ -1713,7 +1715,7 @@ e_nobufs: martian_source: - rt_cache_stat[smp_processor_id()].in_martian_src++; + RT_CACHE_STAT_INC(in_martian_src); #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) { /* @@ -1763,7 +1765,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, rth->u.dst.lastuse = jiffies; dst_hold(&rth->u.dst); rth->u.dst.__use++; - rt_cache_stat[smp_processor_id()].in_hit++; + RT_CACHE_STAT_INC(in_hit); rcu_read_unlock(); skb->dst = (struct dst_entry*)rth; return 0; @@ -2060,7 +2062,7 @@ make_route: rth->u.dst.output=ip_output; - rt_cache_stat[smp_processor_id()].out_slow_tot++; + RT_CACHE_STAT_INC(out_slow_tot); if (flags & RTCF_LOCAL) { rth->u.dst.input = ip_local_deliver; @@ -2070,7 +2072,7 @@ make_route: rth->rt_spec_dst = fl.fl4_src; if (flags & RTCF_LOCAL && !(dev_out->flags & IFF_LOOPBACK)) { rth->u.dst.output = ip_mc_output; - rt_cache_stat[smp_processor_id()].out_slow_mc++; + RT_CACHE_STAT_INC(out_slow_mc); } #ifdef CONFIG_IP_MROUTE if (res.type == RTN_MULTICAST) { @@ -2129,7 +2131,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp) rth->u.dst.lastuse = jiffies; dst_hold(&rth->u.dst); rth->u.dst.__use++; - rt_cache_stat[smp_processor_id()].out_hit++; + RT_CACHE_STAT_INC(out_hit); rcu_read_unlock(); *rp = rth; return 0; @@ -2650,6 +2652,11 @@ int __init ip_rt_init(void) ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1); ip_rt_max_size = (rt_hash_mask + 1) * 16; + rt_cache_stat = kmalloc_percpu(sizeof (struct rt_cache_stat), + GFP_KERNEL); + if (!rt_cache_stat) + goto out_enomem1; + devinet_init(); ip_fib_init(); @@ -2675,6 +2682,8 @@ int __init ip_rt_init(void) out: return rc; out_enomem: + kfree_percpu(rt_cache_stat); +out_enomem1: rc = -ENOMEM; goto out; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 82e9529c1a57..2351b2faf180 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -258,13 +258,15 @@ #include <net/icmp.h> #include <net/tcp.h> #include <net/xfrm.h> +#include <net/ip.h> + #include <asm/uaccess.h> #include <asm/ioctls.h> int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT; -struct tcp_mib tcp_statistics[NR_CPUS * 2]; +DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics); kmem_cache_t *tcp_openreq_cachep; kmem_cache_t *tcp_bucket_cachep; @@ -1395,8 +1397,7 @@ static void tcp_prequeue_process(struct sock *sk) struct sk_buff *skb; struct tcp_opt *tp = tcp_sk(sk); - net_statistics[smp_processor_id() * 2 + 1].TCPPrequeued += - skb_queue_len(&tp->ucopy.prequeue); + NET_ADD_STATS_USER(TCPPrequeued, skb_queue_len(&tp->ucopy.prequeue)); /* RX process wants to run with disabled BHs, though it is not * necessary */ @@ -1676,7 +1677,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* __ Restore normal policy in scheduler __ */ if ((chunk = len - tp->ucopy.len) != 0) { - net_statistics[smp_processor_id() * 2 + 1].TCPDirectCopyFromBacklog += chunk; + NET_ADD_STATS_USER(TCPDirectCopyFromBacklog, chunk); len -= chunk; copied += chunk; } @@ -1687,7 +1688,7 @@ do_prequeue: tcp_prequeue_process(sk); if ((chunk = len - tp->ucopy.len) != 0) { - net_statistics[smp_processor_id() * 2 + 1].TCPDirectCopyFromPrequeue += chunk; + NET_ADD_STATS_USER(TCPDirectCopyFromPrequeue, chunk); len -= chunk; copied += chunk; } @@ -1770,7 +1771,7 @@ skip_copy: tcp_prequeue_process(sk); if (copied > 0 && (chunk = len - tp->ucopy.len) != 0) { - net_statistics[smp_processor_id() * 2 + 1].TCPDirectCopyFromPrequeue += chunk; + NET_ADD_STATS_USER(TCPDirectCopyFromPrequeue, chunk); len -= chunk; copied += chunk; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3d3b0f518995..fad2dc973a6b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3043,8 +3043,8 @@ static int tcp_prune_queue(struct sock *sk) /* First, purge the out_of_order queue. */ if (skb_queue_len(&tp->out_of_order_queue)) { - net_statistics[smp_processor_id() * 2].OfoPruned += - skb_queue_len(&tp->out_of_order_queue); + NET_ADD_STATS_BH(OfoPruned, + skb_queue_len(&tp->out_of_order_queue)); __skb_queue_purge(&tp->out_of_order_queue); /* Reset SACK state. A conforming SACK implementation will diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index b660f78ab2fa..aaa16eb403dc 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -464,7 +464,7 @@ static void SMP_TIMER_NAME(tcp_twkill)(unsigned long dummy) if ((tcp_tw_count -= killed) != 0) mod_timer(&tcp_tw_timer, jiffies+TCP_TWKILL_PERIOD); - net_statistics[smp_processor_id()*2].TimeWaited += killed; + NET_ADD_STATS_BH(TimeWaited, killed); out: spin_unlock(&tw_death_lock); } @@ -628,7 +628,7 @@ void SMP_TIMER_NAME(tcp_twcal_tick)(unsigned long dummy) out: if ((tcp_tw_count -= killed) == 0) del_timer(&tcp_tw_timer); - net_statistics[smp_processor_id()*2].TimeWaitKilled += killed; + NET_ADD_STATS_BH(TimeWaitKilled, killed); spin_unlock(&tw_death_lock); } diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 619e89ea2c49..fc2102496536 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -237,7 +237,8 @@ static void tcp_delack_timer(unsigned long data) if (skb_queue_len(&tp->ucopy.prequeue)) { struct sk_buff *skb; - net_statistics[smp_processor_id()*2].TCPSchedulerFailed += skb_queue_len(&tp->ucopy.prequeue); + NET_ADD_STATS_BH(TCPSchedulerFailed, + skb_queue_len(&tp->ucopy.prequeue)); while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) sk->backlog_rcv(sk, skb); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ca07a67c2bc0..02d04030d901 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -110,7 +110,7 @@ * Snmp MIB for the UDP layer */ -struct udp_mib udp_statistics[NR_CPUS*2]; +DEFINE_SNMP_STAT(struct udp_mib, udp_statistics); struct sock *udp_hash[UDP_HTABLE_SIZE]; rwlock_t udp_hash_lock = RW_LOCK_UNLOCKED; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 86cbad545ca8..309be737569f 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -619,6 +619,81 @@ inet6_unregister_protosw(struct inet_protosw *p) inet_unregister_protosw(p); } +static int __init init_ipv6_mibs(void) +{ + int i; + + ipv6_statistics[0] = kmalloc_percpu(sizeof (struct ipv6_mib), + GFP_KERNEL); + if (!ipv6_statistics[0]) + goto err_ip_mib0; + ipv6_statistics[1] = kmalloc_percpu(sizeof (struct ipv6_mib), + GFP_KERNEL); + if (!ipv6_statistics[1]) + goto err_ip_mib1; + + icmpv6_statistics[0] = kmalloc_percpu(sizeof (struct icmpv6_mib), + GFP_KERNEL); + if (!icmpv6_statistics[0]) + goto err_icmp_mib0; + icmpv6_statistics[1] = kmalloc_percpu(sizeof (struct icmpv6_mib), + GFP_KERNEL); + if (!icmpv6_statistics[1]) + goto err_icmp_mib1; + + udp_stats_in6[0] = kmalloc_percpu(sizeof (struct udp_mib), + GFP_KERNEL); + if (!udp_stats_in6[0]) + goto err_udp_mib0; + udp_stats_in6[1] = kmalloc_percpu(sizeof (struct udp_mib), + GFP_KERNEL); + if (!udp_stats_in6[1]) + goto err_udp_mib1; + + /* Zero all percpu versions of the mibs */ + for (i = 0; i < NR_CPUS; i++) { + if (cpu_possible(i)) { + memset(per_cpu_ptr(ipv6_statistics[0], i), 0, + sizeof (struct ipv6_mib)); + memset(per_cpu_ptr(ipv6_statistics[1], i), 0, + sizeof (struct ipv6_mib)); + memset(per_cpu_ptr(icmpv6_statistics[0], i), 0, + sizeof (struct icmpv6_mib)); + memset(per_cpu_ptr(icmpv6_statistics[1], i), 0, + sizeof (struct icmpv6_mib)); + memset(per_cpu_ptr(udp_stats_in6[0], i), 0, + sizeof (struct udp_mib)); + memset(per_cpu_ptr(udp_stats_in6[1], i), 0, + sizeof (struct udp_mib)); + } + } + return 0; + +err_udp_mib1: + kfree_percpu(udp_stats_in6[0]); +err_udp_mib0: + kfree_percpu(icmpv6_statistics[1]); +err_icmp_mib1: + kfree_percpu(icmpv6_statistics[0]); +err_icmp_mib0: + kfree_percpu(ipv6_statistics[1]); +err_ip_mib1: + kfree_percpu(ipv6_statistics[0]); +err_ip_mib0: + return -ENOMEM; + +} + +static void __exit cleanup_ipv6_mibs(void) +{ + kfree_percpu(ipv6_statistics[0]); + kfree_percpu(ipv6_statistics[1]); + kfree_percpu(icmpv6_statistics[0]); + kfree_percpu(icmpv6_statistics[1]); + kfree_percpu(udp_stats_in6[0]); + kfree_percpu(udp_stats_in6[1]); +} + static int __init inet6_init(void) { struct sk_buff *dummy_skb; @@ -668,6 +743,11 @@ static int __init inet6_init(void) * be able to create sockets. (?? is this dangerous ??) */ (void) sock_register(&inet6_family_ops); + + /* Initialise ipv6 mibs */ + err = init_ipv6_mibs(); + if (err) + goto init_mib_fail; /* * ipngwg API draft makes clear that the correct semantics @@ -735,6 +815,8 @@ icmp_fail: #if defined(MODULE) && defined(CONFIG_SYSCTL) ipv6_sysctl_unregister(); #endif + cleanup_ipv6_mibs(); +init_mib_fail: return err; } module_init(inet6_init); @@ -765,6 +847,7 @@ static void inet6_exit(void) #ifdef CONFIG_SYSCTL ipv6_sysctl_unregister(); #endif + cleanup_ipv6_mibs(); } module_exit(inet6_exit); #endif /* MODULE */ diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index db535ea0801f..b5f53a7ce839 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -65,7 +65,7 @@ #include <asm/uaccess.h> #include <asm/system.h> -struct icmpv6_mib icmpv6_statistics[NR_CPUS*2]; +DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); /* * ICMP socket for flow control. @@ -377,7 +377,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, MSG_DONTWAIT); if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) - (&(icmpv6_statistics[smp_processor_id()*2].Icmp6OutDestUnreachs))[type-1]++; + ICMP6_STATS_PTR_BH(Icmp6OutDestUnreachs) [type-1]++; ICMP6_INC_STATS_BH(Icmp6OutMsgs); out: icmpv6_xmit_unlock(); @@ -539,9 +539,9 @@ static int icmpv6_rcv(struct sk_buff *skb) type = hdr->icmp6_type; if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) - (&icmpv6_statistics[smp_processor_id()*2].Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++; + ICMP6_STATS_PTR_BH(Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++; else if (type >= ICMPV6_ECHO_REQUEST && type <= NDISC_REDIRECT) - (&icmpv6_statistics[smp_processor_id()*2].Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++; + ICMP6_STATS_PTR_BH(Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++; switch (type) { case ICMPV6_ECHO_REQUEST: diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 0587ca8f80fd..a62a73c9fa14 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -51,7 +51,7 @@ #include <asm/uaccess.h> -struct ipv6_mib ipv6_statistics[NR_CPUS*2]; +DEFINE_SNMP_STAT(struct ipv6_mib, ipv6_statistics); static struct packet_type ipv6_packet_type = { diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index ae5f80dd9aa7..9ce2c1d8857b 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -59,11 +59,11 @@ int afinet6_get_info(char *buffer, char **start, off_t offset, int length) static struct snmp6_item { char *name; - unsigned long *ptr; - int mibsize; + void **mib; + int offset; } snmp6_list[] = { /* ipv6 mib according to draft-ietf-ipngwg-ipv6-mib-04 */ -#define SNMP6_GEN(x) { #x , &ipv6_statistics[0].x, sizeof(struct ipv6_mib)/sizeof(unsigned long) } +#define SNMP6_GEN(x) { #x , (void **)ipv6_statistics, offsetof(struct ipv6_mib, x) } SNMP6_GEN(Ip6InReceives), SNMP6_GEN(Ip6InHdrErrors), SNMP6_GEN(Ip6InTooBigErrors), @@ -97,7 +97,7 @@ static struct snmp6_item OutRouterAdvertisements too. OutGroupMembQueries too. */ -#define SNMP6_GEN(x) { #x , &icmpv6_statistics[0].x, sizeof(struct icmpv6_mib)/sizeof(unsigned long) } +#define SNMP6_GEN(x) { #x , (void **)icmpv6_statistics, offsetof(struct icmpv6_mib, x) } SNMP6_GEN(Icmp6InMsgs), SNMP6_GEN(Icmp6InErrors), SNMP6_GEN(Icmp6InDestUnreachs), @@ -127,7 +127,7 @@ static struct snmp6_item SNMP6_GEN(Icmp6OutGroupMembResponses), SNMP6_GEN(Icmp6OutGroupMembReductions), #undef SNMP6_GEN -#define SNMP6_GEN(x) { "Udp6" #x , &udp_stats_in6[0].Udp##x, sizeof(struct udp_mib)/sizeof(unsigned long) } +#define SNMP6_GEN(x) { "Udp6" #x , (void **)udp_stats_in6, offsetof(struct udp_mib, Udp##x) } SNMP6_GEN(InDatagrams), SNMP6_GEN(NoPorts), SNMP6_GEN(InErrors), @@ -135,17 +135,23 @@ static struct snmp6_item #undef SNMP6_GEN }; -static unsigned long fold_field(unsigned long *ptr, int size) +static unsigned long +fold_field(void *mib[], int offt) { - unsigned long res = 0; - int i; - - for (i=0; i<NR_CPUS; i++) { - res += ptr[2*i*size]; - res += ptr[(2*i+1)*size]; - } - - return res; + unsigned long res = 0; + int i; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_possible(i)) + continue; + res += + *((unsigned long *) (((void *)per_cpu_ptr(mib[0], i)) + + offt)); + res += + *((unsigned long *) (((void *)per_cpu_ptr(mib[1], i)) + + offt)); + } + return res; } int afinet6_get_snmp(char *buffer, char **start, off_t offset, int length) @@ -155,7 +161,7 @@ int afinet6_get_snmp(char *buffer, char **start, off_t offset, int length) for (i=0; i<sizeof(snmp6_list)/sizeof(snmp6_list[0]); i++) len += sprintf(buffer+len, "%-32s\t%ld\n", snmp6_list[i].name, - fold_field(snmp6_list[i].ptr, snmp6_list[i].mibsize)); + fold_field(snmp6_list[i].mib, snmp6_list[i].offset)); len -= offset; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index df8e90da19c4..bfb16cd89a0b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -51,7 +51,7 @@ #include <net/checksum.h> -struct udp_mib udp_stats_in6[NR_CPUS*2]; +DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6); /* XXX This is identical to tcp_ipv6.c:ipv6_rcv_saddr_equal, put * XXX it somewhere common. -DaveM diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index fde475e70359..2a733bae42a3 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -60,7 +60,7 @@ /* Global data structures. */ sctp_protocol_t sctp_proto; struct proc_dir_entry *proc_net_sctp; -struct sctp_mib sctp_statistics[NR_CPUS * 2]; +DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics); /* This is the global socket data structure used for responding to * the Out-of-the-blue (OOTB) packets. A control sock will be created @@ -653,6 +653,40 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family) return 1; } +static int __init init_sctp_mibs(void) +{ + int i; + + sctp_statistics[0] = kmalloc_percpu(sizeof (struct sctp_mib), + GFP_KERNEL); + if (!sctp_statistics[0]) + return -ENOMEM; + sctp_statistics[1] = kmalloc_percpu(sizeof (struct sctp_mib), + GFP_KERNEL); + if (!sctp_statistics[1]) { + kfree_percpu(sctp_statistics[0]); + return -ENOMEM; + } + + /* Zero all percpu versions of the mibs */ + for (i = 0; i < NR_CPUS; i++) { + if (cpu_possible(i)) { + memset(per_cpu_ptr(sctp_statistics[0], i), 0, + sizeof (struct sctp_mib)); + memset(per_cpu_ptr(sctp_statistics[1], i), 0, + sizeof (struct sctp_mib)); + } + } + return 0; + +} + +static void cleanup_sctp_mibs(void) +{ + kfree_percpu(sctp_statistics[0]); + kfree_percpu(sctp_statistics[1]); +} + /* Initialize the universe into something sensible. */ int sctp_init(void) { @@ -666,6 +700,11 @@ int sctp_init(void) /* Add SCTP to inetsw linked list. */ inet_register_protosw(&sctp_protosw); + /* Allocate and initialise sctp mibs. */ + status = init_sctp_mibs(); + if (status) + goto err_init_mibs; + /* Initialize proc fs directory. */ sctp_proc_init(); @@ -805,6 +844,8 @@ err_ehash_alloc: err_ahash_alloc: sctp_dbg_objcnt_exit(); sctp_proc_exit(); + cleanup_sctp_mibs(); +err_init_mibs: inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); inet_unregister_protosw(&sctp_protosw); return status; @@ -836,6 +877,7 @@ void sctp_exit(void) sctp_dbg_objcnt_exit(); sctp_proc_exit(); + cleanup_sctp_mibs(); inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); inet_unregister_protosw(&sctp_protosw); diff --git a/net/socket.c b/net/socket.c index e8b80586132a..b17a1944444a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -75,7 +75,6 @@ #include <linux/cache.h> #include <linux/module.h> #include <linux/highmem.h> -#include <linux/wireless.h> #include <linux/divert.h> #include <linux/mount.h> @@ -189,10 +188,7 @@ static __inline__ void net_family_read_unlock(void) * Statistics counters of the socket lists */ -static union { - int counter; - char __pad[SMP_CACHE_BYTES]; -} sockets_in_use[NR_CPUS] __cacheline_aligned = {{0}}; +static DEFINE_PER_CPU(int, sockets_in_use) = 0; /* * Support routines. Move socket addresses back and forth across the kernel/user @@ -475,7 +471,8 @@ struct socket *sock_alloc(void) inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; - sockets_in_use[smp_processor_id()].counter++; + get_cpu_var(sockets_in_use)++; + put_cpu_var(sockets_in_use); return sock; } @@ -511,7 +508,8 @@ void sock_release(struct socket *sock) if (sock->fasync_list) printk(KERN_ERR "sock_release: fasync list not empty!\n"); - sockets_in_use[smp_processor_id()].counter--; + get_cpu_var(sockets_in_use)--; + put_cpu_var(sockets_in_use); if (!sock->file) { iput(SOCK_INODE(sock)); return; @@ -1851,7 +1849,7 @@ void socket_seq_show(struct seq_file *seq) int counter = 0; for (cpu = 0; cpu < NR_CPUS; cpu++) - counter += sockets_in_use[cpu].counter; + counter += per_cpu(sockets_in_use, cpu); /* It can be negative, by the way. 8) */ if (counter < 0) |
