diff options
735 files changed, 15337 insertions, 8383 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index db9499adbed..36526a1e76d 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -190,9 +190,13 @@ quiet_cmd_fig2png = FIG2PNG $@ ### # Help targets as used by the top-level makefile dochelp: - @echo ' Linux kernel internal documentation in different formats:' - @echo ' xmldocs (XML DocBook), psdocs (Postscript), pdfdocs (PDF)' - @echo ' htmldocs (HTML), mandocs (man pages, use installmandocs to install)' + @echo ' Linux kernel internal documentation in different formats:' + @echo ' htmldocs - HTML' + @echo ' installmandocs - install man pages generated by mandocs' + @echo ' mandocs - man pages' + @echo ' pdfdocs - PDF' + @echo ' psdocs - Postscript' + @echo ' xmldocs - XML DocBook' ### # Temporary files left by various tools diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 15e4fed127f..2e1898e4e8f 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1416,6 +1416,11 @@ and is between 256 and 4096 characters. It is defined in the file scsi_logging= [SCSI] + scsi_mod.scan= [SCSI] sync (default) scans SCSI busses as they are + discovered. async scans them in kernel threads, + allowing boot to proceed. none ignores them, expecting + user space to do the scan. + selinux [SELINUX] Disable or enable SELinux at boot time. Format: { "0" | "1" } See security/selinux/Kconfig help text. diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index 75a535a975c..6f70f2b9327 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -375,7 +375,6 @@ Summary: scsi_add_device - creates new scsi device (lu) instance scsi_add_host - perform sysfs registration and set up transport class scsi_adjust_queue_depth - change the queue depth on a SCSI device - scsi_assign_lock - replace default host_lock with given lock scsi_bios_ptable - return copy of block device's partition table scsi_block_requests - prevent further commands being queued to given host scsi_deactivate_tcq - turn off tag command queueing @@ -489,20 +488,6 @@ void scsi_adjust_queue_depth(struct scsi_device * sdev, int tagged, /** - * scsi_assign_lock - replace default host_lock with given lock - * @shost: a pointer to a scsi host instance - * @lock: pointer to lock to replace host_lock for this host - * - * Returns nothing - * - * Might block: no - * - * Defined in: include/scsi/scsi_host.h . - **/ -void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) - - -/** * scsi_bios_ptable - return copy of block device's partition table * @dev: pointer to block device * @@ -1366,17 +1351,11 @@ Locks Each struct Scsi_Host instance has a spin_lock called struct Scsi_Host::default_lock which is initialized in scsi_host_alloc() [found in hosts.c]. Within the same function the struct Scsi_Host::host_lock pointer -is initialized to point at default_lock with the scsi_assign_lock() function. -Thereafter lock and unlock operations performed by the mid level use the -struct Scsi_Host::host_lock pointer. - -LLDs can override the use of struct Scsi_Host::default_lock by -using scsi_assign_lock(). The earliest opportunity to do this would -be in the detect() function after it has invoked scsi_register(). It -could be replaced by a coarser grain lock (e.g. per driver) or a -lock of equal granularity (i.e. per host). Using finer grain locks -(e.g. per SCSI device) may be possible by juggling locks in -queuecommand(). +is initialized to point at default_lock. Thereafter lock and unlock +operations performed by the mid level use the struct Scsi_Host::host_lock +pointer. Previously drivers could override the host_lock pointer but +this is not allowed anymore. + Autosense ========= @@ -1,4 +1,4 @@ - Linux kernel release 2.6.xx <http://kernel.org> + Linux kernel release 2.6.xx <http://kernel.org/> These are the release notes for Linux version 2.6. Read them carefully, as they tell you what this is all about, explain how to install the @@ -22,15 +22,17 @@ ON WHAT HARDWARE DOES IT RUN? Although originally developed first for 32-bit x86-based PCs (386 or higher), today Linux also runs on (at least) the Compaq Alpha AXP, Sun SPARC and - UltraSPARC, Motorola 68000, PowerPC, PowerPC64, ARM, Hitachi SuperH, + UltraSPARC, Motorola 68000, PowerPC, PowerPC64, ARM, Hitachi SuperH, Cell, IBM S/390, MIPS, HP PA-RISC, Intel IA-64, DEC VAX, AMD x86-64, AXIS CRIS, - and Renesas M32R architectures. + Cris, Xtensa, AVR32 and Renesas M32R architectures. Linux is easily portable to most general-purpose 32- or 64-bit architectures as long as they have a paged memory management unit (PMMU) and a port of the GNU C compiler (gcc) (part of The GNU Compiler Collection, GCC). Linux has also been ported to a number of architectures without a PMMU, although functionality is then obviously somewhat limited. + Linux has also been ported to itself. You can now run the kernel as a + userspace application - this is called UserMode Linux (UML). DOCUMENTATION: @@ -113,6 +115,7 @@ INSTALLING the kernel: version 2.6.12.2 and want to jump to 2.6.12.3, you must first reverse the 2.6.12.2 patch (that is, patch -R) _before_ applying the 2.6.12.3 patch. + You can read more on this in Documentation/applying-patches.txt - Make sure you have no stale .o files and dependencies lying around: @@ -161,6 +164,7 @@ CONFIGURING the kernel: only ask you for the answers to new questions. - Alternate configuration commands are: + "make config" Plain text interface. "make menuconfig" Text based color menus, radiolists & dialogs. "make xconfig" X windows (Qt) based configuration tool. "make gconfig" X windows (Gtk) based configuration tool. @@ -303,8 +307,9 @@ IF SOMETHING GOES WRONG: - If you compiled the kernel with CONFIG_KALLSYMS you can send the dump as is, otherwise you will have to use the "ksymoops" program to make - sense of the dump. This utility can be downloaded from - ftp://ftp.<country>.kernel.org/pub/linux/utils/kernel/ksymoops. + sense of the dump (but compiling with CONFIG_KALLSYMS is usually preferred). + This utility can be downloaded from + ftp://ftp.<country>.kernel.org/pub/linux/utils/kernel/ksymoops/ . Alternately you can do the dump lookup by hand: - In debugging dumps like the above, it helps enormously if you can @@ -336,7 +341,7 @@ IF SOMETHING GOES WRONG: If you for some reason cannot do the above (you have a pre-compiled kernel image or similar), telling me as much about your setup as - possible will help. + possible will help. Please read the REPORTING-BUGS document for details. - Alternately, you can use gdb on a running kernel. (read-only; i.e. you cannot change values or set break points.) To do this, first compile the diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c index 605dedf9679..b3599743093 100644 --- a/arch/arm/common/sharpsl_pm.c +++ b/arch/arm/common/sharpsl_pm.c @@ -60,16 +60,16 @@ static int sharpsl_ac_check(void); static int sharpsl_fatal_check(void); static int sharpsl_average_value(int ad); static void sharpsl_average_clear(void); -static void sharpsl_charge_toggle(void *private_); -static void sharpsl_battery_thread(void *private_); +static void sharpsl_charge_toggle(struct work_struct *private_); +static void sharpsl_battery_thread(struct work_struct *private_); /* * Variables */ struct sharpsl_pm_status sharpsl_pm; -DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL); -DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL); +DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle); +DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread); DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger); @@ -116,7 +116,7 @@ void sharpsl_battery_kick(void) EXPORT_SYMBOL(sharpsl_battery_kick); -static void sharpsl_battery_thread(void *private_) +static void sharpsl_battery_thread(struct work_struct *private_) { int voltage, percent, apm_status, i = 0; @@ -128,7 +128,7 @@ static void sharpsl_battery_thread(void *private_) /* Corgi cannot confirm when battery fully charged so periodically kick! */ if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON) && time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_ON_TIME_INTERVAL)) - schedule_work(&toggle_charger); + schedule_delayed_work(&toggle_charger, 0); while(1) { voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); @@ -212,7 +212,7 @@ static void sharpsl_charge_off(void) sharpsl_pm_led(SHARPSL_LED_OFF); sharpsl_pm.charge_mode = CHRG_OFF; - schedule_work(&sharpsl_bat); + schedule_delayed_work(&sharpsl_bat, 0); } static void sharpsl_charge_error(void) @@ -222,7 +222,7 @@ static void sharpsl_charge_error(void) sharpsl_pm.charge_mode = CHRG_ERROR; } -static void sharpsl_charge_toggle(void *private_) +static void sharpsl_charge_toggle(struct work_struct *private_) { dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies); @@ -254,7 +254,7 @@ static void sharpsl_ac_timer(unsigned long data) else if (sharpsl_pm.charge_mode == CHRG_ON) sharpsl_charge_off(); - schedule_work(&sharpsl_bat); + schedule_delayed_work(&sharpsl_bat, 0); } @@ -279,10 +279,10 @@ static void sharpsl_chrg_full_timer(unsigned long data) sharpsl_charge_off(); } else if (sharpsl_pm.full_count < 2) { dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n"); - schedule_work(&toggle_charger); + schedule_delayed_work(&toggle_charger, 0); } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) { dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n"); - schedule_work(&toggle_charger); + schedule_delayed_work(&toggle_charger, 0); } else { sharpsl_charge_off(); sharpsl_pm.charge_mode = CHRG_DONE; diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index f225a083dee..9d2346fb68f 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -323,7 +323,8 @@ static int h3_transceiver_mode(struct device *dev, int mode) cancel_delayed_work(&irda_config->gpio_expa); PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode); - schedule_work(&irda_config->gpio_expa); +#error this is not permitted - mode is an argument variable + schedule_delayed_work(&irda_config->gpio_expa, 0); return 0; } diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index dbc555d209f..cbe909bad79 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -74,7 +74,7 @@ static struct omap_kp_platform_data nokia770_kp_data = { .rows = 8, .cols = 8, .keymap = nokia770_keymap, - .keymapsize = ARRAY_SIZE(nokia770_keymap) + .keymapsize = ARRAY_SIZE(nokia770_keymap), .delay = 4, }; @@ -191,7 +191,7 @@ static void nokia770_audio_pwr_up(void) printk("HP connected\n"); } -static void codec_delayed_power_down(void *arg) +static void codec_delayed_power_down(struct work_struct *work) { down(&audio_pwr_sem); if (audio_pwr_state == -1) @@ -200,7 +200,7 @@ static void codec_delayed_power_down(void *arg) up(&audio_pwr_sem); } -static DECLARE_WORK(codec_power_down_work, codec_delayed_power_down, NULL); +static DECLARE_DELAYED_WORK(codec_power_down_work, codec_delayed_power_down); static void nokia770_audio_pwr_down(void) { diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c index 3b29e59b0e6..0cbf1b0071f 100644 --- a/arch/arm/mach-omap1/leds-osk.c +++ b/arch/arm/mach-omap1/leds-osk.c @@ -35,7 +35,7 @@ static u8 hw_led_state; static u8 tps_leds_change; -static void tps_work(void *unused) +static void tps_work(struct work_struct *unused) { for (;;) { u8 leds; @@ -61,7 +61,7 @@ static void tps_work(void *unused) } } -static DECLARE_WORK(work, tps_work, NULL); +static DECLARE_WORK(work, tps_work); #ifdef CONFIG_OMAP_OSK_MISTRAL diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index 26a95a642ad..3b1ad1d981a 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -206,7 +206,8 @@ static int h4_transceiver_mode(struct device *dev, int mode) cancel_delayed_work(&irda_config->gpio_expa); PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode); - schedule_work(&irda_config->gpio_expa); +#error this is not permitted - mode is an argument variable + schedule_delayed_work(&irda_config->gpio_expa, 0); return 0; } diff --git a/arch/arm/mach-pxa/akita-ioexp.c b/arch/arm/mach-pxa/akita-ioexp.c index 1b398742ab5..12d2fe0ceff 100644 --- a/arch/arm/mach-pxa/akita-ioexp.c +++ b/arch/arm/mach-pxa/akita-ioexp.c @@ -36,11 +36,11 @@ I2C_CLIENT_INSMOD; static int max7310_write(struct i2c_client *client, int address, int data); static struct i2c_client max7310_template; -static void akita_ioexp_work(void *private_); +static void akita_ioexp_work(struct work_struct *private_); static struct device *akita_ioexp_device; static unsigned char ioexp_output_value = AKITA_IOEXP_IO_OUT; -DECLARE_WORK(akita_ioexp, akita_ioexp_work, NULL); +DECLARE_WORK(akita_ioexp, akita_ioexp_work); /* @@ -158,7 +158,7 @@ void akita_reset_ioexp(struct device *dev, unsigned char bit) EXPORT_SYMBOL(akita_set_ioexp); EXPORT_SYMBOL(akita_reset_ioexp); -static void akita_ioexp_work(void *private_) +static void akita_ioexp_work(struct work_struct *private_) { if (akita_ioexp_device) max7310_set_ouputs(akita_ioexp_device, ioexp_output_value); diff --git a/arch/i386/kernel/cpu/mcheck/non-fatal.c b/arch/i386/kernel/cpu/mcheck/non-fatal.c index 1f9153ae5b0..6b5d3518a1c 100644 --- a/arch/i386/kernel/cpu/mcheck/non-fatal.c +++ b/arch/i386/kernel/cpu/mcheck/non-fatal.c @@ -51,10 +51,10 @@ static void mce_checkregs (void *info) } } -static void mce_work_fn(void *data); -static DECLARE_WORK(mce_work, mce_work_fn, NULL); +static void mce_work_fn(struct work_struct *work); +static DECLARE_DELAYED_WORK(mce_work, mce_work_fn); -static void mce_work_fn(void *data) +static void mce_work_fn(struct work_struct *work) { on_each_cpu(mce_checkregs, NULL, 1, 1); schedule_delayed_work(&mce_work, MCE_RATE); diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 4bb8b77cd65..02a9b66b6ac 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -1049,13 +1049,15 @@ void cpu_exit_clear(void) struct warm_boot_cpu_info { struct completion *complete; + struct work_struct task; int apicid; int cpu; }; -static void __cpuinit do_warm_boot_cpu(void *p) +static void __cpuinit do_warm_boot_cpu(struct work_struct *work) { - struct warm_boot_cpu_info *info = p; + struct warm_boot_cpu_info *info = + container_of(work, struct warm_boot_cpu_info, task); do_boot_cpu(info->apicid, info->cpu); complete(info->complete); } @@ -1064,7 +1066,6 @@ static int __cpuinit __smp_prepare_cpu(int cpu) { DECLARE_COMPLETION_ONSTACK(done); struct warm_boot_cpu_info info; - struct work_struct task; int apicid, ret; struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); @@ -1089,7 +1090,7 @@ static int __cpuinit __smp_prepare_cpu(int cpu) info.complete = &done; info.apicid = apicid; info.cpu = cpu; - INIT_WORK(&task, do_warm_boot_cpu, &info); + INIT_WORK(&info.task, do_warm_boot_cpu); tsc_sync_disabled = 1; @@ -1097,7 +1098,7 @@ static int __cpuinit __smp_prepare_cpu(int cpu) clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, KERNEL_PGD_PTRS); flush_tlb_all(); - schedule_work(&task); + schedule_work(&info.task); wait_for_completion(&done); tsc_sync_disabled = 0; diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c index fbc95828cd7..9810c8c9075 100644 --- a/arch/i386/kernel/tsc.c +++ b/arch/i386/kernel/tsc.c @@ -217,7 +217,7 @@ static unsigned int cpufreq_delayed_issched = 0; static unsigned int cpufreq_init = 0; static struct work_struct cpufreq_delayed_get_work; -static void handle_cpufreq_delayed_get(void *v) +static void handle_cpufreq_delayed_get(struct work_struct *work) { unsigned int cpu; @@ -306,7 +306,7 @@ static int __init cpufreq_tsc(void) { int ret; - INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL); + INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get); ret = cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); if (!ret) diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index caab986af70..b62f0c4d2c7 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -209,7 +209,7 @@ static void do_serial_bh(void) } #endif -static void do_softint(void *private_) +static void do_softint(struct work_struct *private_) { printk(KERN_ERR "simserial: do_softint called\n"); } @@ -698,7 +698,7 @@ static int get_async_struct(int line, struct async_struct **ret_info) info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; info->line = line; - INIT_WORK(&info->work, do_softint, info); + INIT_WORK(&info->work, do_softint); info->state = sstate; if (sstate->info) { kfree(info); diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 7cfa63a98cb..6bedd97570c 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -678,7 +678,7 @@ ia64_mca_cmc_vector_enable (void *dummy) * disable the cmc interrupt vector. */ static void -ia64_mca_cmc_vector_disable_keventd(void *unused) +ia64_mca_cmc_vector_disable_keventd(struct work_struct *unused) { on_each_cpu(ia64_mca_cmc_vector_disable, NULL, 1, 0); } @@ -690,7 +690,7 @@ ia64_mca_cmc_vector_disable_keventd(void *unused) * enable the cmc interrupt vector. */ static void -ia64_mca_cmc_vector_enable_keventd(void *unused) +ia64_mca_cmc_vector_enable_keventd(struct work_struct *unused) { on_each_cpu(ia64_mca_cmc_vector_enable, NULL, 1, 0); } @@ -1247,8 +1247,8 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, monarch_cpu = -1; } -static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd, NULL); -static DECLARE_WORK(cmc_enable_work, ia64_mca_cmc_vector_enable_keventd, NULL); +static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd); +static DECLARE_WORK(cmc_enable_work, ia64_mca_cmc_vector_enable_keventd); /* * ia64_mca_cmc_int_handler diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index f7d7f566814..b21ddecea94 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -463,15 +463,17 @@ struct pt_regs * __devinit idle_regs(struct pt_regs *regs) } struct create_idle { + struct work_struct work; struct task_struct *idle; struct completion done; int cpu; }; void -do_fork_idle(void *_c_idle) +do_fork_idle(struct work_struct *work) { - struct create_idle *c_idle = _c_idle; + struct create_idle *c_idle = + container_of(work, struct create_idle, work); c_idle->idle = fork_idle(c_idle->cpu); complete(&c_idle->done); @@ -482,10 +484,10 @@ do_boot_cpu (int sapicid, int cpu) { int timeout; struct create_idle c_idle = { + .work = __WORK_INITIALIZER(c_idle.work, do_fork_idle), .cpu = cpu, .done = COMPLETION_INITIALIZER(c_idle.done), }; - DECLARE_WORK(work, do_fork_idle, &c_idle); c_idle.idle = get_idle_for_cpu(cpu); if (c_idle.idle) { @@ -497,9 +499,9 @@ do_boot_cpu (int sapicid, int cpu) * We can't use kernel_thread since we must avoid to reschedule the child. */ if (!keventd_up() || current_is_keventd()) - work.func(work.data); + c_idle.work.func(&c_idle.work); else { - schedule_work(&work); + schedule_work(&c_idle.work); wait_for_completion(&c_idle.done); } diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index f4edfbf2713..eb92cef9cd0 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -564,8 +564,8 @@ pcibios_enable_device (struct pci_dev *dev, int mask) void pcibios_disable_device (struct pci_dev *dev) { - if (dev->is_enabled) - acpi_pci_irq_disable(dev); + BUG_ON(atomic_read(&dev->enable_cnt)); + acpi_pci_irq_disable(dev); } void diff --git a/arch/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c index 24781f00933..e5668af1978 100644 --- a/arch/m68knommu/platform/5307/timers.c +++ b/arch/m68knommu/platform/5307/timers.c @@ -3,7 +3,7 @@ /* * timers.c -- generic ColdFire hardware timer support. * - * Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1999-2006, Greg Ungerer (gerg@snapgear.com) */ /***************************************************************************/ @@ -44,6 +44,14 @@ unsigned int mcf_timerlevel = 5; extern void mcf_settimericr(int timer, int level); extern int mcf_timerirqpending(int timer); +#if defined(CONFIG_M532x) +#define __raw_readtrr __raw_readl +#define __raw_writetrr __raw_writel +#else +#define __raw_readtrr __raw_readw +#define __raw_writetrr __raw_writew +#endif + /***************************************************************************/ void coldfire_tick(void) @@ -57,7 +65,7 @@ void coldfire_tick(void) void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)) { __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); - __raw_writew(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR)); + __raw_writetrr(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR)); __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR)); @@ -76,7 +84,7 @@ unsigned long coldfire_timer_offset(void) unsigned long trr, tcn, offset; tcn = __raw_readw(TA(MCFTIMER_TCN)); - trr = __raw_readw(TA(MCFTIMER_TRR)); + trr = __raw_readtrr(TA(MCFTIMER_TRR)); offset = (tcn * (1000000 / HZ)) / trr; /* Check if we just wrapped the counters and maybe missed a tick */ @@ -120,7 +128,7 @@ void coldfire_profile_init(void) /* Set up TIMER 2 as high speed profile clock */ __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR)); - __raw_writew(((MCF_CLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); + __raw_writetrr(((MCF_CLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR)); diff --git a/arch/m68knommu/platform/68360/config.c b/arch/m68knommu/platform/68360/config.c index c5482e3622e..1b36f626176 100644 --- a/arch/m68knommu/platform/68360/config.c +++ b/arch/m68knommu/platform/68360/config.c @@ -114,7 +114,7 @@ void BSP_gettod (int *yearp, int *monp, int *dayp, { } -int BSP_hwclk(int op, struct hwclk_time *t) +int BSP_hwclk(int op, struct rtc_time *t) { if (!op) { /* read */ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 4d64960be03..d8af858fe3f 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -242,6 +242,7 @@ config LASAT select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL select SYS_SUPPORTS_LITTLE_ENDIAN + select GENERIC_HARDIRQS_NO__DO_IRQ config MIPS_ATLAS bool "MIPS Atlas board" @@ -265,6 +266,7 @@ config MIPS_ATLAS select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_MULTITHREADING if EXPERIMENTAL + select GENERIC_HARDIRQS_NO__DO_IRQ help This enables support for the MIPS Technologies Atlas evaluation board. @@ -419,6 +421,7 @@ config MOMENCO_OCELOT_C select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN + select GENERIC_HARDIRQS_NO__DO_IRQ help The Ocelot is a MIPS-based Single Board Computer (SBC) made by Momentum Computer <http://www.momenco.com/>. @@ -569,6 +572,7 @@ config SGI_IP27 select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_NUMA select SYS_SUPPORTS_SMP + select GENERIC_HARDIRQS_NO__DO_IRQ help This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics workstations. To compile a Linux kernel that runs on these, say Y @@ -835,6 +839,10 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER bool default y +config GENERIC_HARDIRQS_NO__DO_IRQ + bool + default n + # # Select some configuration options automatically based on user selections. # @@ -996,6 +1004,7 @@ config SOC_PNX8550 select HW_HAS_PCI select SYS_HAS_CPU_MIPS32_R1 select SYS_SUPPORTS_32BIT_KERNEL + select GENERIC_HARDIRQS_NO__DO_IRQ config SWAP_IO_SPACE bool diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c index c8430c07355..6d55e8aab66 100644 --- a/arch/mips/dec/ecc-berr.c +++ b/arch/mips/dec/ecc-berr.c @@ -25,6 +25,7 @@ #include <asm/cpu.h> #include <asm/irq_regs.h> #include <asm/processor.h> +#include <asm/ptrace.h> #include <asm/system.h> #include <asm/traps.h> diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c index 269b22b3431..4c7cb4048d3 100644 --- a/arch/mips/dec/ioasic-irq.c +++ b/arch/mips/dec/ioasic-irq.c @@ -67,7 +67,6 @@ static struct irq_chip ioasic_irq_type = { .mask = mask_ioasic_irq, .mask_ack = ack_ioasic_irq, .unmask = unmask_ioasic_irq, - .end = end_ioasic_irq, }; @@ -106,8 +105,7 @@ void __init init_ioasic_irqs(int base) set_irq_chip_and_handler(i, &ioasic_irq_type, handle_level_irq); for (; i < base + IO_IRQ_LINES; i++) - set_irq_chip_and_handler(i, &ioasic_dma_irq_type, - handle_level_irq); + set_irq_chip(i, &ioasic_dma_irq_type); ioasic_irq_base = base; } diff --git a/arch/mips/dec/kn01-berr.c b/arch/mips/dec/kn01-berr.c index f19b4617a0a..d3b8002bf1e 100644 --- a/arch/mips/dec/kn01-berr.c +++ b/arch/mips/dec/kn01-berr.c @@ -20,8 +20,10 @@ #include <linux/types.h> #include <asm/inst.h> +#include <asm/irq_regs.h> #include <asm/mipsregs.h> #include <asm/page.h> +#include <asm/ptrace.h> #include <asm/system.h> #include <asm/traps.h> #include <asm/uaccess.h> diff --git a/arch/mips/dec/kn02-irq.c b/arch/mips/dec/kn02-irq.c index 5a9be4c9358..916e46b8ccd 100644 --- a/arch/mips/dec/kn02-irq.c +++ b/arch/mips/dec/kn02-irq.c @@ -57,19 +57,12 @@ static void ack_kn02_irq(unsigned int irq) iob(); } -static void end_kn02_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - unmask_kn02_irq(irq); -} - static struct irq_chip kn02_irq_type = { .typename = "KN02-CSR", .ack = ack_kn02_irq, .mask = mask_kn02_irq, .mask_ack = ack_kn02_irq, .unmask = unmask_kn02_irq, - .end = end_kn02_irq, }; diff --git a/arch/mips/emma2rh/common/irq_emma2rh.c b/arch/mips/emma2rh/common/irq_emma2rh.c index 59b98299c89..8d880f0b06e 100644 --- a/arch/mips/emma2rh/common/irq_emma2rh.c +++ b/arch/mips/emma2rh/common/irq_emma2rh.c @@ -56,19 +56,12 @@ static void emma2rh_irq_disable(unsigned int irq) ll_emma2rh_irq_disable(irq - emma2rh_irq_base); } -static void emma2rh_irq_end(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - ll_emma2rh_irq_enable(irq - emma2rh_irq_base); -} - struct irq_chip emma2rh_irq_controller = { .typename = "emma2rh_irq", .ack = emma2rh_irq_disable, .mask = emma2rh_irq_disable, .mask_ack = emma2rh_irq_disable, .unmask = emma2rh_irq_enable, - .end = emma2rh_irq_end, }; void emma2rh_irq_init(u32 irq_base) diff --git a/arch/mips/emma2rh/markeins/irq_markeins.c b/arch/mips/emma2rh/markeins/irq_markeins.c index 3ac4e405ecd..2116d9be5fa 100644 --- a/arch/mips/emma2rh/markeins/irq_markeins.c +++ b/arch/mips/emma2rh/markeins/irq_markeins.c @@ -48,19 +48,12 @@ static void emma2rh_sw_irq_disable(unsigned int irq) ll_emma2rh_sw_irq_disable(irq - emma2rh_sw_irq_base); } -static void emma2rh_sw_irq_end(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - ll_emma2rh_sw_irq_enable(irq - emma2rh_sw_irq_base); -} - struct irq_chip emma2rh_sw_irq_controller = { .typename = "emma2rh_sw_irq", .ack = emma2rh_sw_irq_disable, .mask = emma2rh_sw_irq_disable, .mask_ack = emma2rh_sw_irq_disable, .unmask = emma2rh_sw_irq_enable, - .end = emma2rh_sw_irq_end, }; void emma2rh_sw_irq_init(u32 irq_base) diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index 5c4f50cdf15..f8d417b5c2b 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c @@ -39,19 +39,12 @@ void disable_r4030_irq(unsigned int irq) spin_unlock_irqrestore(&r4030_lock, flags); } -static void end_r4030_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_r4030_irq(irq); -} - static struct irq_chip r4030_irq_type = { .typename = "R4030", .ack = disable_r4030_irq, .mask = disable_r4030_irq, .mask_ack = disable_r4030_irq, .unmask = enable_r4030_irq, - .end = end_r4030_irq, }; void __init init_r4030_ints(void) diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 2526c0ca4d8..b59a676c6d0 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -19,9 +19,6 @@ #include <asm/i8259.h> #include <asm/io.h> -void enable_8259A_irq(unsigned int irq); -void disable_8259A_irq(unsigned int irq); - /* * This is the 'legacy' 8259A Programmable Interrupt Controller, * present in the majority of PC/AT boxes. @@ -31,23 +28,16 @@ void disable_8259A_irq(unsigned int irq); * moves to arch independent land */ +static int i8259A_auto_eoi; DEFINE_SPINLOCK(i8259A_lock); - -static void end_8259A_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && - irq_desc[irq].action) - enable_8259A_irq(irq); -} - +/* some platforms call this... */ void mask_and_ack_8259A(unsigned int); -static struct irq_chip i8259A_irq_type = { - .typename = "XT-PIC", - .enable = enable_8259A_irq, - .disable = disable_8259A_irq, - .ack = mask_and_ack_8259A, - .end = end_8259A_irq, +static struct irq_chip i8259A_chip = { + .name = "XT-PIC", + .mask = disable_8259A_irq, + .unmask = enable_8259A_irq, + .mask_ack = mask_and_ack_8259A, }; /* @@ -59,8 +49,8 @@ static struct irq_chip i8259A_irq_type = { */ static unsigned int cached_irq_mask = 0xffff; -#define cached_21 (cached_irq_mask) -#define cached_A1 (cached_irq_mask >> 8) +#define cached_master_mask (cached_irq_mask) +#define cached_slave_mask (cached_irq_mask >> 8) void disable_8259A_irq(unsigned int irq) { @@ -70,9 +60,9 @@ void disable_8259A_irq(unsigned int irq) spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask |= mask; if (irq & 8) - outb(cached_A1,0xA1); + outb(cached_slave_mask, PIC_SLAVE_IMR); else - outb(cached_21,0x21); + outb(cached_master_mask, PIC_MASTER_IMR); spin_unlock_irqrestore(&i8259A_lock, flags); } @@ -84,9 +74,9 @@ void enable_8259A_irq(unsigned int irq) spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask &= mask; if (irq & 8) - outb(cached_A1,0xA1); + outb(cached_slave_mask, PIC_SLAVE_IMR); else - outb(cached_21,0x21); + outb(cached_master_mask, PIC_MASTER_IMR); spin_unlock_irqrestore(&i8259A_lock, flags); } @@ -98,9 +88,9 @@ int i8259A_irq_pending(unsigned int irq) spin_lock_irqsave(&i8259A_lock, flags); if (irq < 8) - ret = inb(0x20) & mask; + ret = inb(PIC_MASTER_CMD) & mask; else - ret = inb(0xA0) & (mask >> 8); + ret = inb(PIC_SLAVE_CMD) & (mask >> 8); spin_unlock_irqrestore(&i8259A_lock, flags); return ret; @@ -109,7 +99,7 @@ int i8259A_irq_pending(unsigned int irq) void make_8259A_irq(unsigned int irq) { disable_irq_nosync(irq); - set_irq_chip(irq, &i8259A_irq_type); + set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq); enable_irq(irq); } @@ -125,14 +115,14 @@ static inline int i8259A_irq_real(unsigned int irq) int irqmask = 1 << irq; if (irq < 8) { - outb(0x0B,0x20); /* ISR register */ - value = inb(0x20) & irqmask; - outb(0x0A,0x20); /* back to the IRR register */ + outb(0x0B,PIC_MASTER_CMD); /* ISR register */ + value = inb(PIC_MASTER_CMD) & irqmask; + outb(0x0A,PIC_MASTER_CMD); /* back to the IRR register */ return value; } - outb(0x0B,0xA0); /* ISR register */ - value = inb(0xA0) & (irqmask >> 8); - outb(0x0A,0xA0); /* back to the IRR register */ + outb(0x0B,PIC_SLAVE_CMD); /* ISR register */ + value = inb(PIC_SLAVE_CMD) & (irqmask >> 8); + outb(0x0A,PIC_SLAVE_CMD); /* back to the IRR register */ return value; } @@ -149,17 +139,19 @@ void mask_and_ack_8259A(unsigned int irq) spin_lock_irqsave(&i8259A_lock, flags); /* - * Lightweight spurious IRQ detection. We do not want to overdo - * spurious IRQ handling - it's usually a sign of hardware problems, so - * we only do the checks we can do without slowing down good hardware - * nnecesserily. + * Lightweight spurious IRQ detection. We do not want + * to overdo spurious IRQ handling - it's usually a sign + * of hardware problems, so we only do the checks we can + * do without slowing down good hardware unnecessarily. * - * Note that IRQ7 and IRQ15 (the two spurious IRQs usually resulting - * rom the 8259A-1|2 PICs) occur even if the IRQ is masked in the 8259A. - * Thus we can check spurious 8259A IRQs without doing the quite slow - * i8259A_irq_real() call for every IRQ. This does not cover 100% of - * spurious interrupts, but should be enough to warn the user that - * there is something bad going on ... + * Note that IRQ7 and IRQ15 (the two spurious IRQs + * usually resulting from the 8259A-1|2 PICs) occur + * even if the IRQ is masked in the 8259A. Thus we + * can check spurious 8259A IRQs without doing the + * quite slow i8259A_irq_real() call for every IRQ. + * This does not cover 100% of spurious interrupts, + * but should be enough to warn the user that there + * is something bad going on ... */ if (cached_irq_mask & irqmask) goto spurious_8259A_irq; @@ -167,14 +159,14 @@ void mask_and_ack_8259A(unsigned int irq) handle_real_irq: if (irq & 8) { - inb(0xA1); /* DUMMY - (do we need this?) */ - outb(cached_A1,0xA1); - outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */ - outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ + inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */ + outb(cached_slave_mask, PIC_SLAVE_IMR); + outb(0x60+(irq&7),PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ + outb(0x60+PIC_CASCADE_IR,PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ } else { - inb(0x21); /* DUMMY - (do we need this?) */ - outb(cached_21,0x21); - outb(0x60+irq,0x20); /* 'Specific EOI' to master */ + inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */ + outb(cached_master_mask, PIC_MASTER_IMR); + outb(0x60+irq,PIC_MASTER_CMD); /* 'Specific EOI to master */ } #ifdef CONFIG_MIPS_MT_SMTC if (irq_hwmask[irq] & ST0_IM) @@ -195,7 +187,7 @@ spurious_8259A_irq: goto handle_real_irq; { - static int spurious_irq_mask = 0; + static int spurious_irq_mask; /* * At this point we can be sure the IRQ is spurious, * lets ACK and report it. [once per IRQ] @@ -216,13 +208,25 @@ spurious_8259A_irq: static int i8259A_resume(struct sys_device *dev) { - init_8259A(0); + init_8259A(i8259A_auto_eoi); + return 0; +} + +static int i8259A_shutdown(struct sys_device *dev) +{ + /* Put the i8259A into a quiescent state that + * the kernel initialization code can get it + * out of. + */ + outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ + outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */ return 0; } static struct sysdev_class i8259_sysdev_class = { set_kset_name("i8259"), .resume = i8259A_resume, + .shutdown = i8259A_shutdown, }; static struct sys_device device_i8259A = { @@ -244,41 +248,41 @@ void __init init_8259A(int auto_eoi) { unsigned long flags; + i8259A_auto_eoi = auto_eoi; + spin_lock_irqsave(&i8259A_lock, flags); - outb(0xff, 0x21); /* mask all of 8259A-1 */ - outb(0xff, 0xA1); /* mask all of 8259A-2 */ + outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ + outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ /* * outb_p - this has to work on a wide range of PC hardware. */ - outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */ - outb_p(0x00, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x00-0x07 */ - outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */ - if (auto_eoi) - outb_p(0x03, 0x21); /* master does Auto EOI */ - else - outb_p(0x01, 0x21); /* master expects normal EOI */ - - outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */ - outb_p(0x08, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x08-0x0f */ - outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */ - outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode - is to be investigated) */ - + outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ + outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0 mapped to I8259A_IRQ_BASE + 0x00 */ + outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */ + if (auto_eoi) /* master does Auto EOI */ + outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); + else /* master expects normal EOI */ + outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR); + + outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */ + outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0 mapped to I8259A_IRQ_BASE + 0x08 */ + outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */ + outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ if (auto_eoi) /* - * in AEOI mode we just have to mask the interrupt + * In AEOI mode we just have to mask the interrupt * when acking. */ - i8259A_irq_type.ack = disable_8259A_irq; + i8259A_chip.mask_ack = disable_8259A_irq; else - i8259A_irq_type.ack = mask_and_ack_8259A; + i8259A_chip.mask_ack = mask_and_ack_8259A; udelay(100); /* wait for 8259A to initialize */ - outb(cached_21, 0x21); /* restore master IRQ mask */ - outb(cached_A1, 0xA1); /* restore slave IRQ mask */ + outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */ + outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */ spin_unlock_irqrestore(&i8259A_lock, flags); } @@ -291,11 +295,17 @@ static struct irqaction irq2 = { }; static struct resource pic1_io_resource = { - .name = "pic1", .start = 0x20, .end = 0x21, .flags = IORESOURCE_BUSY + .name = "pic1", + .start = PIC_MASTER_CMD, + .end = PIC_MASTER_IMR, + .flags = IORESOURCE_BUSY }; static struct resource pic2_io_resource = { - .name = "pic2", .start = 0xa0, .end = 0xa1, .flags = IORESOURCE_BUSY + .name = "pic2", + .start = PIC_SLAVE_CMD, + .end = PIC_SLAVE_IMR, + .flags = IORESOURCE_BUSY }; /* @@ -313,7 +323,7 @@ void __init init_i8259_irqs (void) init_8259A(0); for (i = 0; i < 16; i++) - set_irq_chip(i, &i8259A_irq_type); + set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq); - setup_irq(2, &irq2); + setup_irq(PIC_CASCADE_IR, &irq2); } diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c index 6cfb31cafde..efbd219845b 100644 --- a/arch/mips/kernel/irq-mv6434x.c +++ b/arch/mips/kernel/irq-mv6434x.c @@ -67,15 +67,6 @@ static inline void unmask_mv64340_irq(unsigned int irq) } /* - * End IRQ processing - */ -static void end_mv64340_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - unmask_mv64340_irq(irq); -} - -/* * Interrupt handler for interrupts coming from the Marvell chip. * It could be built in ethernet ports etc... */ @@ -106,7 +97,6 @@ struct irq_chip mv64340_irq_type = { .mask = mask_mv64340_irq, .mask_ack = mask_mv64340_irq, .unmask = unmask_mv64340_irq, - .end = end_mv64340_irq, }; void __init mv64340_irq_init(unsigned int base) diff --git a/arch/mips/kernel/irq-rm7000.c b/arch/mips/kernel/irq-rm7000.c index ddcc2a5f8a0..123324ba8c1 100644 --- a/arch/mips/kernel/irq-rm7000.c +++ b/arch/mips/kernel/irq-rm7000.c @@ -29,19 +29,12 @@ static inline void mask_rm7k_irq(unsigned int irq) clear_c0_intcontrol(0x100 << (irq - irq_base)); } -static void rm7k_cpu_irq_end(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - unmask_rm7k_irq(irq); -} - static struct irq_chip rm7k_irq_controller = { .typename = "RM7000", .ack = mask_rm7k_irq, .mask = mask_rm7k_irq, .mask_ack = mask_rm7k_irq, .unmask = unmask_rm7k_irq, - .end = rm7k_cpu_irq_end, }; void __init rm7k_cpu_irq_init(int base) diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c index ba6440c88ab..0e6f4c5349d 100644 --- a/arch/mips/kernel/irq-rm9000.c +++ b/arch/mips/kernel/irq-rm9000.c @@ -80,19 +80,12 @@ static void rm9k_perfcounter_irq_shutdown(unsigned int irq) on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 0, 1); } -static void rm9k_cpu_irq_end(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - unmask_rm9k_irq(irq); -} - static struct irq_chip rm9k_irq_controller = { .typename = "RM9000", .ack = mask_rm9k_irq, .mask = mask_rm9k_irq, .mask_ack = mask_rm9k_irq, .unmask = unmask_rm9k_irq, - .end = rm9k_cpu_irq_end, }; static struct irq_chip rm9k_perfcounter_irq = { @@ -103,7 +96,6 @@ static struct irq_chip rm9k_perfcounter_irq = { .mask = mask_rm9k_irq, .mask_ack = mask_rm9k_irq, .unmask = unmask_rm9k_irq, - .end = rm9k_cpu_irq_end, }; unsigned int rm9000_perfcount_irq; diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index b339798b317..2fe4c868a80 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -117,7 +117,7 @@ int show_interrupts(struct seq_file *p, void *v) for_each_online_cpu(j) seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif - seq_printf(p, " %14s", irq_desc[i].chip->typename); + seq_printf(p, " %14s", irq_desc[i].chip->name); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index be5ac23d381..fcc86b96ccf 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -50,12 +50,6 @@ static inline void mask_mips_irq(unsigned int irq) irq_disable_hazard(); } -static void mips_cpu_irq_end(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - unmask_mips_irq(irq); -} - static struct irq_chip mips_cpu_irq_controller = { .typename = "MIPS", .ack = mask_mips_irq, @@ -63,7 +57,6 @@ static struct irq_chip mips_cpu_irq_controller = { .mask_ack = mask_mips_irq, .unmask = unmask_mips_irq, .eoi = unmask_mips_irq, - .end = mips_cpu_irq_end, }; /* @@ -96,8 +89,6 @@ static void mips_mt_cpu_irq_ack(unsigned int irq) mask_mips_mt_irq(irq); } -#define mips_mt_cpu_irq_end mips_cpu_irq_end - static struct irq_chip mips_mt_cpu_irq_controller = { .typename = "MIPS", .startup = mips_mt_cpu_irq_startup, @@ -106,7 +97,6 @@ static struct irq_chip mips_mt_cpu_irq_controller = { .mask_ack = mips_mt_cpu_irq_ack, .unmask = unmask_mips_mt_irq, .eoi = unmask_mips_mt_irq, - .end = mips_mt_cpu_irq_end, }; void __init mips_cpu_irq_init(int irq_base) diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c index f06a144c788..2c82412b9ef 100644 --- a/arch/mips/kernel/kspd.c +++ b/arch/mips/kernel/kspd.c @@ -319,7 +319,7 @@ static void sp_cleanup(void) static int channel_open = 0; /* the work handler */ -static void sp_work(void *data) +static void sp_work(struct work_struct *unused) { if (!channel_open) { if( rtlx_open(RTLX_CHANNEL_SYSIO, 1) != 0) { @@ -354,7 +354,7 @@ static void startwork(int vpe) return; } - INIT_WORK(&work, sp_work, NULL); + INIT_WORK(&work, sp_work); queue_work(workqueue, &work); } else queue_work(workqueue, &work); diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c index 4a84a7beac5..2affa5ff171 100644 --- a/arch/mips/lasat/interrupt.c +++ b/arch/mips/lasat/interrupt.c @@ -44,19 +44,12 @@ void enable_lasat_irq(unsigned int irq_nr) *lasat_int_mask |= (1 << irq_nr) << lasat_int_mask_shift; } -static void end_lasat_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_lasat_irq(irq); -} - static struct irq_chip lasat_irq_type = { .typename = "Lasat", .ack = disable_lasat_irq, .mask = disable_lasat_irq, .mask_ack = disable_lasat_irq, .unmask = enable_lasat_irq, - .end = end_lasat_irq, }; static inline int ls1bit32(unsigned int x) diff --git a/arch/mips/momentum/ocelot_c/cpci-irq.c b/arch/mips/momentum/ocelot_c/cpci-irq.c index e5a4a0a8a7f..bb11fef0847 100644 --- a/arch/mips/momentum/ocelot_c/cpci-irq.c +++ b/arch/mips/momentum/ocelot_c/cpci-irq.c @@ -66,15 +66,6 @@ static inline void unmask_cpci_irq(unsigned int irq) } /* - * End IRQ processing - */ -static void end_cpci_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - unmask_cpci_irq(irq); -} - -/* * Interrupt handler for interrupts coming from the FPGA chip. * It could be built in ethernet ports etc... */ @@ -98,7 +89,6 @@ struct irq_chip cpci_irq_type = { .mask = mask_cpci_irq, .mask_ack = mask_cpci_irq, .unmask = unmask_cpci_irq, - .end = end_cpci_irq, }; void cpci_irq_init(void) diff --git a/arch/mips/momentum/ocelot_c/uart-irq.c b/arch/mips/momentum/ocelot_c/uart-irq.c index 0029f0008de..a7a80c0da56 100644 --- a/arch/mips/momentum/ocelot_c/uart-irq.c +++ b/arch/mips/momentum/ocelot_c/uart-irq.c @@ -60,15 +60,6 @@ static inline void unmask_uart_irq(unsigned int irq) } /* - * End IRQ processing - */ -static void end_uart_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - unmask_uart_irq(irq); -} - -/* * Interrupt handler for interrupts coming from the FPGA chip. */ void ll_uart_irq(void) @@ -91,7 +82,6 @@ struct irq_chip uart_irq_type = { .mask = mask_uart_irq, .mask_ack = mask_uart_irq, .unmask = unmask_uart_irq, - .end = end_uart_irq, }; void uart_irq_init(void) diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c index 0dc23930edb..2c36c108c4d 100644 --- a/arch/mips/philips/pnx8550/common/int.c +++ b/arch/mips/philips/pnx8550/common/int.c @@ -158,20 +158,12 @@ int pnx8550_set_gic_priority(int irq, int priority) return prev_priority; } -static void end_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { - unmask_irq(irq); - } -} - static struct irq_chip level_irq_type = { .typename = "PNX Level IRQ", .ack = mask_irq, .mask = mask_irq, .mask_ack = mask_irq, .unmask = unmask_irq, - .end = end_irq, }; static struct irqaction gic_action = { diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index c7b13805315..c44f8be0644 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -51,19 +51,12 @@ static void disable_local0_irq(unsigned int irq) sgint->imask0 &= ~(1 << (irq - SGINT_LOCAL0)); } -static void end_local0_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_local0_irq(irq); -} - static struct irq_chip ip22_local0_irq_type = { .typename = "IP22 local 0", .ack = disable_local0_irq, .mask = disable_local0_irq, .mask_ack = disable_local0_irq, .unmask = enable_local0_irq, - .end = end_local0_irq, }; static void enable_local1_irq(unsigned int irq) @@ -79,19 +72,12 @@ void disable_local1_irq(unsigned int irq) sgint->imask1 &= ~(1 << (irq - SGINT_LOCAL1)); } -static void end_local1_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_local1_irq(irq); -} - static struct irq_chip ip22_local1_irq_type = { .typename = "IP22 local 1", .ack = disable_local1_irq, .mask = disable_local1_irq, .mask_ack = disable_local1_irq, .unmask = enable_local1_irq, - .end = end_local1_irq, }; static void enable_local2_irq(unsigned int irq) @@ -107,19 +93,12 @@ void disable_local2_irq(unsigned int irq) sgint->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); } -static void end_local2_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_local2_irq(irq); -} - static struct irq_chip ip22_local2_irq_type = { .typename = "IP22 local 2", .ack = disable_local2_irq, .mask = disable_local2_irq, .mask_ack = disable_local2_irq, .unmask = enable_local2_irq, - .end = end_local2_irq, }; static void enable_local3_irq(unsigned int irq) @@ -135,19 +114,12 @@ void disable_local3_irq(unsigned int irq) sgint->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); } -static void end_local3_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_local3_irq(irq); -} - static struct irq_chip ip22_local3_irq_type = { .typename = "IP22 local 3", .ack = disable_local3_irq, .mask = disable_local3_irq, .mask_ack = disable_local3_irq, .unmask = enable_local3_irq, - .end = end_local3_irq, }; static void indy_local0_irqdispatch(void) diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 5f8835b4e84..319f8803ef6 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -332,13 +332,6 @@ static inline void disable_bridge_irq(unsigned int irq) intr_disconnect_level(cpu, swlevel); } -static void end_bridge_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && - irq_desc[irq].action) - enable_bridge_irq(irq); -} - static struct irq_chip bridge_irq_type = { .typename = "bridge", .startup = startup_bridge_irq, @@ -347,7 +340,6 @@ static struct irq_chip bridge_irq_type = { .mask = disable_bridge_irq, .mask_ack = disable_bridge_irq, .unmask = enable_bridge_irq, - .end = end_bridge_irq, }; void __devinit register_bridge_irq(unsigned int irq) diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index 7d361726bbf..c20e9899b34 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -180,10 +180,6 @@ static void disable_rt_irq(unsigned int irq) { } -static void end_rt_irq(unsigned int irq) -{ -} - static struct irq_chip rt_irq_type = { .typename = "SN HUB RT timer", .ack = disable_rt_irq, @@ -191,7 +187,6 @@ static struct irq_chip rt_irq_type = { .mask_ack = disable_rt_irq, .unmask = enable_rt_irq, .eoi = enable_rt_irq, - .end = end_rt_irq, }; static struct irqaction rt_irqaction = { diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c index 21873de49aa..ed4a19adf36 100644 --- a/arch/mips/tx4927/common/tx4927_irq.c +++ b/arch/mips/tx4927/common/tx4927_irq.c @@ -66,12 +66,10 @@ #define TX4927_IRQ_CP0_INIT ( 1 << 10 ) #define TX4927_IRQ_CP0_ENABLE ( 1 << 13 ) #define TX4927_IRQ_CP0_DISABLE ( 1 << 14 ) -#define TX4927_IRQ_CP0_ENDIRQ ( 1 << 16 ) #define TX4927_IRQ_PIC_INIT ( 1 << 20 ) #define TX4927_IRQ_PIC_ENABLE ( 1 << 23 ) #define TX4927_IRQ_PIC_DISABLE ( 1 << 24 ) -#define TX4927_IRQ_PIC_ENDIRQ ( 1 << 26 ) #define TX4927_IRQ_ALL 0xffffffff #endif @@ -82,12 +80,10 @@ static const u32 tx4927_irq_debug_flag = (TX4927_IRQ_NONE | TX4927_IRQ_WARN | TX4927_IRQ_EROR // | TX4927_IRQ_CP0_INIT // | TX4927_IRQ_CP0_ENABLE -// | TX4927_IRQ_CP0_DISABLE // | TX4927_IRQ_CP0_ENDIRQ // | TX4927_IRQ_PIC_INIT // | TX4927_IRQ_PIC_ENABLE // | TX4927_IRQ_PIC_DISABLE -// | TX4927_IRQ_PIC_ENDIRQ // | TX4927_IRQ_INIT // | TX4927_IRQ_NEST1 // | TX4927_IRQ_NEST2 @@ -114,11 +110,9 @@ static const u32 tx4927_irq_debug_flag = (TX4927_IRQ_NONE static void tx4927_irq_cp0_enable(unsigned int irq); static void tx4927_irq_cp0_disable(unsigned int irq); -static void tx4927_irq_cp0_end(unsigned int irq); static void tx4927_irq_pic_enable(unsigned int irq); static void tx4927_irq_pic_disable(unsigned int irq); -static void tx4927_irq_pic_end(unsigned int irq); /* * Kernel structs for all pic's @@ -131,7 +125,6 @@ static struct irq_chip tx4927_irq_cp0_type = { .mask = tx4927_irq_cp0_disable, .mask_ack = tx4927_irq_cp0_disable, .unmask = tx4927_irq_cp0_enable, - .end = tx4927_irq_cp0_end, }; #define TX4927_PIC_NAME "TX4927-PIC" @@ -141,7 +134,6 @@ static struct irq_chip tx4927_irq_pic_type = { .mask = tx4927_irq_pic_disable, .mask_ack = tx4927_irq_pic_disable, .unmask = tx4927_irq_pic_enable, - .end = tx4927_irq_pic_end, }; #define TX4927_PIC_ACTION(s) { no_action, 0, CPU_MASK_NONE, s, NULL, NULL } @@ -214,15 +206,6 @@ static void tx4927_irq_cp0_disable(unsigned int irq) tx4927_irq_cp0_modify(CCP0_STATUS, tx4927_irq_cp0_mask(irq), 0); } -static void tx4927_irq_cp0_end(unsigned int irq) -{ - TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_ENDIRQ, "irq=%d \n", irq); - - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - tx4927_irq_cp0_enable(irq); - } -} - /* * Functions for pic */ @@ -376,15 +359,6 @@ static void tx4927_irq_pic_disable(unsigned int irq) tx4927_irq_pic_mask(irq), 0); } -static void tx4927_irq_pic_end(unsigned int irq) -{ - TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_ENDIRQ, "irq=%d\n", irq); - - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - tx4927_irq_pic_enable(irq); - } -} - /* * Main init functions */ diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c index 34cdb2a240e..5a5ea6c0b9f 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c @@ -153,7 +153,6 @@ JP7 is not bus master -- do NOT use -- only 4 pci bus master's allowed -- SouthB #define TOSHIBA_RBTX4927_IRQ_IOC_INIT ( 1 << 10 ) #define TOSHIBA_RBTX4927_IRQ_IOC_ENABLE ( 1 << 13 ) #define TOSHIBA_RBTX4927_IRQ_IOC_DISABLE ( 1 << 14 ) -#define TOSHIBA_RBTX4927_IRQ_IOC_ENDIRQ ( 1 << 16 ) #define TOSHIBA_RBTX4927_IRQ_ISA_INIT ( 1 << 20 ) #define TOSHIBA_RBTX4927_IRQ_ISA_ENABLE ( 1 << 23 ) @@ -172,7 +171,6 @@ static const u32 toshiba_rbtx4927_irq_debug_flag = // | TOSHIBA_RBTX4927_IRQ_IOC_INIT // | TOSHIBA_RBTX4927_IRQ_IOC_ENABLE // | TOSHIBA_RBTX4927_IRQ_IOC_DISABLE -// | TOSHIBA_RBTX4927_IRQ_IOC_ENDIRQ // | TOSHIBA_RBTX4927_IRQ_ISA_INIT // | TOSHIBA_RBTX4927_IRQ_ISA_ENABLE // | TOSHIBA_RBTX4927_IRQ_ISA_DISABLE @@ -223,7 +221,6 @@ extern void mask_and_ack_8259A(unsigned int irq); static void toshiba_rbtx4927_irq_ioc_enable(unsigned int irq); static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq); -static void toshiba_rbtx4927_irq_ioc_end(unsigned int irq); #ifdef CONFIG_TOSHIBA_FPCIB0 static void toshiba_rbtx4927_irq_isa_enable(unsigned int irq); @@ -239,7 +236,6 @@ static struct irq_chip toshiba_rbtx4927_irq_ioc_type = { .mask = toshiba_rbtx4927_irq_ioc_disable, .mask_ack = toshiba_rbtx4927_irq_ioc_disable, .unmask = toshiba_rbtx4927_irq_ioc_enable, - .end = toshiba_rbtx4927_irq_ioc_end, }; #define TOSHIBA_RBTX4927_IOC_INTR_ENAB 0xbc002000 #define TOSHIBA_RBTX4927_IOC_INTR_STAT 0xbc002006 @@ -388,23 +384,6 @@ static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq) TOSHIBA_RBTX4927_WR08(TOSHIBA_RBTX4927_IOC_INTR_ENAB, v); } -static void toshiba_rbtx4927_irq_ioc_end(unsigned int irq) -{ - TOSHIBA_RBTX4927_IRQ_DPRINTK(TOSHIBA_RBTX4927_IRQ_IOC_ENDIRQ, - "irq=%d\n", irq); - - if (irq < TOSHIBA_RBTX4927_IRQ_IOC_BEG - || irq > TOSHIBA_RBTX4927_IRQ_IOC_END) { - TOSHIBA_RBTX4927_IRQ_DPRINTK(TOSHIBA_RBTX4927_IRQ_EROR, - "bad irq=%d\n", irq); - panic("\n"); - } - - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - toshiba_rbtx4927_irq_ioc_enable(irq); - } -} - /**********************************************************************************/ /* Functions for isa */ diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c index 42e127683ae..a347b424d91 100644 --- a/arch/mips/tx4938/common/irq.c +++ b/arch/mips/tx4938/common/irq.c @@ -39,11 +39,9 @@ static void tx4938_irq_cp0_enable(unsigned int irq); static void tx4938_irq_cp0_disable(unsigned int irq); -static void tx4938_irq_cp0_end(unsigned int irq); static void tx4938_irq_pic_enable(unsigned int irq); static void tx4938_irq_pic_disable(unsigned int irq); -static void tx4938_irq_pic_end(unsigned int irq); /**********************************************************************************/ /* Kernel structs for all pic's */ @@ -56,7 +54,6 @@ static struct irq_chip tx4938_irq_cp0_type = { .mask = tx4938_irq_cp0_disable, .mask_ack = tx4938_irq_cp0_disable, .unmask = tx4938_irq_cp0_enable, - .end = tx4938_irq_cp0_end, }; #define TX4938_PIC_NAME "TX4938-PIC" @@ -66,7 +63,6 @@ static struct irq_chip tx4938_irq_pic_type = { .mask = tx4938_irq_pic_disable, .mask_ack = tx4938_irq_pic_disable, .unmask = tx4938_irq_pic_enable, - .end = tx4938_irq_pic_end, }; static struct irqaction tx4938_irq_pic_action = { @@ -104,14 +100,6 @@ tx4938_irq_cp0_disable(unsigned int irq) clear_c0_status(tx4938_irq_cp0_mask(irq)); } -static void -tx4938_irq_cp0_end(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - tx4938_irq_cp0_enable(irq); - } -} - /**********************************************************************************/ /* Functions for pic */ /**********************************************************************************/ @@ -269,14 +257,6 @@ tx4938_irq_pic_disable(unsigned int irq) tx4938_irq_pic_mask(irq), 0); } -static void -tx4938_irq_pic_end(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - tx4938_irq_pic_enable(irq); - } -} - /**********************************************************************************/ /* Main init functions */ /**********************************************************************************/ diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c index 8c87a35f306..b6f363d0801 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c @@ -89,7 +89,6 @@ IRQ Device static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq); static void toshiba_rbtx4938_irq_ioc_disable(unsigned int irq); -static void toshiba_rbtx4938_irq_ioc_end(unsigned int irq); #define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC" static struct irq_chip toshiba_rbtx4938_irq_ioc_type = { @@ -98,7 +97,6 @@ static struct irq_chip toshiba_rbtx4938_irq_ioc_type = { .mask = toshiba_rbtx4938_irq_ioc_disable, .mask_ack = toshiba_rbtx4938_irq_ioc_disable, .unmask = toshiba_rbtx4938_irq_ioc_enable, - .end = toshiba_rbtx4938_irq_ioc_end, }; #define TOSHIBA_RBTX4938_IOC_INTR_ENAB 0xb7f02000 @@ -167,14 +165,6 @@ toshiba_rbtx4938_irq_ioc_disable(unsigned int irq) TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); } -static void -toshiba_rbtx4938_irq_ioc_end(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - toshiba_rbtx4938_irq_ioc_enable(irq); - } -} - extern void __init txx9_spi_irqinit(int irc_irq); void __init arch_init_irq(void) diff --git a/arch/mips/vr41xx/Kconfig b/arch/mips/vr41xx/Kconfig index 92f41f6f934..c8dfd8092ca 100644 --- a/arch/mips/vr41xx/Kconfig +++ b/arch/mips/vr41xx/Kconfig @@ -6,6 +6,7 @@ config CASIO_E55 select ISA select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN + select GENERIC_HARDIRQS_NO__DO_IRQ config IBM_WORKPAD bool "Support for IBM WorkPad z50" @@ -15,6 +16,7 @@ config IBM_WORKPAD select ISA select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN + select GENERIC_HARDIRQS_NO__DO_IRQ config NEC_CMBVR4133 bool "Support for NEC CMB-VR4133" @@ -39,6 +41,7 @@ config TANBAC_TB022X select IRQ_CPU select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN + select GENERIC_HARDIRQS_NO__DO_IRQ help The TANBAC VR4131 multichip module(TB0225) and the TANBAC VR4131DIMM(TB0229) are MIPS-based platforms @@ -71,6 +74,7 @@ config VICTOR_MPC30X select IRQ_CPU select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN + select GENERIC_HARDIRQS_NO__DO_IRQ config ZAO_CAPCELLA bool "Support for ZAO Networks Capcella" @@ -80,6 +84,7 @@ config ZAO_CAPCELLA select IRQ_CPU select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN + select GENERIC_HARDIRQS_NO__DO_IRQ config PCI_VR41XX bool "Add PCI control unit support of NEC VR4100 series" diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c index 54b92a74c7a..c075261976c 100644 --- a/arch/mips/vr41xx/common/icu.c +++ b/arch/mips/vr41xx/common/icu.c @@ -427,19 +427,12 @@ static void enable_sysint1_irq(unsigned int irq) icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq)); } -static void end_sysint1_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq)); -} - static struct irq_chip sysint1_irq_type = { .typename = "SYSINT1", .ack = disable_sysint1_irq, .mask = disable_sysint1_irq, .mask_ack = disable_sysint1_irq, .unmask = enable_sysint1_irq, - .end = end_sysint1_irq, }; static void disable_sysint2_irq(unsigned int irq) @@ -452,19 +445,12 @@ static void enable_sysint2_irq(unsigned int irq) icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq)); } -static void end_sysint2_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq)); -} - static struct irq_chip sysint2_irq_type = { .typename = "SYSINT2", .ack = disable_sysint2_irq, .mask = disable_sysint2_irq, .mask_ack = disable_sysint2_irq, .unmask = enable_sysint2_irq, - .end = end_sysint2_irq, }; static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c index 31bcdae8482..0e837762cc5 100644 --- a/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c @@ -14,7 +14,7 @@ static unsigned long avr_clock; static struct work_struct wd_work; -static void wd_stop(void *unused) +static void wd_stop(struct work_struct *unused) { const char string[] = "AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK"; int i = 0, rescue = 8; @@ -122,7 +122,7 @@ static int __init ls_uarts_init(void) ls_uart_init(); - INIT_WORK(&wd_work, wd_stop, NULL); + INIT_WORK(&wd_work, wd_stop); schedule_work(&wd_work); return 0; diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c index afa593a8544..c3a89414ddc 100644 --- a/arch/powerpc/platforms/powermac/backlight.c +++ b/arch/powerpc/platforms/powermac/backlight.c @@ -18,11 +18,11 @@ #define OLD_BACKLIGHT_MAX 15 -static void pmac_backlight_key_worker(void *data); -static void pmac_backlight_set_legacy_worker(void *data); +static void pmac_backlight_key_worker(struct work_struct *work); +static void pmac_backlight_set_legacy_worker(struct work_struct *work); -static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker, NULL); -static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker, NULL); +static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker); +static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker); /* Although these variables are used in interrupt context, it makes no sense to * protect them. No user is able to produce enough key events per second and @@ -94,7 +94,7 @@ int pmac_backlight_curve_lookup(struct fb_info *info, int value) return level; } -static void pmac_backlight_key_worker(void *data) +static void pmac_backlight_key_worker(struct work_struct *work) { if (atomic_read(&kernel_backlight_disabled)) return; @@ -166,7 +166,7 @@ static int __pmac_backlight_set_legacy_brightness(int brightness) return error; } -static void pmac_backlight_set_legacy_worker(void *data) +static void pmac_backlight_set_legacy_worker(struct work_struct *work) { if (atomic_read(&kernel_backlight_disabled)) return; diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index 13707745131..49037edf7d3 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -37,8 +37,8 @@ /* EEH event workqueue setup. */ static DEFINE_SPINLOCK(eeh_eventlist_lock); LIST_HEAD(eeh_eventlist); -static void eeh_thread_launcher(void *); -DECLARE_WORK(eeh_event_wq, eeh_thread_launcher, NULL); +static void eeh_thread_launcher(struct work_struct *); +DECLARE_WORK(eeh_event_wq, eeh_thread_launcher); /* Serialize reset sequences for a given pci device */ DEFINE_MUTEX(eeh_event_mutex); @@ -103,7 +103,7 @@ static int eeh_event_handler(void * dummy) * eeh_thread_launcher * @dummy - unused */ -static void eeh_thread_launcher(void *dummy) +static void eeh_thread_launcher(struct work_struct *dummy) { if (kernel_thread(eeh_event_handler, NULL, CLONE_KERNEL) < 0) printk(KERN_ERR "Failed to start EEH daemon\n"); diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c index 2e1943e2781..709952c25f2 100644 --- a/arch/ppc/8260_io/fcc_enet.c +++ b/arch/ppc/8260_io/fcc_enet.c @@ -385,6 +385,7 @@ struct fcc_enet_private { phy_info_t *phy; struct work_struct phy_relink; struct work_struct phy_display_config; + struct net_device *dev; uint sequence_done; @@ -1391,10 +1392,11 @@ static phy_info_t *phy_info[] = { NULL }; -static void mii_display_status(void *data) +static void mii_display_status(struct work_struct *work) { - struct net_device *dev = data; - volatile struct fcc_enet_private *fep = dev->priv; + volatile struct fcc_enet_private *fep = + container_of(work, struct fcc_enet_private, phy_relink); + struct net_device *dev = fep->dev; uint s = fep->phy_status; if (!fep->link && !fep->old_link) { @@ -1428,10 +1430,12 @@ static void mii_display_status(void *data) printk(".\n"); } -static void mii_display_config(void *data) +static void mii_display_config(struct work_struct *work) { - struct net_device *dev = data; - volatile struct fcc_enet_private *fep = dev->priv; + volatile struct fcc_enet_private *fep = + container_of(work, struct fcc_enet_private, + phy_display_config); + struct net_device *dev = fep->dev; uint s = fep->phy_status; printk("%s: config: auto-negotiation ", dev->name); @@ -1758,8 +1762,9 @@ static int __init fec_enet_init(void) cep->phy_id_done = 0; cep->phy_addr = fip->fc_phyaddr; mii_queue(dev, mk_mii_read(MII_PHYSID1), mii_discover_phy); - INIT_WORK(&cep->phy_relink, mii_display_status, dev); - INIT_WORK(&cep->phy_display_config, mii_display_config, dev); + INIT_WORK(&cep->phy_relink, mii_display_status); + INIT_WORK(&cep->phy_display_config, mii_display_config); + cep->dev = dev; #endif /* CONFIG_USE_MDIO */ fip++; diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c index 2f9fa9e3d33..e6c28fb423b 100644 --- a/arch/ppc/8xx_io/fec.c +++ b/arch/ppc/8xx_io/fec.c @@ -173,6 +173,7 @@ struct fec_enet_private { uint phy_speed; phy_info_t *phy; struct work_struct phy_task; + struct net_device *dev; uint sequence_done; @@ -1263,10 +1264,11 @@ static void mii_display_status(struct net_device *dev) printk(".\n"); } -static void mii_display_config(void *priv) +static void mii_display_config(struct work_struct *work) { - struct net_device *dev = (struct net_device *)priv; - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = + container_of(work, struct fec_enet_private, phy_task); + struct net_device *dev = fep->dev; volatile uint *s = &(fep->phy_status); printk("%s: config: auto-negotiation ", dev->name); @@ -1295,10 +1297,11 @@ static void mii_display_config(void *priv) fep->sequence_done = 1; } -static void mii_relink(void *priv) +static void mii_relink(struct work_struct *work) { - struct net_device *dev = (struct net_device *)priv; - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = + container_of(work, struct fec_enet_private, phy_task); + struct net_device *dev = fep->dev; int duplex; fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; @@ -1325,7 +1328,8 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = dev->priv; - INIT_WORK(&fep->phy_task, mii_relink, (void *)dev); + fep->dev = dev; + INIT_WORK(&fep->phy_task, mii_relink); schedule_work(&fep->phy_task); } @@ -1333,7 +1337,8 @@ static void mii_queue_config(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = dev->priv; - INIT_WORK(&fep->phy_task, mii_display_config, (void *)dev); + fep->dev = dev; + INIT_WORK(&fep->phy_task, mii_display_config); schedule_work(&fep->phy_task); } diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index af1e8fc7d98..67d5cf9cba8 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -92,8 +92,8 @@ static int appldata_timer_active; * Work queue */ static struct workqueue_struct *appldata_wq; -static void appldata_work_fn(void *data); -static DECLARE_WORK(appldata_work, appldata_work_fn, NULL); +static void appldata_work_fn(struct work_struct *work); +static DECLARE_WORK(appldata_work, appldata_work_fn); /* @@ -125,7 +125,7 @@ static void appldata_timer_function(unsigned long data) * * call data gathering function for each (active) module */ -static void appldata_work_fn(void *data) +static void appldata_work_fn(struct work_struct *work) { struct list_head *lh; struct appldata_ops *ops; diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index bffc7e17697..d83d64af31f 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -51,6 +51,14 @@ config GENERIC_TIME config ARCH_MAY_HAVE_PC_FDC bool +config STACKTRACE_SUPPORT + bool + default y + +config LOCKDEP_SUPPORT + bool + default y + source "init/Kconfig" menu "System type" @@ -219,6 +227,20 @@ config SH_SHMIN help Select SHMIN if configuring for the SHMIN board. +config SH_7206_SOLUTION_ENGINE + bool "SolutionEngine7206" + select CPU_SUBTYPE_SH7206 + help + Select 7206 SolutionEngine if configuring for a Hitachi SH7206 + evaluation board. + +config SH_7619_SOLUTION_ENGINE + bool "SolutionEngine7619" + select CPU_SUBTYPE_SH7619 + help + Select 7619 SolutionEngine if configuring for a Hitachi SH7619 + evaluation board. + config SH_UNKNOWN bool "BareCPU" help @@ -280,12 +302,20 @@ config CF_BASE_ADDR menu "Processor features" -config CPU_LITTLE_ENDIAN - bool "Little Endian" +choice + prompt "Endianess selection" + default CPU_LITTLE_ENDIAN help Some SuperH machines can be configured for either little or big - endian byte order. These modes require different kernels. Say Y if - your machine is little endian, N if it's a big endian machine. + endian byte order. These modes require different kernels. + +config CPU_LITTLE_ENDIAN + bool "Little Endian" + +config CPU_BIG_ENDIAN + bool "Big Endian" + +endchoice config SH_FPU bool "FPU support" @@ -345,6 +375,9 @@ config CPU_HAS_MASKREG_IRQ config CPU_HAS_INTC2_IRQ bool +config CPU_HAS_IPR_IRQ + bool + config CPU_HAS_SR_RB bool "CPU has SR.RB" depends on CPU_SH3 || CPU_SH4 @@ -357,6 +390,9 @@ config CPU_HAS_SR_RB See <file:Documentation/sh/register-banks.txt> for further information on SR.RB and register banking in the kernel in general. +config CPU_HAS_PTEA + bool + endmenu menu "Timer support" @@ -364,10 +400,25 @@ depends on !GENERIC_TIME config SH_TMU bool "TMU timer support" + depends on CPU_SH3 || CPU_SH4 default y help This enables the use of the TMU as the system timer. +config SH_CMT + bool "CMT timer support" + depends on CPU_SH2 + default y + help + This enables the use of the CMT as the system timer. + +config SH_MTU2 + bool "MTU2 timer support" + depends on CPU_SH2A + default n + help + This enables the use of the MTU2 as the system timer. + endmenu source "arch/sh/boards/renesas/hs7751rvoip/Kconfig" @@ -376,19 +427,52 @@ source "arch/sh/boards/renesas/rts7751r2d/Kconfig" source "arch/sh/boards/renesas/r7780rp/Kconfig" +config SH_TIMER_IRQ + int + default "28" if CPU_SUBTYPE_SH7780 + default "86" if CPU_SUBTYPE_SH7619 + default "140" if CPU_SUBTYPE_SH7206 + default "16" + +config NO_IDLE_HZ + bool "Dynamic tick timer" + help + Select this option if you want to disable continuous timer ticks + and have them programmed to occur as required. This option saves + power as the system can remain in idle state for longer. + + By default dynamic tick is disabled during the boot, and can be + manually enabled with: + + echo 1 > /sys/devices/system/timer/timer0/dyn_tick + + Alternatively, if you want dynamic tick automatically enabled + during boot, pass "dyntick=enable" via the kernel command string. + + Please note that dynamic tick may affect the accuracy of + timekeeping on some platforms depending on the implementation. + config SH_PCLK_FREQ int "Peripheral clock frequency (in Hz)" + default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343 + default "31250000" if CPU_SUBTYPE_SH7619 + default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \ + CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \ + CPU_SUBTYPE_SH7206 default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780 default "60000000" if CPU_SUBTYPE_SH7751 - default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \ - CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 - default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343 default "66000000" if CPU_SUBTYPE_SH4_202 help This option is used to specify the peripheral clock frequency. This is necessary for determining the reference clock value on platforms lacking an RTC. +config SH_CLK_MD + int "CPU Mode Pin Setting" + depends on CPU_SUBTYPE_SH7619 || CPU_SUBTYPE_SH7206 + help + MD2 - MD0 Setting. + menu "CPU Frequency scaling" source "drivers/cpufreq/Kconfig" @@ -421,6 +505,8 @@ config HEARTBEAT behavior is platform-dependent, but normally the flash frequency is a hyperbolic function of the 5-minute load average. +source "arch/sh/drivers/Kconfig" + endmenu config ISA_DMA_API diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug index 48479e014da..66a25ef4ef1 100644 --- a/arch/sh/Kconfig.debug +++ b/arch/sh/Kconfig.debug @@ -1,5 +1,9 @@ menu "Kernel hacking" +config TRACE_IRQFLAGS_SUPPORT + bool + default y + source "lib/Kconfig.debug" config SH_STANDARD_BIOS @@ -17,7 +21,18 @@ config SH_STANDARD_BIOS config EARLY_SCIF_CONSOLE bool "Use early SCIF console" - depends on CPU_SH4 || CPU_SH2A && !SH_STANDARD_BIOS + help + This enables an early console using a fixed SCIF port. This can + be used by platforms that are either not running the SH + standard BIOS, or do not wish to use the BIOS callbacks for the + serial I/O. + +config EARLY_SCIF_CONSOLE_PORT + hex "SCIF port for early console" + depends on EARLY_SCIF_CONSOLE + default "0xffe00000" if CPU_SUBTYPE_SH7780 + default "0xfffe9800" if CPU_SUBTYPE_SH72060 + default "0xffe80000" if CPU_SH4 config EARLY_PRINTK bool "Early printk support" @@ -30,6 +45,11 @@ config EARLY_PRINTK when the kernel may crash or hang before the serial console is initialised. If unsure, say N. + On devices that are running SH-IPL and want to keep the port + initialization consistent while not using the BIOS callbacks, + select both the EARLY_SCIF_CONSOLE and SH_STANDARD_BIOS, using + the kernel command line option to toggle back and forth. + config DEBUG_STACKOVERFLOW bool "Check for stack overflows" depends on DEBUG_KERNEL diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 26d62ff51a6..d10bba5e107 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -13,10 +13,6 @@ # for "archclean" and "archdep" for cleaning up and making dependencies for # this architecture # - -cflags-y := -mb -cflags-$(CONFIG_CPU_LITTLE_ENDIAN) := -ml - isa-y := any isa-$(CONFIG_SH_DSP) := sh isa-$(CONFIG_CPU_SH2) := sh2 @@ -38,13 +34,16 @@ isa-y := $(isa-y)-nofpu endif endif -cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) - -cflags-$(CONFIG_CPU_SH2) += -m2 -cflags-$(CONFIG_CPU_SH3) += -m3 -cflags-$(CONFIG_CPU_SH4) += -m4 \ +cflags-$(CONFIG_CPU_SH2) := -m2 +cflags-$(CONFIG_CPU_SH3) := -m3 +cflags-$(CONFIG_CPU_SH4) := -m4 \ $(call cc-option,-mno-implicit-fp,-m4-nofpu) -cflags-$(CONFIG_CPU_SH4A) += $(call cc-option,-m4a-nofpu,) +cflags-$(CONFIG_CPU_SH4A) := -m4a $(call cc-option,-m4a-nofpu,) + +cflags-$(CONFIG_CPU_BIG_ENDIAN) += -mb +cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml + +cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) -ffreestanding cflags-$(CONFIG_SH_DSP) += -Wa,-dsp cflags-$(CONFIG_SH_KGDB) += -g @@ -59,7 +58,9 @@ OBJCOPYFLAGS := -O binary -R .note -R .comment -R .stab -R .stabstr -S # never be used by anyone. Use a board-specific defconfig that has a # reasonable chance of being current instead. # -KBUILD_DEFCONFIG := rts7751r2d_defconfig +KBUILD_DEFCONFIG := r7780rp_defconfig + +KBUILD_IMAGE := arch/sh/boot/zImage # # Choosing incompatible machines durings configuration will result in @@ -109,6 +110,8 @@ machdir-$(CONFIG_SH_SH4202_MICRODEV) := superh/microdev machdir-$(CONFIG_SH_LANDISK) := landisk machdir-$(CONFIG_SH_TITAN) := titan machdir-$(CONFIG_SH_SHMIN) := shmin +machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE) := se/7206 +machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE) := se/7619 machdir-$(CONFIG_SH_UNKNOWN) := unknown incdir-y := $(notdir $(machdir-y)) @@ -124,6 +127,7 @@ core-$(CONFIG_HD64465) += arch/sh/cchips/hd6446x/hd64465/ core-$(CONFIG_VOYAGERGX) += arch/sh/cchips/voyagergx/ cpuincdir-$(CONFIG_CPU_SH2) := cpu-sh2 +cpuincdir-$(CONFIG_CPU_SH2A) := cpu-sh2a cpuincdir-$(CONFIG_CPU_SH3) := cpu-sh3 cpuincdir-$(CONFIG_CPU_SH4) := cpu-sh4 diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile index f1776d02797..574b0316ed5 100644 --- a/arch/sh/boards/renesas/r7780rp/Makefile +++ b/arch/sh/boards/renesas/r7780rp/Makefile @@ -3,4 +3,6 @@ # obj-y := setup.o io.o irq.o -obj-$(CONFIG_HEARTBEAT) += led.o + +obj-$(CONFIG_HEARTBEAT) += led.o +obj-$(CONFIG_PUSH_SWITCH) += psw.o diff --git a/arch/sh/boards/renesas/r7780rp/irq.c b/arch/sh/boards/renesas/r7780rp/irq.c index aa15ec5bc69..cc381e19778 100644 --- a/arch/sh/boards/renesas/r7780rp/irq.c +++ b/arch/sh/boards/renesas/r7780rp/irq.c @@ -10,6 +10,7 @@ */ #include <linux/init.h> #include <linux/irq.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <asm/r7780rp.h> diff --git a/arch/sh/boards/renesas/r7780rp/psw.c b/arch/sh/boards/renesas/r7780rp/psw.c new file mode 100644 index 00000000000..c844dfa5d58 --- /dev/null +++ b/arch/sh/boards/renesas/r7780rp/psw.c @@ -0,0 +1,122 @@ +/* + * arch/sh/boards/renesas/r7780rp/psw.c + * + * push switch support for RDBRP-1/RDBREVRP-1 debug boards. + * + * Copyright (C) 2006 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/io.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <asm/mach/r7780rp.h> +#include <asm/push-switch.h> + +static irqreturn_t psw_irq_handler(int irq, void *arg) +{ + struct platform_device *pdev = arg; + struct push_switch *psw = platform_get_drvdata(pdev); + struct push_switch_platform_info *psw_info = pdev->dev.platform_data; + unsigned int l, mask; + int ret = 0; + + l = ctrl_inw(PA_DBSW); + + /* Nothing to do if there's no state change */ + if (psw->state) { + ret = 1; + goto out; + } + + mask = l & 0x70; + /* Figure out who raised it */ + if (mask & (1 << psw_info->bit)) { + psw->state = !!(mask & (1 << psw_info->bit)); + if (psw->state) /* debounce */ + mod_timer(&psw->debounce, jiffies + 50); + + ret = 1; + } + +out: + /* Clear the switch IRQs */ + l |= (0x7 << 12); + ctrl_outw(l, PA_DBSW); + + return IRQ_RETVAL(ret); +} + +static struct resource psw_resources[] = { + [0] = { + .start = IRQ_PSW, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct push_switch_platform_info s2_platform_data = { + .name = "s2", + .bit = 6, + .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_SHARED, + .irq_handler = psw_irq_handler, +}; + +static struct platform_device s2_switch_device = { + .name = "push-switch", + .id = 0, + .num_resources = ARRAY_SIZE(psw_resources), + .resource = psw_resources, + .dev = { + .platform_data = &s2_platform_data, + }, +}; + +static struct push_switch_platform_info s3_platform_data = { + .name = "s3", + .bit = 5, + .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_SHARED, + .irq_handler = psw_irq_handler, +}; + +static struct platform_device s3_switch_device = { + .name = "push-switch", + .id = 1, + .num_resources = ARRAY_SIZE(psw_resources), + .resource = psw_resources, + .dev = { + .platform_data = &s3_platform_data, + }, +}; + +static struct push_switch_platform_info s4_platform_data = { + .name = "s4", + .bit = 4, + .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_SHARED, + .irq_handler = psw_irq_handler, +}; + +static struct platform_device s4_switch_device = { + .name = "push-switch", + .id = 2, + .num_resources = ARRAY_SIZE(psw_resources), + .resource = psw_resources, + .dev = { + .platform_data = &s4_platform_data, + }, +}; + +static struct platform_device *psw_devices[] = { + &s2_switch_device, &s3_switch_device, &s4_switch_device, +}; + +static int __init psw_init(void) +{ + return platform_add_devices(psw_devices, ARRAY_SIZE(psw_devices)); +} +module_init(psw_init); diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c index c331caeb694..9f89c8de9db 100644 --- a/arch/sh/boards/renesas/r7780rp/setup.c +++ b/arch/sh/boards/renesas/r7780rp/setup.c @@ -44,8 +44,37 @@ static struct platform_device m66596_usb_host_device = { .resource = m66596_usb_host_resources, }; +static struct resource cf_ide_resources[] = { + [0] = { + .start = 0x1f0, + .end = 0x1f0 + 8, + .flags = IORESOURCE_IO, + }, + [1] = { + .start = 0x1f0 + 0x206, + .end = 0x1f0 + 8 + 0x206 + 8, + .flags = IORESOURCE_IO, + }, + [2] = { +#ifdef CONFIG_SH_R7780MP + .start = 1, +#else + .start = 4, +#endif + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device cf_ide_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(cf_ide_resources), + .resource = cf_ide_resources, +}; + static struct platform_device *r7780rp_devices[] __initdata = { &m66596_usb_host_device, + &cf_ide_device, }; static int __init r7780rp_devices_setup(void) diff --git a/arch/sh/boards/se/7206/Makefile b/arch/sh/boards/se/7206/Makefile new file mode 100644 index 00000000000..63950f4f245 --- /dev/null +++ b/arch/sh/boards/se/7206/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the 7206 SolutionEngine specific parts of the kernel +# + +obj-y := setup.o io.o irq.o +obj-$(CONFIG_HEARTBEAT) += led.o + diff --git a/arch/sh/boards/se/7206/io.c b/arch/sh/boards/se/7206/io.c new file mode 100644 index 00000000000..b557273e0cb --- /dev/null +++ b/arch/sh/boards/se/7206/io.c @@ -0,0 +1,123 @@ +/* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $ + * + * linux/arch/sh/boards/se/7206/io.c + * + * Copyright (C) 2006 Yoshinori Sato + * + * I/O routine for Hitachi 7206 SolutionEngine. + * + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <asm/io.h> +#include <asm/se7206.h> + + +static inline void delay(void) +{ + ctrl_inw(0x20000000); /* P2 ROM Area */ +} + +/* MS7750 requires special versions of in*, out* routines, since + PC-like io ports are located at upper half byte of 16-bit word which + can be accessed only with 16-bit wide. */ + +static inline volatile __u16 * +port2adr(unsigned int port) +{ + if (port >= 0x2000) + return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000)); + else if (port >= 0x300 || port < 0x310) + return (volatile __u16 *) (PA_SMSC + (port - 0x300)); +} + +unsigned char se7206_inb(unsigned long port) +{ + return (*port2adr(port))&0xff; +} + +unsigned char se7206_inb_p(unsigned long port) +{ + unsigned long v; + + v = (*port2adr(port))&0xff; + delay(); + return v; +} + +unsigned short se7206_inw(unsigned long port) +{ + return *port2adr(port);; +} + +unsigned int se7206_inl(unsigned long port) +{ + maybebadio(port); + return 0; +} + +void se7206_outb(unsigned char value, unsigned long port) +{ + *(port2adr(port)) = value; +} + +void se7206_outb_p(unsigned char value, unsigned long port) +{ + *(port2adr(port)) = value; + delay(); +} + +void se7206_outw(unsigned short value, unsigned long port) +{ + *port2adr(port) = value; +} + +void se7206_outl(unsigned int value, unsigned long port) +{ + maybebadio(port); +} + +void se7206_insb(unsigned long port, void *addr, unsigned long count) +{ + volatile __u16 *p = port2adr(port); + __u8 *ap = addr; + + while (count--) + *ap++ = *p; +} + +void se7206_insw(unsigned long port, void *addr, unsigned long count) +{ + volatile __u16 *p = port2adr(port); + __u16 *ap = addr; + while (count--) + *ap++ = *p; +} + +void se7206_insl(unsigned long port, void *addr, unsigned long count) +{ + maybebadio(port); +} + +void se7206_outsb(unsigned long port, const void *addr, unsigned long count) +{ + volatile __u16 *p = port2adr(port); + const __u8 *ap = addr; + + while (count--) + *p = *ap++; +} + +void se7206_outsw(unsigned long port, const void *addr, unsigned long count) +{ + volatile __u16 *p = port2adr(port); + const __u16 *ap = addr; + while (count--) + *p = *ap++; +} + +void se7206_outsl(unsigned long port, const void *addr, unsigned long count) +{ + maybebadio(port); +} diff --git a/arch/sh/boards/se/7206/irq.c b/arch/sh/boards/se/7206/irq.c new file mode 100644 index 00000000000..3fb0c5f5b23 --- /dev/null +++ b/arch/sh/boards/se/7206/irq.c @@ -0,0 +1,139 @@ +/* + * linux/arch/sh/boards/se/7206/irq.c + * + * Copyright (C) 2005,2006 Yoshinori Sato + * + * Hitachi SolutionEngine Support. + * + */ +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <asm/se7206.h> + +#define INTSTS0 0x31800000 +#define INTSTS1 0x31800002 +#define INTMSK0 0x31800004 +#define INTMSK1 0x31800006 +#define INTSEL 0x31800008 + +static void disable_se7206_irq(unsigned int irq) +{ + unsigned short val; + unsigned short mask = 0xffff ^ (0x0f << 4 * (3 - (IRQ0_IRQ - irq))); + unsigned short msk0,msk1; + + /* Set the priority in IPR to 0 */ + val = ctrl_inw(INTC_IPR01); + val &= mask; + ctrl_outw(val, INTC_IPR01); + /* FPGA mask set */ + msk0 = ctrl_inw(INTMSK0); + msk1 = ctrl_inw(INTMSK1); + + switch (irq) { + case IRQ0_IRQ: + msk0 |= 0x0010; + break; + case IRQ1_IRQ: + msk0 |= 0x000f; + break; + case IRQ2_IRQ: + msk0 |= 0x0f00; + msk1 |= 0x00ff; + break; + } + ctrl_outw(msk0, INTMSK0); + ctrl_outw(msk1, INTMSK1); +} + +static void enable_se7206_irq(unsigned int irq) +{ + unsigned short val; + unsigned short value = (0x0001 << 4 * (3 - (IRQ0_IRQ - irq))); + unsigned short msk0,msk1; + + /* Set priority in IPR back to original value */ + val = ctrl_inw(INTC_IPR01); + val |= value; + ctrl_outw(val, INTC_IPR01); + + /* FPGA mask reset */ + msk0 = ctrl_inw(INTMSK0); + msk1 = ctrl_inw(INTMSK1); + + switch (irq) { + case IRQ0_IRQ: + msk0 &= ~0x0010; + break; + case IRQ1_IRQ: + msk0 &= ~0x000f; + break; + case IRQ2_IRQ: + msk0 &= ~0x0f00; + msk1 &= ~0x00ff; + break; + } + ctrl_outw(msk0, INTMSK0); + ctrl_outw(msk1, INTMSK1); +} + +static void eoi_se7206_irq(unsigned int irq) +{ + unsigned short sts0,sts1; + + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_se7206_irq(irq); + /* FPGA isr clear */ + sts0 = ctrl_inw(INTSTS0); + sts1 = ctrl_inw(INTSTS1); + + switch (irq) { + case IRQ0_IRQ: + sts0 &= ~0x0010; + break; + case IRQ1_IRQ: + sts0 &= ~0x000f; + break; + case IRQ2_IRQ: + sts0 &= ~0x0f00; + sts1 &= ~0x00ff; + break; + } + ctrl_outw(sts0, INTSTS0); + ctrl_outw(sts1, INTSTS1); +} + +static struct irq_chip se7206_irq_chip __read_mostly = { + .name = "SE7206-FPGA-IRQ", + .mask = disable_se7206_irq, + .unmask = enable_se7206_irq, + .mask_ack = disable_se7206_irq, + .eoi = eoi_se7206_irq, +}; + +static void make_se7206_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + set_irq_chip_and_handler_name(irq, &se7206_irq_chip, + handle_level_irq, "level"); + disable_se7206_irq(irq); +} + +/* + * Initialize IRQ setting + */ +void __init init_se7206_IRQ(void) +{ + make_se7206_irq(IRQ0_IRQ); /* SMC91C111 */ + make_se7206_irq(IRQ1_IRQ); /* ATA */ + make_se7206_irq(IRQ3_IRQ); /* SLOT / PCM */ + ctrl_outw(inw(INTC_ICR1) | 0x000b ,INTC_ICR1 ) ; /* ICR1 */ + + /* FPGA System register setup*/ + ctrl_outw(0x0000,INTSTS0); /* Clear INTSTS0 */ + ctrl_outw(0x0000,INTSTS1); /* Clear INTSTS1 */ + /* IRQ0=LAN, IRQ1=ATA, IRQ3=SLT,PCM */ + ctrl_outw(0x0001,INTSEL); +} diff --git a/arch/sh/boards/se/7206/led.c b/arch/sh/boards/se/7206/led.c new file mode 100644 index 00000000000..ef794601ab8 --- /dev/null +++ b/arch/sh/boards/se/7206/led.c @@ -0,0 +1,57 @@ +/* + * linux/arch/sh/kernel/led_se.c + * + * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com> + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * This file contains Solution Engine specific LED code. + */ + +#include <linux/config.h> +#include <asm/se7206.h> + +#ifdef CONFIG_HEARTBEAT + +#include <linux/sched.h> + +/* Cycle the LED's in the clasic Knightrider/Sun pattern */ +void heartbeat_se(void) +{ + static unsigned int cnt = 0, period = 0; + volatile unsigned short* p = (volatile unsigned short*)PA_LED; + static unsigned bit = 0, up = 1; + + cnt += 1; + if (cnt < period) { + return; + } + + cnt = 0; + + /* Go through the points (roughly!): + * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 + */ + period = 110 - ( (300<<FSHIFT)/ + ((avenrun[0]/5) + (3<<FSHIFT)) ); + + if (up) { + if (bit == 7) { + bit--; + up=0; + } else { + bit ++; + } + } else { + if (bit == 0) { + bit++; + up=1; + } else { + bit--; + } + } + *p = 1<<(bit+8); + +} +#endif /* CONFIG_HEARTBEAT */ diff --git a/arch/sh/boards/se/7206/setup.c b/arch/sh/boards/se/7206/setup.c new file mode 100644 index 00000000000..0f42e91a323 --- /dev/null +++ b/arch/sh/boards/se/7206/setup.c @@ -0,0 +1,79 @@ +/* + * + * linux/arch/sh/boards/se/7206/setup.c + * + * Copyright (C) 2006 Yoshinori Sato + * + * Hitachi 7206 SolutionEngine Support. + * + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <asm/se7206.h> +#include <asm/io.h> +#include <asm/machvec.h> + +static struct resource smc91x_resources[] = { + [0] = { + .start = 0x300, + .end = 0x300 + 0x020 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 64, + .end = 64, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = -1, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static int __init se7206_devices_setup(void) +{ + return platform_device_register(&smc91x_device); +} + +__initcall(se7206_devices_setup); + +void heartbeat_se(void); + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_se __initmv = { + .mv_name = "SolutionEngine", + .mv_nr_irqs = 256, + .mv_inb = se7206_inb, + .mv_inw = se7206_inw, + .mv_inl = se7206_inl, + .mv_outb = se7206_outb, + .mv_outw = se7206_outw, + .mv_outl = se7206_outl, + + .mv_inb_p = se7206_inb_p, + .mv_inw_p = se7206_inw, + .mv_inl_p = se7206_inl, + .mv_outb_p = se7206_outb_p, + .mv_outw_p = se7206_outw, + .mv_outl_p = se7206_outl, + + .mv_insb = se7206_insb, + .mv_insw = se7206_insw, + .mv_insl = se7206_insl, + .mv_outsb = se7206_outsb, + .mv_outsw = se7206_outsw, + .mv_outsl = se7206_outsl, + + .mv_init_irq = init_se7206_IRQ, +#ifdef CONFIG_HEARTBEAT + .mv_heartbeat = heartbeat_se, +#endif +}; +ALIAS_MV(se) diff --git a/arch/sh/boards/se/7619/Makefile b/arch/sh/boards/se/7619/Makefile new file mode 100644 index 00000000000..3666eca8a65 --- /dev/null +++ b/arch/sh/boards/se/7619/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the 7619 SolutionEngine specific parts of the kernel +# + +obj-y := setup.o io.o diff --git a/arch/sh/boards/se/7619/io.c b/arch/sh/boards/se/7619/io.c new file mode 100644 index 00000000000..176f1f39cd9 --- /dev/null +++ b/arch/sh/boards/se/7619/io.c @@ -0,0 +1,102 @@ +/* + * + * linux/arch/sh/boards/se/7619/io.c + * + * Copyright (C) 2006 Yoshinori Sato + * + * I/O routine for Hitachi 7619 SolutionEngine. + * + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <asm/io.h> +#include <asm/se7619.h> +#include <asm/irq.h> + +/* FIXME: M3A-ZAB7 Compact Flash Slot support */ + +static inline void delay(void) +{ + ctrl_inw(0xa0000000); /* Uncached ROM area (P2) */ +} + +#define badio(name,port) \ + printk("bad I/O operation (%s) for port 0x%lx at 0x%08x\n", \ + #name, (port), (__u32) __builtin_return_address(0)) + +unsigned char se7619___inb(unsigned long port) +{ + badio(inb, port); + return 0; +} + +unsigned char se7619___inb_p(unsigned long port) +{ + badio(inb_p, port); + delay(); + return 0; +} + +unsigned short se7619___inw(unsigned long port) +{ + badio(inw, port); + return 0; +} + +unsigned int se7619___inl(unsigned long port) +{ + badio(inl, port); + return 0; +} + +void se7619___outb(unsigned char value, unsigned long port) +{ + badio(outb, port); +} + +void se7619___outb_p(unsigned char value, unsigned long port) +{ + badio(outb_p, port); + delay(); +} + +void se7619___outw(unsigned short value, unsigned long port) +{ + badio(outw, port); +} + +void se7619___outl(unsigned int value, unsigned long port) +{ + badio(outl, port); +} + +void se7619___insb(unsigned long port, void *addr, unsigned long count) +{ + badio(inw, port); +} + +void se7619___insw(unsigned long port, void *addr, unsigned long count) +{ + badio(inw, port); +} + +void se7619___insl(unsigned long port, void *addr, unsigned long count) +{ + badio(insl, port); +} + +void se7619___outsb(unsigned long port, const void *addr, unsigned long count) +{ + badio(insl, port); +} + +void se7619___outsw(unsigned long port, const void *addr, unsigned long count) +{ + badio(insl, port); +} + +void se7619___outsl(unsigned long port, const void *addr, unsigned long count) +{ + badio(outsw, port); +} diff --git a/arch/sh/boards/se/7619/setup.c b/arch/sh/boards/se/7619/setup.c new file mode 100644 index 00000000000..e627b26de0d --- /dev/null +++ b/arch/sh/boards/se/7619/setup.c @@ -0,0 +1,43 @@ +/* + * arch/sh/boards/se/7619/setup.c + * + * Copyright (C) 2006 Yoshinori Sato + * + * Hitachi SH7619 SolutionEngine Support. + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <asm/io.h> +#include <asm/se7619.h> +#include <asm/machvec.h> + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_se __initmv = { + .mv_name = "SolutionEngine", + .mv_nr_irqs = 108, + .mv_inb = se7619___inb, + .mv_inw = se7619___inw, + .mv_inl = se7619___inl, + .mv_outb = se7619___outb, + .mv_outw = se7619___outw, + .mv_outl = se7619___outl, + + .mv_inb_p = se7619___inb_p, + .mv_inw_p = se7619___inw, + .mv_inl_p = se7619___inl, + .mv_outb_p = se7619___outb_p, + .mv_outw_p = se7619___outw, + .mv_outl_p = se7619___outl, + + .mv_insb = se7619___insb, + .mv_insw = se7619___insw, + .mv_insl = se7619___insl, + .mv_outsb = se7619___outsb, + .mv_outsw = se7619___outsw, + .mv_outsl = se7619___outsl, +}; +ALIAS_MV(se) diff --git a/arch/sh/boards/titan/setup.c b/arch/sh/boards/titan/setup.c index a6046d93758..6bcd939bfae 100644 --- a/arch/sh/boards/titan/setup.c +++ b/arch/sh/boards/titan/setup.c @@ -1,26 +1,30 @@ /* - * Setup for Titan + * arch/sh/boards/titan/setup.c - Setup for Titan + * + * Copyright (C) 2006 Jamie Lenehan + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. */ - #include <linux/init.h> -#include <asm/irq.h> +#include <linux/irq.h> #include <asm/titan.h> #include <asm/io.h> -extern void __init pcibios_init_platform(void); - static struct ipr_data titan_ipr_map[] = { - { TITAN_IRQ_WAN, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY }, - { TITAN_IRQ_LAN, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY }, - { TITAN_IRQ_MPCIA, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY }, - { TITAN_IRQ_USB, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY }, + /* IRQ, IPR idx, shift, prio */ + { TITAN_IRQ_WAN, 3, 12, 8 }, /* eth0 (WAN) */ + { TITAN_IRQ_LAN, 3, 8, 8 }, /* eth1 (LAN) */ + { TITAN_IRQ_MPCIA, 3, 4, 8 }, /* mPCI A (top) */ + { TITAN_IRQ_USB, 3, 0, 8 }, /* mPCI B (bottom), USB */ }; static void __init init_titan_irq(void) { /* enable individual interrupt mode for externals */ - ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); - + ipr_irq_enable_irlm(); + /* register ipr irqs */ make_ipr_irq(titan_ipr_map, ARRAY_SIZE(titan_ipr_map)); } @@ -47,6 +51,5 @@ struct sh_machine_vector mv_titan __initmv = { .mv_ioport_map = titan_ioport_map, .mv_init_irq = init_titan_irq, - .mv_init_pci = pcibios_init_platform, }; ALIAS_MV(titan) diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c index f2fed5ce5cc..35452d85b7f 100644 --- a/arch/sh/boot/compressed/misc.c +++ b/arch/sh/boot/compressed/misc.c @@ -12,6 +12,7 @@ */ #include <asm/uaccess.h> +#include <asm/addrspace.h> #ifdef CONFIG_SH_STANDARD_BIOS #include <asm/sh_bios.h> #endif @@ -228,7 +229,7 @@ long* stack_start = &user_stack[STACK_SIZE]; void decompress_kernel(void) { output_data = 0; - output_ptr = (unsigned long)&_text+0x20001000; + output_ptr = P2SEGADDR((unsigned long)&_text+0x1000); free_mem_ptr = (unsigned long)&_end; free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; diff --git a/arch/sh/configs/r7780rp_defconfig b/arch/sh/configs/r7780rp_defconfig index 34e2046c321..2b75b4896ba 100644 --- a/arch/sh/configs/r7780rp_defconfig +++ b/arch/sh/configs/r7780rp_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.19-rc3 -# Tue Oct 31 12:32:06 2006 +# Linux kernel version: 2.6.19 +# Wed Dec 6 11:59:38 2006 # CONFIG_SUPERH=y CONFIG_RWSEM_GENERIC_SPINLOCK=y @@ -11,6 +11,8 @@ CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_CALIBRATE_DELAY=y # CONFIG_GENERIC_TIME is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -37,6 +39,7 @@ CONFIG_BSD_PROCESS_ACCT=y # CONFIG_AUDIT is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +# CONFIG_SYSFS_DEPRECATED is not set # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y @@ -118,6 +121,8 @@ CONFIG_SH_R7780RP=y # CONFIG_SH_LANDISK is not set # CONFIG_SH_TITAN is not set # CONFIG_SH_SHMIN is not set +# CONFIG_SH_7206_SOLUTION_ENGINE is not set +# CONFIG_SH_7619_SOLUTION_ENGINE is not set # CONFIG_SH_UNKNOWN is not set # @@ -130,6 +135,12 @@ CONFIG_CPU_SH4A=y # SH-2 Processor Support # # CONFIG_CPU_SUBTYPE_SH7604 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set + +# +# SH-2A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7206 is not set # # SH-3 Processor Support @@ -165,6 +176,7 @@ CONFIG_CPU_SH4A=y # # CONFIG_CPU_SUBTYPE_SH7770 is not set CONFIG_CPU_SUBTYPE_SH7780=y +# CONFIG_CPU_SUBTYPE_SH7785 is not set # # SH4AL-DSP Processor Support @@ -181,8 +193,14 @@ CONFIG_MEMORY_START=0x08000000 CONFIG_MEMORY_SIZE=0x08000000 # CONFIG_32BIT is not set CONFIG_VSYSCALL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set CONFIG_HUGETLB_PAGE_SIZE_64K=y +# CONFIG_HUGETLB_PAGE_SIZE_256K is not set # CONFIG_HUGETLB_PAGE_SIZE_1MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -204,12 +222,14 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 # Processor features # CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set CONFIG_SH_FPU=y # CONFIG_SH_DSP is not set CONFIG_SH_STORE_QUEUES=y CONFIG_CPU_HAS_INTEVT=y CONFIG_CPU_HAS_INTC2_IRQ=y CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_PTEA=y # # Timer support @@ -220,6 +240,8 @@ CONFIG_SH_TMU=y # R7780RP options # CONFIG_SH_R7780MP=y +CONFIG_SH_TIMER_IRQ=28 +CONFIG_NO_IDLE_HZ=y CONFIG_SH_PCLK_FREQ=32000000 # @@ -238,13 +260,18 @@ CONFIG_SH_PCLK_FREQ=32000000 # CONFIG_HD6446X_SERIES is not set # +# Additional SuperH Device Drivers +# +CONFIG_PUSH_SWITCH=y + +# # Kernel features # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set CONFIG_HZ=250 -# CONFIG_KEXEC is not set +CONFIG_KEXEC=y # CONFIG_SMP is not set # CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_VOLUNTARY is not set @@ -278,10 +305,7 @@ CONFIG_PCI_AUTO_UPDATE_RESOURCES=y # # PCI Hotplug Support # -CONFIG_HOTPLUG_PCI=y -# CONFIG_HOTPLUG_PCI_FAKE is not set -# CONFIG_HOTPLUG_PCI_CPCI is not set -# CONFIG_HOTPLUG_PCI_SHPC is not set +# CONFIG_HOTPLUG_PCI is not set # # Executable file formats @@ -341,6 +365,7 @@ CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set # CONFIG_IPV6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set @@ -556,6 +581,7 @@ CONFIG_SATA_SIL=y # CONFIG_PATA_IT821X is not set # CONFIG_PATA_JMICRON is not set # CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set # CONFIG_PATA_MPIIX is not set # CONFIG_PATA_OLDPIIX is not set # CONFIG_PATA_NETCELL is not set @@ -572,6 +598,7 @@ CONFIG_SATA_SIL=y # CONFIG_PATA_SIS is not set # CONFIG_PATA_VIA is not set # CONFIG_PATA_WINBOND is not set +CONFIG_PATA_PLATFORM=y # # Multi-device support (RAID and LVM) @@ -688,6 +715,7 @@ CONFIG_R8169=y # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set # # Token Ring devices @@ -830,10 +858,6 @@ CONFIG_HW_RANDOM=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set @@ -1020,7 +1044,7 @@ CONFIG_INOTIFY_USER=y CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set -# CONFIG_FUSE_FS is not set +CONFIG_FUSE_FS=m # # CD-ROM/DVD Filesystems @@ -1052,7 +1076,7 @@ CONFIG_TMPFS=y CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y -# CONFIG_CONFIGFS_FS is not set +CONFIG_CONFIGFS_FS=m # # Miscellaneous filesystems @@ -1153,28 +1177,33 @@ CONFIG_NLS_ISO8859_1=y # # Profiling support # -# CONFIG_PROFILING is not set +CONFIG_PROFILING=y +CONFIG_OPROFILE=m # # Kernel hacking # -# CONFIG_PRINTK_TIME is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_PRINTK_TIME=y CONFIG_ENABLE_MUST_CHECK=y -# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set -CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_MUTEXES is not set # CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y CONFIG_DEBUG_FS=y # CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_LIST is not set @@ -1184,7 +1213,7 @@ CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_SH_STANDARD_BIOS is not set # CONFIG_EARLY_SCIF_CONSOLE is not set -# CONFIG_DEBUG_STACKOVERFLOW is not set +CONFIG_DEBUG_STACKOVERFLOW=y # CONFIG_DEBUG_STACK_USAGE is not set # CONFIG_4KSTACKS is not set # CONFIG_KGDB is not set diff --git a/arch/sh/configs/se7206_defconfig b/arch/sh/configs/se7206_defconfig new file mode 100644 index 00000000000..36cec0b6e7c --- /dev/null +++ b/arch/sh/configs/se7206_defconfig @@ -0,0 +1,826 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.19-rc4 +# Sun Nov 5 16:20:10 2006 +# +CONFIG_SUPERH=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SYSVIPC is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" + +# +# System type +# +# CONFIG_SH_SOLUTION_ENGINE is not set +# CONFIG_SH_7751_SOLUTION_ENGINE is not set +# CONFIG_SH_7300_SOLUTION_ENGINE is not set +# CONFIG_SH_7343_SOLUTION_ENGINE is not set +# CONFIG_SH_73180_SOLUTION_ENGINE is not set +# CONFIG_SH_7751_SYSTEMH is not set +# CONFIG_SH_HP6XX is not set +# CONFIG_SH_EC3104 is not set +# CONFIG_SH_SATURN is not set +# CONFIG_SH_DREAMCAST is not set +# CONFIG_SH_BIGSUR is not set +# CONFIG_SH_MPC1211 is not set +# CONFIG_SH_SH03 is not set +# CONFIG_SH_SECUREEDGE5410 is not set +# CONFIG_SH_HS7751RVOIP is not set +# CONFIG_SH_7710VOIPGW is not set +# CONFIG_SH_RTS7751R2D is not set +# CONFIG_SH_R7780RP is not set +# CONFIG_SH_EDOSK7705 is not set +# CONFIG_SH_SH4202_MICRODEV is not set +# CONFIG_SH_LANDISK is not set +# CONFIG_SH_TITAN is not set +# CONFIG_SH_SHMIN is not set +CONFIG_SH_7206_SOLUTION_ENGINE=y +# CONFIG_SH_7619_SOLUTION_ENGINE is not set +# CONFIG_SH_UNKNOWN is not set + +# +# Processor selection +# +CONFIG_CPU_SH2=y +CONFIG_CPU_SH2A=y + +# +# SH-2 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7604 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set + +# +# SH-2A Processor Support +# +CONFIG_CPU_SUBTYPE_SH7206=y + +# +# SH-3 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7300 is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set + +# +# SH-4 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +# CONFIG_CPU_SUBTYPE_SH7751R is not set +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set + +# +# ST40 Processor Support +# +# CONFIG_CPU_SUBTYPE_ST40STB1 is not set +# CONFIG_CPU_SUBTYPE_ST40GX1 is not set + +# +# SH-4A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set + +# +# SH4AL-DSP Processor Support +# +# CONFIG_CPU_SUBTYPE_SH73180 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set + +# +# Memory management options +# +CONFIG_PAGE_OFFSET=0x00000000 +CONFIG_MEMORY_START=0x0c000000 +CONFIG_MEMORY_SIZE=0x02000000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set + +# +# Cache configuration +# +# CONFIG_SH_DIRECT_MAPPED is not set +# CONFIG_SH_WRITETHROUGH is not set +# CONFIG_SH_OCRAM is not set + +# +# Processor features +# +# CONFIG_CPU_LITTLE_ENDIAN is not set +# CONFIG_SH_FPU is not set +# CONFIG_SH_FPU_EMU is not set +# CONFIG_SH_DSP is not set + +# +# Timer support +# +CONFIG_SH_CMT=y +# CONFIG_SH_MTU2 is not set +CONFIG_SH_PCLK_FREQ=33333333 +CONFIG_SH_CLK_MD=6 + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# +# CONFIG_SH_DMA is not set + +# +# Companion Chips +# +# CONFIG_HD6446X_SERIES is not set + +# +# Kernel features +# +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +# CONFIG_KEXEC is not set +# CONFIG_SMP is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +# CONFIG_UBC_WAKEUP is not set +# CONFIG_CMDLINE_BOOL is not set + +# +# Bus options +# +# CONFIG_PCI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options (EXPERIMENTAL) +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +# CONFIG_PACKET is not set +# CONFIG_UNIX is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0x20000000 +CONFIG_MTD_PHYSMAP_LEN=0x1000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=4 +# CONFIG_MTD_SOLUTIONENGINE is not set +# CONFIG_MTD_UCLINUX is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +# CONFIG_NETDEVICES is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=4 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +# CONFIG_SYSFS is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_SH_STANDARD_BIOS is not set +# CONFIG_EARLY_SCIF_CONSOLE is not set +# CONFIG_KGDB is not set + +# +# Security options +# +# CONFIG_KEYS is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y diff --git a/arch/sh/drivers/Kconfig b/arch/sh/drivers/Kconfig new file mode 100644 index 00000000000..c54c758e624 --- /dev/null +++ b/arch/sh/drivers/Kconfig @@ -0,0 +1,9 @@ +menu "Additional SuperH Device Drivers" + +config PUSH_SWITCH + tristate "Push switch support" + help + This enables support for the push switch framework, a simple + framework that allows for sysfs driven switch status reporting. + +endmenu diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile index 338c3729d27..bf18dbfb678 100644 --- a/arch/sh/drivers/Makefile +++ b/arch/sh/drivers/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_SH_DMA) += dma/ obj-$(CONFIG_SUPERHYWAY) += superhyway/ - +obj-$(CONFIG_PUSH_SWITCH) += push-switch.o diff --git a/arch/sh/drivers/dma/Makefile b/arch/sh/drivers/dma/Makefile index 065d4c90970..db1295d3226 100644 --- a/arch/sh/drivers/dma/Makefile +++ b/arch/sh/drivers/dma/Makefile @@ -2,8 +2,8 @@ # Makefile for the SuperH DMA specific kernel interface routines under Linux. # -obj-y += dma-api.o dma-isa.o +obj-y += dma-api.o +obj-$(CONFIG_ISA_DMA_API) += dma-isa.o obj-$(CONFIG_SYSFS) += dma-sysfs.o obj-$(CONFIG_SH_DMA) += dma-sh.o obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o - diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c index 47c3e837599..e062067edd2 100644 --- a/arch/sh/drivers/dma/dma-api.c +++ b/arch/sh/drivers/dma/dma-api.c @@ -11,61 +11,27 @@ */ #include <linux/init.h> #include <linux/module.h> -#include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/proc_fs.h> #include <linux/list.h> #include <linux/platform_device.h> +#include <linux/mm.h> #include <asm/dma.h> DEFINE_SPINLOCK(dma_spin_lock); static LIST_HEAD(registered_dmac_list); -/* - * A brief note about the reasons for this API as it stands. - * - * For starters, the old ISA DMA API didn't work for us for a number of - * reasons, for one, the vast majority of channels on the SH DMAC are - * dual-address mode only, and both the new and the old DMA APIs are after the - * concept of managing a DMA buffer, which doesn't overly fit this model very - * well. In addition to which, the new API is largely geared at IOMMUs and - * GARTs, and doesn't even support the channel notion very well. - * - * The other thing that's a marginal issue, is the sheer number of random DMA - * engines that are present (ie, in boards like the Dreamcast), some of which - * cascade off of the SH DMAC, and others do not. As such, there was a real - * need for a scalable subsystem that could deal with both single and - * dual-address mode usage, in addition to interoperating with cascaded DMACs. - * - * There really isn't any reason why this needs to be SH specific, though I'm - * not aware of too many other processors (with the exception of some MIPS) - * that have the same concept of a dual address mode, or any real desire to - * actually make use of the DMAC even if such a subsystem were exposed - * elsewhere. - * - * The idea for this was derived from the ARM port, which acted as an excellent - * reference when trying to address these issues. - * - * It should also be noted that the decision to add Yet Another DMA API(tm) to - * the kernel wasn't made easily, and was only decided upon after conferring - * with jejb with regards to the state of the old and new APIs as they applied - * to these circumstances. Philip Blundell was also a great help in figuring - * out some single-address mode DMA semantics that were otherwise rather - * confusing. - */ - struct dma_info *get_dma_info(unsigned int chan) { struct dma_info *info; - unsigned int total = 0; /* * Look for each DMAC's range to determine who the owner of * the channel is. */ list_for_each_entry(info, ®istered_dmac_list, list) { - total += info->nr_channels; - if (chan > total) + if ((chan < info->first_channel_nr) || + (chan >= info->first_channel_nr + info->nr_channels)) continue; return info; @@ -73,6 +39,22 @@ struct dma_info *get_dma_info(unsigned int chan) return NULL; } +EXPORT_SYMBOL(get_dma_info); + +struct dma_info *get_dma_info_by_name(const char *dmac_name) +{ + struct dma_info *info; + + list_for_each_entry(info, ®istered_dmac_list, list) { + if (dmac_name && (strcmp(dmac_name, info->name) != 0)) + continue; + else + return info; + } + + return NULL; +} +EXPORT_SYMBOL(get_dma_info_by_name); static unsigned int get_nr_channels(void) { @@ -91,63 +73,161 @@ static unsigned int get_nr_channels(void) struct dma_channel *get_dma_channel(unsigned int chan) { struct dma_info *info = get_dma_info(chan); + struct dma_channel *channel; + int i; - if (!info) + if (unlikely(!info)) return ERR_PTR(-EINVAL); - return info->channels + chan; + for (i = 0; i < info->nr_channels; i++) { + channel = &info->channels[i]; + if (channel->chan == chan) + return channel; + } + + return NULL; } +EXPORT_SYMBOL(get_dma_channel); int get_dma_residue(unsigned int chan) { struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; + struct dma_channel *channel = get_dma_channel(chan); if (info->ops->get_residue) return info->ops->get_residue(channel); return 0; } +EXPORT_SYMBOL(get_dma_residue); -int request_dma(unsigned int chan, const char *dev_id) +static int search_cap(const char **haystack, const char *needle) { - struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; + const char **p; + + for (p = haystack; *p; p++) + if (strcmp(*p, needle) == 0) + return 1; + + return 0; +} + +/** + * request_dma_bycap - Allocate a DMA channel based on its capabilities + * @dmac: List of DMA controllers to search + * @caps: List of capabilites + * + * Search all channels of all DMA controllers to find a channel which + * matches the requested capabilities. The result is the channel + * number if a match is found, or %-ENODEV if no match is found. + * + * Note that not all DMA controllers export capabilities, in which + * case they can never be allocated using this API, and so + * request_dma() must be used specifying the channel number. + */ +int request_dma_bycap(const char **dmac, const char **caps, const char *dev_id) +{ + unsigned int found = 0; + struct dma_info *info; + const char **p; + int i; + + BUG_ON(!dmac || !caps); + + list_for_each_entry(info, ®istered_dmac_list, list) + if (strcmp(*dmac, info->name) == 0) { + found = 1; + break; + } + + if (!found) + return -ENODEV; + + for (i = 0; i < info->nr_channels; i++) { + struct dma_channel *channel = &info->channels[i]; + + if (unlikely(!channel->caps)) + continue; + + for (p = caps; *p; p++) { + if (!search_cap(channel->caps, *p)) + break; + if (request_dma(channel->chan, dev_id) == 0) + return channel->chan; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL(request_dma_bycap); + +int dmac_search_free_channel(const char *dev_id) +{ + struct dma_channel *channel = { 0 }; + struct dma_info *info = get_dma_info(0); + int i; + + for (i = 0; i < info->nr_channels; i++) { + channel = &info->channels[i]; + if (unlikely(!channel)) + return -ENODEV; + + if (atomic_read(&channel->busy) == 0) + break; + } - down(&channel->sem); + if (info->ops->request) { + int result = info->ops->request(channel); + if (result) + return result; - if (!info->ops || chan >= MAX_DMA_CHANNELS) { - up(&channel->sem); - return -EINVAL; + atomic_set(&channel->busy, 1); + return channel->chan; } - atomic_set(&channel->busy, 1); + return -ENOSYS; +} + +int request_dma(unsigned int chan, const char *dev_id) +{ + struct dma_channel *channel = { 0 }; + struct dma_info *info = get_dma_info(chan); + int result; + + channel = get_dma_channel(chan); + if (atomic_xchg(&channel->busy, 1)) + return -EBUSY; strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id)); - up(&channel->sem); + if (info->ops->request) { + result = info->ops->request(channel); + if (result) + atomic_set(&channel->busy, 0); - if (info->ops->request) - return info->ops->request(channel); + return result; + } return 0; } +EXPORT_SYMBOL(request_dma); void free_dma(unsigned int chan) { struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; + struct dma_channel *channel = get_dma_channel(chan); if (info->ops->free) info->ops->free(channel); atomic_set(&channel->busy, 0); } +EXPORT_SYMBOL(free_dma); void dma_wait_for_completion(unsigned int chan) { struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; + struct dma_channel *channel = get_dma_channel(chan); if (channel->flags & DMA_TEI_CAPABLE) { wait_event(channel->wait_queue, @@ -158,21 +238,52 @@ void dma_wait_for_completion(unsigned int chan) while (info->ops->get_residue(channel)) cpu_relax(); } +EXPORT_SYMBOL(dma_wait_for_completion); + +int register_chan_caps(const char *dmac, struct dma_chan_caps *caps) +{ + struct dma_info *info; + unsigned int found = 0; + int i; + + list_for_each_entry(info, ®istered_dmac_list, list) + if (strcmp(dmac, info->name) == 0) { + found = 1; + break; + } + + if (unlikely(!found)) + return -ENODEV; + + for (i = 0; i < info->nr_channels; i++, caps++) { + struct dma_channel *channel; + + if ((info->first_channel_nr + i) != caps->ch_num) + return -EINVAL; + + channel = &info->channels[i]; + channel->caps = caps->caplist; + } + + return 0; +} +EXPORT_SYMBOL(register_chan_caps); void dma_configure_channel(unsigned int chan, unsigned long flags) { struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; + struct dma_channel *channel = get_dma_channel(chan); if (info->ops->configure) info->ops->configure(channel, flags); } +EXPORT_SYMBOL(dma_configure_channel); int dma_xfer(unsigned int chan, unsigned long from, unsigned long to, size_t size, unsigned int mode) { struct dma_info *info = get_dma_info(chan); - struct dma_channel *channel = &info->channels[chan]; + struct dma_channel *channel = get_dma_channel(chan); channel->sar = from; channel->dar = to; @@ -181,8 +292,20 @@ int dma_xfer(unsigned int chan, unsigned long from, return info->ops->xfer(channel); } +EXPORT_SYMBOL(dma_xfer); + +int dma_extend(unsigned int chan, unsigned long op, void *param) +{ + struct dma_info *info = get_dma_info(chan); + struct dma_channel *channel = get_dma_channel(chan); + + if (info->ops->extend) + return info->ops->extend(channel, op, param); + + return -ENOSYS; +} +EXPORT_SYMBOL(dma_extend); -#ifdef CONFIG_PROC_FS static int dma_read_proc(char *buf, char **start, off_t off, int len, int *eof, void *data) { @@ -214,8 +337,6 @@ static int dma_read_proc(char *buf, char **start, off_t off, return p - buf; } -#endif - int register_dmac(struct dma_info *info) { @@ -224,8 +345,7 @@ int register_dmac(struct dma_info *info) INIT_LIST_HEAD(&info->list); printk(KERN_INFO "DMA: Registering %s handler (%d channel%s).\n", - info->name, info->nr_channels, - info->nr_channels > 1 ? "s" : ""); + info->name, info->nr_channels, info->nr_channels > 1 ? "s" : ""); BUG_ON((info->flags & DMAC_CHANNELS_CONFIGURED) && !info->channels); @@ -242,28 +362,26 @@ int register_dmac(struct dma_info *info) size = sizeof(struct dma_channel) * info->nr_channels; - info->channels = kmalloc(size, GFP_KERNEL); + info->channels = kzalloc(size, GFP_KERNEL); if (!info->channels) return -ENOMEM; - - memset(info->channels, 0, size); } total_channels = get_nr_channels(); for (i = 0; i < info->nr_channels; i++) { - struct dma_channel *chan = info->channels + i; + struct dma_channel *chan = &info->channels[i]; + + atomic_set(&chan->busy, 0); - chan->chan = i; - chan->vchan = i + total_channels; + chan->chan = info->first_channel_nr + i; + chan->vchan = info->first_channel_nr + i + total_channels; memcpy(chan->dev_id, "Unused", 7); if (info->flags & DMAC_CHANNELS_TEI_CAPABLE) chan->flags |= DMA_TEI_CAPABLE; - init_MUTEX(&chan->sem); init_waitqueue_head(&chan->wait_queue); - dma_create_sysfs_files(chan, info); } @@ -271,6 +389,7 @@ int register_dmac(struct dma_info *info) return 0; } +EXPORT_SYMBOL(register_dmac); void unregister_dmac(struct dma_info *info) { @@ -285,31 +404,16 @@ void unregister_dmac(struct dma_info *info) list_del(&info->list); platform_device_unregister(info->pdev); } +EXPORT_SYMBOL(unregister_dmac); static int __init dma_api_init(void) { - printk("DMA: Registering DMA API.\n"); - -#ifdef CONFIG_PROC_FS + printk(KERN_NOTICE "DMA: Registering DMA API.\n"); create_proc_read_entry("dma", 0, 0, dma_read_proc, 0); -#endif - return 0; } - subsys_initcall(dma_api_init); MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); MODULE_DESCRIPTION("DMA API for SuperH"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(request_dma); -EXPORT_SYMBOL(free_dma); -EXPORT_SYMBOL(register_dmac); -EXPORT_SYMBOL(get_dma_residue); -EXPORT_SYMBOL(get_dma_info); -EXPORT_SYMBOL(get_dma_channel); -EXPORT_SYMBOL(dma_xfer); -EXPORT_SYMBOL(dma_wait_for_completion); -EXPORT_SYMBOL(dma_configure_channel); - diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c index 66078601335..f63721ed86c 100644 --- a/arch/sh/drivers/dma/dma-sh.c +++ b/arch/sh/drivers/dma/dma-sh.c @@ -94,20 +94,13 @@ static int sh_dmac_request_dma(struct dma_channel *chan) if (unlikely(!chan->flags & DMA_TEI_CAPABLE)) return 0; - chan->name = kzalloc(32, GFP_KERNEL); - if (unlikely(chan->name == NULL)) - return -ENOMEM; - snprintf(chan->name, 32, "DMAC Transfer End (Channel %d)", - chan->chan); - return request_irq(get_dmte_irq(chan->chan), dma_tei, - IRQF_DISABLED, chan->name, chan); + IRQF_DISABLED, chan->dev_id, chan); } static void sh_dmac_free_dma(struct dma_channel *chan) { free_irq(get_dmte_irq(chan->chan), chan); - kfree(chan->name); } static void diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c index 29b8ef9873d..eebcd4768bb 100644 --- a/arch/sh/drivers/dma/dma-sysfs.c +++ b/arch/sh/drivers/dma/dma-sysfs.c @@ -3,7 +3,7 @@ * * sysfs interface for SH DMA API * - * Copyright (C) 2004, 2005 Paul Mundt + * Copyright (C) 2004 - 2006 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -21,7 +21,6 @@ static struct sysdev_class dma_sysclass = { set_kset_name("dma"), }; - EXPORT_SYMBOL(dma_sysclass); static ssize_t dma_show_devices(struct sys_device *dev, char *buf) @@ -31,7 +30,10 @@ static ssize_t dma_show_devices(struct sys_device *dev, char *buf) for (i = 0; i < MAX_DMA_CHANNELS; i++) { struct dma_info *info = get_dma_info(i); - struct dma_channel *channel = &info->channels[i]; + struct dma_channel *channel = get_dma_channel(i); + + if (unlikely(!info) || !channel) + continue; len += sprintf(buf + len, "%2d: %14s %s\n", channel->chan, info->name, @@ -125,11 +127,16 @@ int dma_create_sysfs_files(struct dma_channel *chan, struct dma_info *info) if (ret) return ret; - sysdev_create_file(dev, &attr_dev_id); - sysdev_create_file(dev, &attr_count); - sysdev_create_file(dev, &attr_mode); - sysdev_create_file(dev, &attr_flags); - sysdev_create_file(dev, &attr_config); + ret |= sysdev_create_file(dev, &attr_dev_id); + ret |= sysdev_create_file(dev, &attr_count); + ret |= sysdev_create_file(dev, &attr_mode); + ret |= sysdev_create_file(dev, &attr_flags); + ret |= sysdev_create_file(dev, &attr_config); + + if (unlikely(ret)) { + dev_err(&info->pdev->dev, "Failed creating attrs\n"); + return ret; + } snprintf(name, sizeof(name), "dma%d", chan->chan); return sysfs_create_link(&info->pdev->dev.kobj, &dev->kobj, name); diff --git a/arch/sh/drivers/pci/ops-titan.c b/arch/sh/drivers/pci/ops-titan.c index cd56d53375e..ac8ee2312cd 100644 --- a/arch/sh/drivers/pci/ops-titan.c +++ b/arch/sh/drivers/pci/ops-titan.c @@ -15,25 +15,21 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/pci.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/titan.h> #include "pci-sh4.h" +static char titan_irq_tab[] __initdata = { + TITAN_IRQ_WAN, + TITAN_IRQ_LAN, + TITAN_IRQ_MPCIA, + TITAN_IRQ_MPCIB, + TITAN_IRQ_USB, +}; + int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) { - int irq = -1; - - switch (slot) { - case 0: irq = TITAN_IRQ_WAN; break; /* eth0 (WAN) */ - case 1: irq = TITAN_IRQ_LAN; break; /* eth1 (LAN) */ - case 2: irq = TITAN_IRQ_MPCIA; break; /* mPCI A */ - case 3: irq = TITAN_IRQ_MPCIB; break; /* mPCI B */ - case 4: irq = TITAN_IRQ_USB; break; /* USB */ - default: - printk(KERN_INFO "PCI: Bad IRQ mapping " - "request for slot %d\n", slot); - return -1; - } + int irq = titan_irq_tab[slot]; printk("PCI: Mapping TITAN IRQ for slot %d, pin %c to irq %d\n", slot, pin - 1 + 'A', irq); diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index d6e63529653..602b644c35a 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -22,6 +22,20 @@ #include <linux/delay.h> #include "pci-sh4.h" +#define INTC_BASE 0xffd00000 +#define INTC_ICR0 (INTC_BASE+0x0) +#define INTC_ICR1 (INTC_BASE+0x1c) +#define INTC_INTPRI (INTC_BASE+0x10) +#define INTC_INTREQ (INTC_BASE+0x24) +#define INTC_INTMSK0 (INTC_BASE+0x44) +#define INTC_INTMSK1 (INTC_BASE+0x48) +#define INTC_INTMSK2 (INTC_BASE+0x40080) +#define INTC_INTMSKCLR0 (INTC_BASE+0x64) +#define INTC_INTMSKCLR1 (INTC_BASE+0x68) +#define INTC_INTMSKCLR2 (INTC_BASE+0x40084) +#define INTC_INT2MSKR (INTC_BASE+0x40038) +#define INTC_INT2MSKCR (INTC_BASE+0x4003c) + /* * Initialization. Try all known PCI access methods. Note that we support * using both PCI BIOS and direct access: in such cases, we use I/O ports diff --git a/arch/sh/drivers/push-switch.c b/arch/sh/drivers/push-switch.c new file mode 100644 index 00000000000..f2b9157c314 --- /dev/null +++ b/arch/sh/drivers/push-switch.c @@ -0,0 +1,138 @@ +/* + * Generic push-switch framework + * + * Copyright (C) 2006 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <asm/push-switch.h> + +#define DRV_NAME "push-switch" +#define DRV_VERSION "0.1.0" + +static ssize_t switch_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct push_switch_platform_info *psw_info = dev->platform_data; + return sprintf(buf, "%s\n", psw_info->name); +} +static DEVICE_ATTR(switch, S_IRUGO, switch_show, NULL); + +static void switch_timer(unsigned long data) +{ + struct push_switch *psw = (struct push_switch *)data; + + schedule_work(&psw->work); +} + +static void switch_work_handler(void *data) +{ + struct platform_device *pdev = data; + struct push_switch *psw = platform_get_drvdata(pdev); + + psw->state = 0; + + kobject_uevent(&pdev->dev.kobj, KOBJ_CHANGE); +} + +static int switch_drv_probe(struct platform_device *pdev) +{ + struct push_switch_platform_info *psw_info; + struct push_switch *psw; + int ret, irq; + + psw = kzalloc(sizeof(struct push_switch), GFP_KERNEL); + if (unlikely(!psw)) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (unlikely(irq < 0)) { + ret = -ENODEV; + goto err; + } + + psw_info = pdev->dev.platform_data; + BUG_ON(!psw_info); + + ret = request_irq(irq, psw_info->irq_handler, + IRQF_DISABLED | psw_info->irq_flags, + psw_info->name ? psw_info->name : DRV_NAME, pdev); + if (unlikely(ret < 0)) + goto err; + + if (psw_info->name) { + ret = device_create_file(&pdev->dev, &dev_attr_switch); + if (unlikely(ret)) { + dev_err(&pdev->dev, "Failed creating device attrs\n"); + ret = -EINVAL; + goto err_irq; + } + } + + INIT_WORK(&psw->work, switch_work_handler, pdev); + init_timer(&psw->debounce); + + psw->debounce.function = switch_timer; + psw->debounce.data = (unsigned long)psw; + + platform_set_drvdata(pdev, psw); + + return 0; + +err_irq: + free_irq(irq, pdev); +err: + kfree(psw); + return ret; +} + +static int switch_drv_remove(struct platform_device *pdev) +{ + struct push_switch *psw = platform_get_drvdata(pdev); + struct push_switch_platform_info *psw_info = pdev->dev.platform_data; + int irq = platform_get_irq(pdev, 0); + + if (psw_info->name) + device_remove_file(&pdev->dev, &dev_attr_switch); + + platform_set_drvdata(pdev, NULL); + flush_scheduled_work(); + del_timer_sync(&psw->debounce); + free_irq(irq, pdev); + + kfree(psw); + + return 0; +} + +static struct platform_driver switch_driver = { + .probe = switch_drv_probe, + .remove = switch_drv_remove, + .driver = { + .name = DRV_NAME, + }, +}; + +static int __init switch_init(void) +{ + printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION); + return platform_driver_register(&switch_driver); +} + +static void __exit switch_exit(void) +{ + platform_driver_unregister(&switch_driver); +} +module_init(switch_init); +module_exit(switch_exit); + +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR("Paul Mundt"); +MODULE_LICENSE("GPLv2"); diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 5da88a43d35..99c7e5249f7 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o init_task.o vmlinux.lds -obj-y := process.o signal.o entry.o traps.o irq.o \ +obj-y := process.o signal.o traps.o irq.o \ ptrace.o setup.o time.o sys_sh.o semaphore.o \ io.o io_generic.o sh_ksyms.o syscalls.o @@ -21,3 +21,4 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile index fb5dac06938..0582e6712b7 100644 --- a/arch/sh/kernel/cpu/Makefile +++ b/arch/sh/kernel/cpu/Makefile @@ -2,11 +2,12 @@ # Makefile for the Linux/SuperH CPU-specifc backends. # -obj-y += irq/ init.o clock.o - -obj-$(CONFIG_CPU_SH2) += sh2/ -obj-$(CONFIG_CPU_SH3) += sh3/ -obj-$(CONFIG_CPU_SH4) += sh4/ +obj-$(CONFIG_CPU_SH2) = sh2/ +obj-$(CONFIG_CPU_SH2A) = sh2a/ +obj-$(CONFIG_CPU_SH3) = sh3/ +obj-$(CONFIG_CPU_SH4) = sh4/ obj-$(CONFIG_UBC_WAKEUP) += ubc.o obj-$(CONFIG_SH_ADC) += adc.o + +obj-y += irq/ init.o clock.o diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 51ec64cdf34..abb586b1256 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -5,9 +5,11 @@ * * This clock framework is derived from the OMAP version by: * - * Copyright (C) 2004 Nokia Corporation + * Copyright (C) 2004 - 2005 Nokia Corporation * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> * + * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -20,6 +22,7 @@ #include <linux/kref.h> #include <linux/seq_file.h> #include <linux/err.h> +#include <linux/platform_device.h> #include <asm/clock.h> #include <asm/timer.h> @@ -195,17 +198,37 @@ void clk_recalc_rate(struct clk *clk) propagate_rate(clk); } -struct clk *clk_get(const char *id) +/* + * Returns a clock. Note that we first try to use device id on the bus + * and clock name. If this fails, we try to use clock name only. + */ +struct clk *clk_get(struct device *dev, const char *id) { struct clk *p, *clk = ERR_PTR(-ENOENT); + int idno; + + if (dev == NULL || dev->bus != &platform_bus_type) + idno = -1; + else + idno = to_platform_device(dev)->id; mutex_lock(&clock_list_sem); list_for_each_entry(p, &clock_list, node) { + if (p->id == idno && + strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + clk = p; + goto found; + } + } + + list_for_each_entry(p, &clock_list, node) { if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { clk = p; break; } } + +found: mutex_unlock(&clock_list_sem); return clk; diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index bfb90eb0b7a..48121766e8d 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -68,12 +68,14 @@ static void __init cache_init(void) waysize = cpu_data->dcache.sets; +#ifdef CCR_CACHE_ORA /* * If the OC is already in RAM mode, we only have * half of the entries to flush.. */ if (ccr & CCR_CACHE_ORA) waysize >>= 1; +#endif waysize <<= cpu_data->dcache.entry_shift; diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile index 1c034c283f5..0049d217561 100644 --- a/arch/sh/kernel/cpu/irq/Makefile +++ b/arch/sh/kernel/cpu/irq/Makefile @@ -1,8 +1,9 @@ # # Makefile for the Linux/SuperH CPU-specifc IRQ handlers. # -obj-y += ipr.o imask.o +obj-y += imask.o +obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o diff --git a/arch/sh/kernel/cpu/irq/imask.c b/arch/sh/kernel/cpu/irq/imask.c index a33ae3e0a5a..301b505c427 100644 --- a/arch/sh/kernel/cpu/irq/imask.c +++ b/arch/sh/kernel/cpu/irq/imask.c @@ -53,7 +53,10 @@ void static inline set_interrupt_registers(int ip) { unsigned long __dummy; - asm volatile("ldc %2, r6_bank\n\t" + asm volatile( +#ifdef CONFIG_CPU_HAS_SR_RB + "ldc %2, r6_bank\n\t" +#endif "stc sr, %0\n\t" "and #0xf0, %0\n\t" "shlr2 %0\n\t" diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c index 74ca576a7ce..74defe76a05 100644 --- a/arch/sh/kernel/cpu/irq/intc2.c +++ b/arch/sh/kernel/cpu/irq/intc2.c @@ -11,22 +11,29 @@ * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780. */ #include <linux/kernel.h> -#include <linux/irq.h> +#include <linux/interrupt.h> #include <linux/io.h> -#include <asm/system.h> + +#if defined(CONFIG_CPU_SUBTYPE_SH7760) +#define INTC2_BASE 0xfe080000 +#define INTC2_INTMSK (INTC2_BASE + 0x40) +#define INTC2_INTMSKCLR (INTC2_BASE + 0x60) +#elif defined(CONFIG_CPU_SUBTYPE_SH7780) +#define INTC2_BASE 0xffd40000 +#define INTC2_INTMSK (INTC2_BASE + 0x38) +#define INTC2_INTMSKCLR (INTC2_BASE + 0x3c) +#endif static void disable_intc2_irq(unsigned int irq) { struct intc2_data *p = get_irq_chip_data(irq); - ctrl_outl(1 << p->msk_shift, - INTC2_BASE + INTC2_INTMSK_OFFSET + p->msk_offset); + ctrl_outl(1 << p->msk_shift, INTC2_INTMSK + p->msk_offset); } static void enable_intc2_irq(unsigned int irq) { struct intc2_data *p = get_irq_chip_data(irq); - ctrl_outl(1 << p->msk_shift, - INTC2_BASE + INTC2_INTMSKCLR_OFFSET + p->msk_offset); + ctrl_outl(1 << p->msk_shift, INTC2_INTMSKCLR + p->msk_offset); } static struct irq_chip intc2_irq_chip = { @@ -61,12 +68,10 @@ void make_intc2_irq(struct intc2_data *table, unsigned int nr_irqs) /* Set the priority level */ local_irq_save(flags); - ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + - p->ipr_offset); + ipr = ctrl_inl(INTC2_BASE + p->ipr_offset); ipr &= ~(0xf << p->ipr_shift); ipr |= p->priority << p->ipr_shift; - ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + - p->ipr_offset); + ctrl_outl(ipr, INTC2_BASE + p->ipr_offset); local_irq_restore(flags); diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c index a0089563cbf..35eb5751a3a 100644 --- a/arch/sh/kernel/cpu/irq/ipr.c +++ b/arch/sh/kernel/cpu/irq/ipr.c @@ -19,25 +19,21 @@ #include <linux/init.h> #include <linux/irq.h> #include <linux/module.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/machvec.h> - +#include <linux/io.h> +#include <linux/interrupt.h> static void disable_ipr_irq(unsigned int irq) { struct ipr_data *p = get_irq_chip_data(irq); - int shift = p->shift*4; /* Set the priority in IPR to 0 */ - ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << shift)), p->addr); + ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << p->shift)), p->addr); } static void enable_ipr_irq(unsigned int irq) { struct ipr_data *p = get_irq_chip_data(irq); - int shift = p->shift*4; /* Set priority in IPR back to original value */ - ctrl_outw(ctrl_inw(p->addr) | (p->priority << shift), p->addr); + ctrl_outw(ctrl_inw(p->addr) | (p->priority << p->shift), p->addr); } static struct irq_chip ipr_irq_chip = { @@ -53,6 +49,10 @@ void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs) for (i = 0; i < nr_irqs; i++) { unsigned int irq = table[i].irq; + table[i].addr = map_ipridx_to_addr(table[i].ipr_idx); + /* could the IPR index be mapped, if not we ignore this */ + if (table[i].addr == 0) + continue; disable_irq_nosync(irq); set_irq_chip_and_handler_name(irq, &ipr_irq_chip, handle_level_irq, "level"); @@ -62,83 +62,6 @@ void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs) } EXPORT_SYMBOL(make_ipr_irq); -static struct ipr_data sys_ipr_map[] = { -#ifndef CONFIG_CPU_SUBTYPE_SH7780 - { TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY }, - { TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY }, -#ifdef RTC_IRQ - { RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY }, -#endif -#ifdef SCI_ERI_IRQ - { SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY }, - { SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY }, - { SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY }, -#endif -#ifdef SCIF1_ERI_IRQ - { SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, - { SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, - { SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, - { SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, -#endif -#if defined(CONFIG_CPU_SUBTYPE_SH7300) - { SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY }, - { DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY }, - { DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY }, - { VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY }, -#endif -#ifdef SCIF_ERI_IRQ - { SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, - { SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, - { SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, - { SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, -#endif -#ifdef IRDA_ERI_IRQ - { IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, - { IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, - { IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, - { IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, -#endif -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ - defined(CONFIG_CPU_SUBTYPE_SH7706) || \ - defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) - /* - * Initialize the Interrupt Controller (INTC) - * registers to their power on values - */ - - /* - * Enable external irq (INTC IRQ mode). - * You should set corresponding bits of PFC to "00" - * to enable these interrupts. - */ - { IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY }, - { IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY }, - { IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY }, - { IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY }, - { IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY }, - { IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY }, -#endif -#endif -}; - -void __init init_IRQ(void) -{ - make_ipr_irq(sys_ipr_map, ARRAY_SIZE(sys_ipr_map)); - -#ifdef CONFIG_CPU_HAS_PINT_IRQ - init_IRQ_pint(); -#endif - -#ifdef CONFIG_CPU_HAS_INTC2_IRQ - init_IRQ_intc2(); -#endif - /* Perform the machine specific initialisation */ - if (sh_mv.mv_init_irq != NULL) - sh_mv.mv_init_irq(); - - irq_ctx_init(smp_processor_id()); -} - #if !defined(CONFIG_CPU_HAS_PINT_IRQ) int ipr_irq_demux(int irq) { diff --git a/arch/sh/kernel/cpu/sh2/Makefile b/arch/sh/kernel/cpu/sh2/Makefile index 389353fba60..f0f059acfcf 100644 --- a/arch/sh/kernel/cpu/sh2/Makefile +++ b/arch/sh/kernel/cpu/sh2/Makefile @@ -2,5 +2,6 @@ # Makefile for the Linux/SuperH SH-2 backends. # -obj-y := probe.o +obj-y := ex.o probe.o entry.o +obj-$(CONFIG_CPU_SUBTYPE_SH7619) += setup-sh7619.o clock-sh7619.o diff --git a/arch/sh/kernel/cpu/sh2/clock-sh7619.c b/arch/sh/kernel/cpu/sh2/clock-sh7619.c new file mode 100644 index 00000000000..d0440b26970 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/clock-sh7619.c @@ -0,0 +1,81 @@ +/* + * arch/sh/kernel/cpu/sh2/clock-sh7619.c + * + * SH7619 support for the clock framework + * + * Copyright (C) 2006 Yoshinori Sato + * + * Based on clock-sh4.c + * Copyright (C) 2005 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <asm/clock.h> +#include <asm/freq.h> +#include <asm/io.h> + +const static int pll1rate[]={1,2}; +const static int pfc_divisors[]={1,2,0,4}; + +#if (CONFIG_SH_CLK_MD == 1) || (CONFIG_SH_CLK_MD == 2) +#define PLL2 (4) +#elif (CONFIG_SH_CLK_MD == 5) || (CONFIG_SH_CLK_MD == 6) +#define PLL2 (2) +#else +#error "Illigal Clock Mode!" +#endif + +static void master_clk_init(struct clk *clk) +{ + clk->rate *= PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 7]; +} + +static struct clk_ops sh7619_master_clk_ops = { + .init = master_clk_init, +}; + +static void module_clk_recalc(struct clk *clk) +{ + int idx = (ctrl_inw(FREQCR) & 0x0007); + clk->rate = clk->parent->rate / pfc_divisors[idx]; +} + +static struct clk_ops sh7619_module_clk_ops = { + .recalc = module_clk_recalc, +}; + +static void bus_clk_recalc(struct clk *clk) +{ + clk->rate = clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 7]; +} + +static struct clk_ops sh7619_bus_clk_ops = { + .recalc = bus_clk_recalc, +}; + +static void cpu_clk_recalc(struct clk *clk) +{ + clk->rate = clk->parent->rate; +} + +static struct clk_ops sh7619_cpu_clk_ops = { + .recalc = cpu_clk_recalc, +}; + +static struct clk_ops *sh7619_clk_ops[] = { + &sh7619_master_clk_ops, + &sh7619_module_clk_ops, + &sh7619_bus_clk_ops, + &sh7619_cpu_clk_ops, +}; + +void __init arch_init_clk_ops(struct clk_ops **ops, int idx) +{ + if (idx < ARRAY_SIZE(sh7619_clk_ops)) + *ops = sh7619_clk_ops[idx]; +} + diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S new file mode 100644 index 00000000000..34d51b3745e --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/entry.S @@ -0,0 +1,341 @@ +/* + * arch/sh/kernel/cpu/sh2/entry.S + * + * The SH-2 exception entry + * + * Copyright (C) 2005,2006 Yoshinori Sato + * Copyright (C) 2005 AXE,Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/linkage.h> +#include <asm/asm-offsets.h> +#include <asm/thread_info.h> +#include <asm/cpu/mmu_context.h> +#include <asm/unistd.h> +#include <asm/errno.h> +#include <asm/page.h> + +/* Offsets to the stack */ +OFF_R0 = 0 /* Return value. New ABI also arg4 */ +OFF_R1 = 4 /* New ABI: arg5 */ +OFF_R2 = 8 /* New ABI: arg6 */ +OFF_R3 = 12 /* New ABI: syscall_nr */ +OFF_R4 = 16 /* New ABI: arg0 */ +OFF_R5 = 20 /* New ABI: arg1 */ +OFF_R6 = 24 /* New ABI: arg2 */ +OFF_R7 = 28 /* New ABI: arg3 */ +OFF_SP = (15*4) +OFF_PC = (16*4) +OFF_SR = (16*4+2*4) +OFF_TRA = (16*4+6*4) + +#include <asm/entry-macros.S> + +ENTRY(exception_handler) + ! already saved r0/r1 + mov.l r2,@-sp + mov.l r3,@-sp + mov r0,r1 + cli + mov.l $cpu_mode,r2 + mov.l @r2,r0 + mov.l @(5*4,r15),r3 ! previous SR + shll2 r3 ! set "S" flag + rotl r0 ! T <- "S" flag + rotl r0 ! "S" flag is LSB + rotcr r3 ! T -> r3:b30 + shlr r3 + shlr r0 + bt/s 1f + mov.l r3,@(5*4,r15) ! copy cpu mode to SR + ! switch to kernel mode + mov #1,r0 + rotr r0 + rotr r0 + mov.l r0,@r2 ! enter kernel mode + mov.l $current_thread_info,r2 + mov.l @r2,r2 + mov #0x20,r0 + shll8 r0 + add r2,r0 + mov r15,r2 ! r2 = user stack top + mov r0,r15 ! switch kernel stack + add #-4,r15 ! dummy + mov.l r1,@-r15 ! TRA + sts.l macl, @-r15 + sts.l mach, @-r15 + stc.l gbr, @-r15 + mov.l @(4*4,r2),r0 + mov.l @(5*4,r2),r1 + mov.l r1,@-r15 ! original SR + sts.l pr,@-r15 + mov.l r0,@-r15 ! original PC + mov r2,r3 + add #(4+2)*4,r3 ! rewind r0 - r3 + exception frame + mov.l r3,@-r15 ! original SP + mov.l r14,@-r15 + mov.l r13,@-r15 + mov.l r12,@-r15 + mov.l r11,@-r15 + mov.l r10,@-r15 + mov.l r9,@-r15 + mov.l r8,@-r15 + mov.l r7,@-r15 + mov.l r6,@-r15 + mov.l r5,@-r15 + mov.l r4,@-r15 + mov r2,r8 ! copy user -> kernel stack + mov.l @r8+,r3 + mov.l r3,@-r15 + mov.l @r8+,r2 + mov.l r2,@-r15 + mov.l @r8+,r1 + mov.l r1,@-r15 + mov.l @r8+,r0 + bra 2f + mov.l r0,@-r15 +1: + ! in kernel exception + mov #(22-4-4-1)*4+4,r0 + mov r15,r2 + sub r0,r15 + mov.l @r2+,r0 ! old R3 + mov.l r0,@-r15 + mov.l @r2+,r0 ! old R2 + mov.l r0,@-r15 + mov.l @r2+,r0 ! old R1 + mov.l r0,@-r15 + mov.l @r2+,r0 ! old R0 + mov.l r0,@-r15 + mov.l @r2+,r3 ! old PC + mov.l @r2+,r0 ! old SR + add #-4,r2 ! exception frame stub (sr) + mov.l r1,@-r2 ! TRA + sts.l macl, @-r2 + sts.l mach, @-r2 + stc.l gbr, @-r2 + mov.l r0,@-r2 ! save old SR + sts.l pr,@-r2 + mov.l r3,@-r2 ! save old PC + mov r2,r0 + add #8*4,r0 + mov.l r0,@-r2 ! save old SP + mov.l r14,@-r2 + mov.l r13,@-r2 + mov.l r12,@-r2 + mov.l r11,@-r2 + mov.l r10,@-r2 + mov.l r9,@-r2 + mov.l r8,@-r2 + mov.l r7,@-r2 + mov.l r6,@-r2 + mov.l r5,@-r2 + mov.l r4,@-r2 + mov.l @(OFF_R0,r15),r0 + mov.l @(OFF_R1,r15),r1 + mov.l @(OFF_R2,r15),r2 + mov.l @(OFF_R3,r15),r3 +2: + mov #OFF_TRA,r8 + add r15,r8 + mov.l @r8,r9 + mov #64,r8 + cmp/hs r8,r9 + bt interrupt_entry ! vec >= 64 is interrupt + mov #32,r8 + cmp/hs r8,r9 + bt trap_entry ! 64 > vec >= 32 is trap + mov.l 4f,r8 + mov r9,r4 + shll2 r9 + add r9,r8 + mov.l @r8,r8 + mov #0,r9 + cmp/eq r9,r8 + bf 3f + mov.l 8f,r8 ! unhandled exception +3: + mov.l 5f,r10 + jmp @r8 + lds r10,pr + +interrupt_entry: + mov r9,r4 + mov.l 6f,r9 + mov.l 7f,r8 + jmp @r8 + lds r9,pr + + .align 2 +4: .long exception_handling_table +5: .long ret_from_exception +6: .long ret_from_irq +7: .long do_IRQ +8: .long do_exception_error + +trap_entry: + add #-0x10,r9 + shll2 r9 ! TRA + mov #OFF_TRA,r8 + add r15,r8 + mov.l r9,@r8 + mov r9,r8 +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r9 + jsr @r9 + nop +#endif + sti + bra system_call + nop + + .align 2 +1: .long syscall_exit +2: .long break_point_trap_software +3: .long NR_syscalls +4: .long sys_call_table +#ifdef CONFIG_TRACE_IRQFLAGS +5: .long trace_hardirqs_on +#endif + +#if defined(CONFIG_SH_STANDARD_BIOS) + /* Unwind the stack and jmp to the debug entry */ +debug_kernel_fw: + mov r15,r0 + add #(22-4)*4-4,r0 + ldc.l @r0+,gbr + lds.l @r0+,mach + lds.l @r0+,macl + mov r15,r0 + mov.l @(OFF_SP,r0),r1 + mov #OFF_SR,r2 + mov.l @(r0,r2),r3 + mov.l r3,@-r1 + mov #OFF_SP,r2 + mov.l @(r0,r2),r3 + mov.l r3,@-r1 + mov r15,r0 + add #(22-4)*4-8,r0 + mov.l 1f,r2 + mov.l @r2,r2 + stc sr,r3 + mov.l r2,@r0 + mov.l r3,@r0 + mov.l r1,@(8,r0) + mov.l @r15+, r0 + mov.l @r15+, r1 + mov.l @r15+, r2 + mov.l @r15+, r3 + mov.l @r15+, r4 + mov.l @r15+, r5 + mov.l @r15+, r6 + mov.l @r15+, r7 + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r10 + mov.l @r15+, r11 + mov.l @r15+, r12 + mov.l @r15+, r13 + mov.l @r15+, r14 + add #8,r15 + lds.l @r15+, pr + rte + mov.l @r15+,r15 + .align 2 +1: .long gdb_vbr_vector +#endif /* CONFIG_SH_STANDARD_BIOS */ + +ENTRY(address_error_handler) + mov r15,r4 ! regs + add #4,r4 + mov #OFF_PC,r0 + mov.l @(r0,r15),r6 ! pc + mov.l 1f,r0 + jmp @r0 + mov #0,r5 ! writeaccess is unknown + .align 2 + +1: .long do_address_error + +restore_all: + cli +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 3f, r0 + jsr @r0 + nop +#endif + mov r15,r0 + mov.l $cpu_mode,r2 + mov #OFF_SR,r3 + mov.l @(r0,r3),r1 + mov.l r1,@r2 + shll2 r1 ! clear MD bit + shlr2 r1 + mov.l @(OFF_SP,r0),r2 + add #-8,r2 + mov.l r2,@(OFF_SP,r0) ! point exception frame top + mov.l r1,@(4,r2) ! set sr + mov #OFF_PC,r3 + mov.l @(r0,r3),r1 + mov.l r1,@r2 ! set pc + add #4*16+4,r0 + lds.l @r0+,pr + add #4,r0 ! skip sr + ldc.l @r0+,gbr + lds.l @r0+,mach + lds.l @r0+,macl + get_current_thread_info r0, r1 + mov.l $current_thread_info,r1 + mov.l r0,@r1 + mov.l @r15+,r0 + mov.l @r15+,r1 + mov.l @r15+,r2 + mov.l @r15+,r3 + mov.l @r15+,r4 + mov.l @r15+,r5 + mov.l @r15+,r6 + mov.l @r15+,r7 + mov.l @r15+,r8 + mov.l @r15+,r9 + mov.l @r15+,r10 + mov.l @r15+,r11 + mov.l @r15+,r12 + mov.l @r15+,r13 + mov.l @r15+,r14 + mov.l @r15,r15 + rte + nop +2: + mov.l 1f,r8 + mov.l 2f,r9 + jmp @r9 + lds r8,pr + + .align 2 +$current_thread_info: + .long __current_thread_info +$cpu_mode: + .long __cpu_mode +#ifdef CONFIG_TRACE_IRQFLAGS +3: .long trace_hardirqs_off +#endif + +! common exception handler +#include "../../entry-common.S" + + .data +! cpu operation mode +! bit30 = MD (compatible SH3/4) +__cpu_mode: + .long 0x40000000 + + .section .bss +__current_thread_info: + .long 0 + +ENTRY(exception_handling_table) + .space 4*32 diff --git a/arch/sh/kernel/cpu/sh2/ex.S b/arch/sh/kernel/cpu/sh2/ex.S new file mode 100644 index 00000000000..6d285af7846 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/ex.S @@ -0,0 +1,46 @@ +/* + * arch/sh/kernel/cpu/sh2/ex.S + * + * The SH-2 exception vector table + * + * Copyright (C) 2005 Yoshinori Sato + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/linkage.h> + +! +! convert Exception Vector to Exception Number +! +exception_entry: +no = 0 + .rept 256 + mov.l r0,@-sp + mov #no,r0 + bra exception_trampoline + and #0xff,r0 +no = no + 1 + .endr +exception_trampoline: + mov.l r1,@-sp + mov.l $exception_handler,r1 + jmp @r1 + + .align 2 +$exception_entry: + .long exception_entry +$exception_handler: + .long exception_handler +! +! Exception Vector Base +! + .align 2 +ENTRY(vbr_base) +vector = 0 + .rept 256 + .long exception_entry + vector * 8 +vector = vector + 1 + .endr diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c index f17a2a0d588..ba527d9b502 100644 --- a/arch/sh/kernel/cpu/sh2/probe.c +++ b/arch/sh/kernel/cpu/sh2/probe.c @@ -17,17 +17,23 @@ int __init detect_cpu_and_cache_system(void) { - /* - * For now, assume SH7604 .. fix this later. - */ +#if defined(CONFIG_CPU_SUBTYPE_SH7604) cpu_data->type = CPU_SH7604; cpu_data->dcache.ways = 4; - cpu_data->dcache.way_shift = 6; + cpu_data->dcache.way_incr = (1<<10); cpu_data->dcache.sets = 64; cpu_data->dcache.entry_shift = 4; cpu_data->dcache.linesz = L1_CACHE_BYTES; cpu_data->dcache.flags = 0; - +#elif defined(CONFIG_CPU_SUBTYPE_SH7619) + cpu_data->type = CPU_SH7619; + cpu_data->dcache.ways = 4; + cpu_data->dcache.way_incr = (1<<12); + cpu_data->dcache.sets = 256; + cpu_data->dcache.entry_shift = 4; + cpu_data->dcache.linesz = L1_CACHE_BYTES; + cpu_data->dcache.flags = 0; +#endif /* * SH-2 doesn't have separate caches */ diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c new file mode 100644 index 00000000000..82c2d905152 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c @@ -0,0 +1,53 @@ +/* + * SH7619 Setup + * + * Copyright (C) 2006 Yoshinori Sato + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/serial.h> +#include <asm/sci.h> + +static struct plat_sci_port sci_platform_data[] = { + { + .mapbase = 0xf8400000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 88, 89, 91, 90}, + }, { + .mapbase = 0xf8410000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 92, 93, 95, 94}, + }, { + .mapbase = 0xf8420000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 96, 97, 99, 98}, + }, { + .flags = 0, + } +}; + +static struct platform_device sci_device = { + .name = "sh-sci", + .id = -1, + .dev = { + .platform_data = sci_platform_data, + }, +}; + +static struct platform_device *sh7619_devices[] __initdata = { + &sci_device, +}; + +static int __init sh7619_devices_setup(void) +{ + return platform_add_devices(sh7619_devices, + ARRAY_SIZE(sh7619_devices)); +} +__initcall(sh7619_devices_setup); diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile new file mode 100644 index 00000000000..350972ae941 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the Linux/SuperH SH-2A backends. +# + +obj-y := common.o probe.o + +common-y += $(addprefix ../sh2/, ex.o) +common-y += $(addprefix ../sh2/, entry.o) + +obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7206.c b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c new file mode 100644 index 00000000000..a9ad309c6a3 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c @@ -0,0 +1,85 @@ +/* + * arch/sh/kernel/cpu/sh2a/clock-sh7206.c + * + * SH7206 support for the clock framework + * + * Copyright (C) 2006 Yoshinori Sato + * + * Based on clock-sh4.c + * Copyright (C) 2005 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <asm/clock.h> +#include <asm/freq.h> +#include <asm/io.h> + +const static int pll1rate[]={1,2,3,4,6,8}; +const static int pfc_divisors[]={1,2,3,4,6,8,12}; +#define ifc_divisors pfc_divisors + +#if (CONFIG_SH_CLK_MD == 2) +#define PLL2 (4) +#elif (CONFIG_SH_CLK_MD == 6) +#define PLL2 (2) +#elif (CONFIG_SH_CLK_MD == 7) +#define PLL2 (1) +#else +#error "Illigal Clock Mode!" +#endif + +static void master_clk_init(struct clk *clk) +{ + clk->rate *= PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007]; +} + +static struct clk_ops sh7206_master_clk_ops = { + .init = master_clk_init, +}; + +static void module_clk_recalc(struct clk *clk) +{ + int idx = (ctrl_inw(FREQCR) & 0x0007); + clk->rate = clk->parent->rate / pfc_divisors[idx]; +} + +static struct clk_ops sh7206_module_clk_ops = { + .recalc = module_clk_recalc, +}; + +static void bus_clk_recalc(struct clk *clk) +{ + clk->rate = clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007]; +} + +static struct clk_ops sh7206_bus_clk_ops = { + .recalc = bus_clk_recalc, +}; + +static void cpu_clk_recalc(struct clk *clk) +{ + int idx = (ctrl_inw(FREQCR) & 0x0007); + clk->rate = clk->parent->rate / ifc_divisors[idx]; +} + +static struct clk_ops sh7206_cpu_clk_ops = { + .recalc = cpu_clk_recalc, +}; + +static struct clk_ops *sh7206_clk_ops[] = { + &sh7206_master_clk_ops, + &sh7206_module_clk_ops, + &sh7206_bus_clk_ops, + &sh7206_cpu_clk_ops, +}; + +void __init arch_init_clk_ops(struct clk_ops **ops, int idx) +{ + if (idx < ARRAY_SIZE(sh7206_clk_ops)) + *ops = sh7206_clk_ops[idx]; +} + diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c new file mode 100644 index 00000000000..87c6c054208 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/probe.c @@ -0,0 +1,39 @@ +/* + * arch/sh/kernel/cpu/sh2a/probe.c + * + * CPU Subtype Probing for SH-2A. + * + * Copyright (C) 2004, 2005 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/init.h> +#include <asm/processor.h> +#include <asm/cache.h> + +int __init detect_cpu_and_cache_system(void) +{ + /* Just SH7206 for now .. */ + cpu_data->type = CPU_SH7206; + + cpu_data->dcache.ways = 4; + cpu_data->dcache.way_incr = (1 << 11); + cpu_data->dcache.sets = 128; + cpu_data->dcache.entry_shift = 4; + cpu_data->dcache.linesz = L1_CACHE_BYTES; + cpu_data->dcache.flags = 0; + + /* + * The icache is the same as the dcache as far as this setup is + * concerned. The only real difference in hardware is that the icache + * lacks the U bit that the dcache has, none of this has any bearing + * on the cache info. + */ + cpu_data->icache = cpu_data->dcache; + + return 0; +} + diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c new file mode 100644 index 00000000000..cdfeef49e62 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c @@ -0,0 +1,58 @@ +/* + * SH7206 Setup + * + * Copyright (C) 2006 Yoshinori Sato + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/serial.h> +#include <asm/sci.h> + +static struct plat_sci_port sci_platform_data[] = { + { + .mapbase = 0xfffe8000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 240, 241, 242, 243}, + }, { + .mapbase = 0xfffe8800, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 244, 245, 246, 247}, + }, { + .mapbase = 0xfffe9000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 248, 249, 250, 251}, + }, { + .mapbase = 0xfffe9800, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 252, 253, 254, 255}, + }, { + .flags = 0, + } +}; + +static struct platform_device sci_device = { + .name = "sh-sci", + .id = -1, + .dev = { + .platform_data = sci_platform_data, + }, +}; + +static struct platform_device *sh7206_devices[] __initdata = { + &sci_device, +}; + +static int __init sh7206_devices_setup(void) +{ + return platform_add_devices(sh7206_devices, + ARRAY_SIZE(sh7206_devices)); +} +__initcall(sh7206_devices_setup); diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile index 58d3815695f..83905e4e438 100644 --- a/arch/sh/kernel/cpu/sh3/Makefile +++ b/arch/sh/kernel/cpu/sh3/Makefile @@ -2,7 +2,7 @@ # Makefile for the Linux/SuperH SH-3 backends. # -obj-y := ex.o probe.o +obj-y := ex.o probe.o entry.o # CPU subtype setup obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7709.c b/arch/sh/kernel/cpu/sh3/clock-sh7709.c index 10461a745e5..b791a29fdb6 100644 --- a/arch/sh/kernel/cpu/sh3/clock-sh7709.c +++ b/arch/sh/kernel/cpu/sh3/clock-sh7709.c @@ -24,7 +24,7 @@ static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; static void set_bus_parent(struct clk *clk) { - struct clk *bus_clk = clk_get("bus_clk"); + struct clk *bus_clk = clk_get(NULL, "bus_clk"); clk->parent = bus_clk; clk_put(bus_clk); } diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 39aaefb2d83..8c0dc2700c6 100644 --- a/arch/sh/kernel/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S @@ -1,5 +1,5 @@ /* - * linux/arch/sh/entry.S + * arch/sh/kernel/entry.S * * Copyright (C) 1999, 2000, 2002 Niibe Yutaka * Copyright (C) 2003 - 2006 Paul Mundt @@ -7,15 +7,16 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - * */ #include <linux/sys.h> #include <linux/errno.h> #include <linux/linkage.h> #include <asm/asm-offsets.h> #include <asm/thread_info.h> -#include <asm/cpu/mmu_context.h> #include <asm/unistd.h> +#include <asm/cpu/mmu_context.h> +#include <asm/pgtable.h> +#include <asm/page.h> ! NOTE: ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address @@ -81,6 +82,8 @@ OFF_TRA = (16*4+6*4) #define k_g_imask r6_bank /* r6_bank1 */ #define current r7 /* r7_bank1 */ +#include <asm/entry-macros.S> + /* * Kernel mode register usage: * k0 scratch @@ -107,26 +110,6 @@ OFF_TRA = (16*4+6*4) ! this first version depends *much* on C implementation. ! -#define CLI() \ - stc sr, r0; \ - or #0xf0, r0; \ - ldc r0, sr - -#define STI() \ - mov.l __INV_IMASK, r11; \ - stc sr, r10; \ - and r11, r10; \ - stc k_g_imask, r11; \ - or r11, r10; \ - ldc r10, sr - -#if defined(CONFIG_PREEMPT) -# define preempt_stop() CLI() -#else -# define preempt_stop() -# define resume_kernel restore_all -#endif - #if defined(CONFIG_MMU) .align 2 ENTRY(tlb_miss_load) @@ -155,29 +138,14 @@ ENTRY(tlb_protection_violation_store) call_dpf: mov.l 1f, r0 - mov r5, r8 - mov.l @r0, r6 - mov r6, r9 - mov.l 2f, r0 - sts pr, r10 - jsr @r0 - mov r15, r4 - ! - tst r0, r0 - bf/s 0f - lds r10, pr - rts - nop -0: STI() + mov.l @r0, r6 ! address mov.l 3f, r0 - mov r9, r6 - mov r8, r5 + jmp @r0 - mov r15, r4 + mov r15, r4 ! regs .align 2 1: .long MMU_TEA -2: .long __do_page_fault 3: .long do_page_fault .align 2 @@ -203,32 +171,6 @@ call_dae: 2: .long do_address_error #endif /* CONFIG_MMU */ -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) -! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present. -! If both are configured, handle the debug traps (breakpoints) in SW, -! but still allow BIOS traps to FW. - - .align 2 -debug_kernel: -#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB) - /* Force BIOS call to FW (debug_trap put TRA in r8) */ - mov r8,r0 - shlr2 r0 - cmp/eq #0x3f,r0 - bt debug_kernel_fw -#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */ - -debug_enter: -#if defined(CONFIG_SH_KGDB) - /* Jump to kgdb, pass stacked regs as arg */ -debug_kernel_sw: - mov.l 3f, r0 - jmp @r0 - mov r15, r4 - .align 2 -3: .long kgdb_handle_exception -#endif /* CONFIG_SH_KGDB */ - #if defined(CONFIG_SH_STANDARD_BIOS) /* Unwind the stack and jmp to the debug entry */ debug_kernel_fw: @@ -269,276 +211,6 @@ debug_kernel_fw: 2: .long gdb_vbr_vector #endif /* CONFIG_SH_STANDARD_BIOS */ -#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ - - - .align 2 -debug_trap: -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) - mov #OFF_SR, r0 - mov.l @(r0,r15), r0 ! get status register - shll r0 - shll r0 ! kernel space? - bt/s debug_kernel -#endif - mov.l @r15, r0 ! Restore R0 value - mov.l 1f, r8 - jmp @r8 - nop - - .align 2 -ENTRY(exception_error) - ! - STI() - mov.l 2f, r0 - jmp @r0 - nop - -! - .align 2 -1: .long break_point_trap_software -2: .long do_exception_error - - .align 2 -ret_from_exception: - preempt_stop() -ENTRY(ret_from_irq) - ! - mov #OFF_SR, r0 - mov.l @(r0,r15), r0 ! get status register - shll r0 - shll r0 ! kernel space? - bt/s resume_kernel ! Yes, it's from kernel, go back soon - GET_THREAD_INFO(r8) - -#ifdef CONFIG_PREEMPT - bra resume_userspace - nop -ENTRY(resume_kernel) - mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count - tst r0, r0 - bf noresched -need_resched: - mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags - tst #_TIF_NEED_RESCHED, r0 ! need_resched set? - bt noresched - - mov #OFF_SR, r0 - mov.l @(r0,r15), r0 ! get status register - and #0xf0, r0 ! interrupts off (exception path)? - cmp/eq #0xf0, r0 - bt noresched - - mov.l 1f, r0 - mov.l r0, @(TI_PRE_COUNT,r8) - - STI() - mov.l 2f, r0 - jsr @r0 - nop - mov #0, r0 - mov.l r0, @(TI_PRE_COUNT,r8) - CLI() - - bra need_resched - nop -noresched: - bra restore_all - nop - - .align 2 -1: .long PREEMPT_ACTIVE -2: .long schedule -#endif - -ENTRY(resume_userspace) - ! r8: current_thread_info - CLI() - mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags - tst #_TIF_WORK_MASK, r0 - bt/s restore_all - tst #_TIF_NEED_RESCHED, r0 - - .align 2 -work_pending: - ! r0: current_thread_info->flags - ! r8: current_thread_info - ! t: result of "tst #_TIF_NEED_RESCHED, r0" - bf/s work_resched - tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0 -work_notifysig: - bt/s restore_all - mov r15, r4 - mov r12, r5 ! set arg1(save_r0) - mov r0, r6 - mov.l 2f, r1 - mova restore_all, r0 - jmp @r1 - lds r0, pr -work_resched: -#ifndef CONFIG_PREEMPT - ! gUSA handling - mov.l @(OFF_SP,r15), r0 ! get user space stack pointer - mov r0, r1 - shll r0 - bf/s 1f - shll r0 - bf/s 1f - mov #OFF_PC, r0 - ! SP >= 0xc0000000 : gUSA mark - mov.l @(r0,r15), r2 ! get user space PC (program counter) - mov.l @(OFF_R0,r15), r3 ! end point - cmp/hs r3, r2 ! r2 >= r3? - bt 1f - add r3, r1 ! rewind point #2 - mov.l r1, @(r0,r15) ! reset PC to rewind point #2 - ! -1: -#endif - mov.l 1f, r1 - jsr @r1 ! schedule - nop - CLI() - ! - mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags - tst #_TIF_WORK_MASK, r0 - bt restore_all - bra work_pending - tst #_TIF_NEED_RESCHED, r0 - - .align 2 -1: .long schedule -2: .long do_notify_resume - - .align 2 -syscall_exit_work: - ! r0: current_thread_info->flags - ! r8: current_thread_info - tst #_TIF_SYSCALL_TRACE, r0 - bt/s work_pending - tst #_TIF_NEED_RESCHED, r0 - STI() - ! XXX setup arguments... - mov.l 4f, r0 ! do_syscall_trace - jsr @r0 - nop - bra resume_userspace - nop - - .align 2 -syscall_trace_entry: - ! Yes it is traced. - ! XXX setup arguments... - mov.l 4f, r11 ! Call do_syscall_trace which notifies - jsr @r11 ! superior (will chomp R[0-7]) - nop - ! Reload R0-R4 from kernel stack, where the - ! parent may have modified them using - ! ptrace(POKEUSR). (Note that R0-R2 are - ! used by the system call handler directly - ! from the kernel stack anyway, so don't need - ! to be reloaded here.) This allows the parent - ! to rewrite system calls and args on the fly. - mov.l @(OFF_R4,r15), r4 ! arg0 - mov.l @(OFF_R5,r15), r5 - mov.l @(OFF_R6,r15), r6 - mov.l @(OFF_R7,r15), r7 ! arg3 - mov.l @(OFF_R3,r15), r3 ! syscall_nr - ! Arrange for do_syscall_trace to be called - ! again as the system call returns. - mov.l 2f, r10 ! Number of syscalls - cmp/hs r10, r3 - bf syscall_call - mov #-ENOSYS, r0 - bra syscall_exit - mov.l r0, @(OFF_R0,r15) ! Return value - -/* - * Syscall interface: - * - * Syscall #: R3 - * Arguments #0 to #3: R4--R7 - * Arguments #4 to #6: R0, R1, R2 - * TRA: (number of arguments + 0x10) x 4 - * - * This code also handles delegating other traps to the BIOS/gdb stub - * according to: - * - * Trap number - * (TRA>>2) Purpose - * -------- ------- - * 0x0-0xf old syscall ABI - * 0x10-0x1f new syscall ABI - * 0x20-0xff delegated through debug_trap to BIOS/gdb stub. - * - * Note: When we're first called, the TRA value must be shifted - * right 2 bits in order to get the value that was used as the "trapa" - * argument. - */ - - .align 2 - .globl ret_from_fork -ret_from_fork: - mov.l 1f, r8 - jsr @r8 - mov r0, r4 - bra syscall_exit - nop - .align 2 -1: .long schedule_tail - ! -ENTRY(system_call) - mov.l 1f, r9 - mov.l @r9, r8 ! Read from TRA (Trap Address) Register - ! - ! Is the trap argument >= 0x20? (TRA will be >= 0x80) - mov #0x7f, r9 - cmp/hi r9, r8 - bt/s 0f - mov #OFF_TRA, r9 - add r15, r9 - ! - mov.l r8, @r9 ! set TRA value to tra - STI() - ! Call the system call handler through the table. - ! First check for bad syscall number - mov r3, r9 - mov.l 2f, r8 ! Number of syscalls - cmp/hs r8, r9 - bf/s good_system_call - GET_THREAD_INFO(r8) -syscall_badsys: ! Bad syscall number - mov #-ENOSYS, r0 - bra resume_userspace - mov.l r0, @(OFF_R0,r15) ! Return value - ! -0: - bra debug_trap - nop - ! -good_system_call: ! Good syscall number - mov.l @(TI_FLAGS,r8), r8 - mov #_TIF_SYSCALL_TRACE, r10 - tst r10, r8 - bf syscall_trace_entry - ! -syscall_call: - shll2 r9 ! x4 - mov.l 3f, r8 ! Load the address of sys_call_table - add r8, r9 - mov.l @r9, r8 - jsr @r8 ! jump to specific syscall handler - nop - mov.l @(OFF_R0,r15), r12 ! save r0 - mov.l r0, @(OFF_R0,r15) ! save the return value - ! -syscall_exit: - CLI() - ! - GET_THREAD_INFO(r8) - mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags - tst #_TIF_ALLWORK_MASK, r0 - bf syscall_exit_work restore_all: mov.l @r15+, r0 mov.l @r15+, r1 @@ -606,7 +278,9 @@ skip_restore: ! ! Calculate new SR value mov k3, k2 ! original SR value - mov.l 9f, k1 + mov #0xf0, k1 + extu.b k1, k1 + not k1, k1 and k1, k2 ! Mask orignal SR value ! mov k3, k0 ! Calculate IMASK-bits @@ -632,16 +306,12 @@ skip_restore: nop .align 2 -1: .long TRA -2: .long NR_syscalls -3: .long sys_call_table -4: .long do_syscall_trace 5: .long 0x00001000 ! DSP 7: .long 0x30000000 -9: -__INV_IMASK: - .long 0xffffff0f ! ~(IMASK) +! common exception handler +#include "../../entry-common.S" + ! Exception Vector Base ! ! Should be aligned page boundary. @@ -661,9 +331,176 @@ general_exception: 2: .long ret_from_exception ! ! + +/* This code makes some assumptions to improve performance. + * Make sure they are stil true. */ +#if PTRS_PER_PGD != PTRS_PER_PTE +#error PGD and PTE sizes don't match +#endif + +/* gas doesn't flag impossible values for mov #immediate as an error */ +#if (_PAGE_PRESENT >> 2) > 0x7f +#error cannot load PAGE_PRESENT as an immediate +#endif +#if _PAGE_DIRTY > 0x7f +#error cannot load PAGE_DIRTY as an immediate +#endif +#if (_PAGE_PRESENT << 2) != _PAGE_ACCESSED +#error cannot derive PAGE_ACCESSED from PAGE_PRESENT +#endif + +#if defined(CONFIG_CPU_SH4) +#define ldmmupteh(r) mov.l 8f, r +#else +#define ldmmupteh(r) mov #MMU_PTEH, r +#endif + .balign 1024,0,1024 tlb_miss: - mov.l 1f, k2 +#ifdef COUNT_EXCEPTIONS + ! Increment the counts + mov.l 9f, k1 + mov.l @k1, k2 + add #1, k2 + mov.l k2, @k1 +#endif + + ! k0 scratch + ! k1 pgd and pte pointers + ! k2 faulting address + ! k3 pgd and pte index masks + ! k4 shift + + ! Load up the pgd entry (k1) + + ldmmupteh(k0) ! 9 LS (latency=2) MMU_PTEH + + mov.w 4f, k3 ! 8 LS (latency=2) (PTRS_PER_PGD-1) << 2 + mov #-(PGDIR_SHIFT-2), k4 ! 6 EX + + mov.l @(MMU_TEA-MMU_PTEH,k0), k2 ! 18 LS (latency=2) + + mov.l @(MMU_TTB-MMU_PTEH,k0), k1 ! 18 LS (latency=2) + + mov k2, k0 ! 5 MT (latency=0) + shld k4, k0 ! 99 EX + + and k3, k0 ! 78 EX + + mov.l @(k0, k1), k1 ! 21 LS (latency=2) + mov #-(PAGE_SHIFT-2), k4 ! 6 EX + + ! Load up the pte entry (k2) + + mov k2, k0 ! 5 MT (latency=0) + shld k4, k0 ! 99 EX + + tst k1, k1 ! 86 MT + + bt 20f ! 110 BR + + and k3, k0 ! 78 EX + mov.w 5f, k4 ! 8 LS (latency=2) _PAGE_PRESENT + + mov.l @(k0, k1), k2 ! 21 LS (latency=2) + add k0, k1 ! 49 EX + +#ifdef CONFIG_CPU_HAS_PTEA + ! Test the entry for present and _PAGE_ACCESSED + + mov #-28, k3 ! 6 EX + mov k2, k0 ! 5 MT (latency=0) + + tst k4, k2 ! 68 MT + shld k3, k0 ! 99 EX + + bt 20f ! 110 BR + + ! Set PTEA register + ! MMU_PTEA = ((pteval >> 28) & 0xe) | (pteval & 0x1) + ! + ! k0=pte>>28, k1=pte*, k2=pte, k3=<unused>, k4=_PAGE_PRESENT + + and #0xe, k0 ! 79 EX + + mov k0, k3 ! 5 MT (latency=0) + mov k2, k0 ! 5 MT (latency=0) + + and #1, k0 ! 79 EX + + or k0, k3 ! 82 EX + + ldmmupteh(k0) ! 9 LS (latency=2) + shll2 k4 ! 101 EX _PAGE_ACCESSED + + tst k4, k2 ! 68 MT + + mov.l k3, @(MMU_PTEA-MMU_PTEH,k0) ! 27 LS + + mov.l 7f, k3 ! 9 LS (latency=2) _PAGE_FLAGS_HARDWARE_MASK + + ! k0=MMU_PTEH, k1=pte*, k2=pte, k3=_PAGE_FLAGS_HARDWARE, k4=_PAGE_ACCESSED +#else + + ! Test the entry for present and _PAGE_ACCESSED + + mov.l 7f, k3 ! 9 LS (latency=2) _PAGE_FLAGS_HARDWARE_MASK + tst k4, k2 ! 68 MT + + shll2 k4 ! 101 EX _PAGE_ACCESSED + ldmmupteh(k0) ! 9 LS (latency=2) + + bt 20f ! 110 BR + tst k4, k2 ! 68 MT + + ! k0=MMU_PTEH, k1=pte*, k2=pte, k3=_PAGE_FLAGS_HARDWARE, k4=_PAGE_ACCESSED + +#endif + + ! Set up the entry + + and k2, k3 ! 78 EX + bt/s 10f ! 108 BR + + mov.l k3, @(MMU_PTEL-MMU_PTEH,k0) ! 27 LS + + ldtlb ! 128 CO + + ! At least one instruction between ldtlb and rte + nop ! 119 NOP + + rte ! 126 CO + + nop ! 119 NOP + + +10: or k4, k2 ! 82 EX + + ldtlb ! 128 CO + + ! At least one instruction between ldtlb and rte + mov.l k2, @k1 ! 27 LS + + rte ! 126 CO + + ! Note we cannot execute mov here, because it is executed after + ! restoring SSR, so would be executed in user space. + nop ! 119 NOP + + + .align 5 + ! Once cache line if possible... +1: .long swapper_pg_dir +4: .short (PTRS_PER_PGD-1) << 2 +5: .short _PAGE_PRESENT +7: .long _PAGE_FLAGS_HARDWARE_MASK +8: .long MMU_PTEH +#ifdef COUNT_EXCEPTIONS +9: .long exception_count_miss +#endif + + ! Either pgd or pte not present +20: mov.l 1f, k2 mov.l 4f, k3 bra handle_exception mov.l @k2, k2 @@ -710,8 +547,9 @@ ENTRY(handle_exception) bt/s 1f ! It's a kernel to kernel transition. mov r15, k0 ! save original stack to k0 /* User space to kernel */ - mov #(THREAD_SIZE >> 8), k1 + mov #(THREAD_SIZE >> 10), k1 shll8 k1 ! k1 := THREAD_SIZE + shll2 k1 add current, k1 mov k1, r15 ! change to kernel stack ! @@ -761,7 +599,7 @@ skip_save: ! Save the user registers on the stack. mov.l k2, @-r15 ! EXPEVT - mov #-1, k4 + mov #-1, k4 mov.l k4, @-r15 ! set TRA (default: -1) ! sts.l macl, @-r15 @@ -813,6 +651,15 @@ skip_save: bf interrupt_exception shlr2 r8 shlr r8 + +#ifdef COUNT_EXCEPTIONS + mov.l 5f, r9 + add r8, r9 + mov.l @r9, r10 + add #1, r10 + mov.l r10, @r9 +#endif + mov.l 4f, r9 add r8, r9 mov.l @r9, r9 @@ -826,6 +673,9 @@ skip_save: 2: .long 0x000080f0 ! FD=1, IMASK=15 3: .long 0xcfffffff ! RB=0, BL=0 4: .long exception_handling_table +#ifdef COUNT_EXCEPTIONS +5: .long exception_count_table +#endif interrupt_exception: mov.l 1f, r9 diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile index 8dbf3895ece..6e415baf04b 100644 --- a/arch/sh/kernel/cpu/sh4/Makefile +++ b/arch/sh/kernel/cpu/sh4/Makefile @@ -2,7 +2,8 @@ # Makefile for the Linux/SuperH SH-4 backends. # -obj-y := ex.o probe.o +obj-y := ex.o probe.o common.o +common-y += $(addprefix ../sh3/, entry.o) obj-$(CONFIG_SH_FPU) += fpu.o obj-$(CONFIG_SH_STORE_QUEUES) += sq.o diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c index bfdf5fe8d94..fa2019aabd7 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c +++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c @@ -97,7 +97,7 @@ static void shoc_clk_recalc(struct clk *clk) static int shoc_clk_verify_rate(struct clk *clk, unsigned long rate) { - struct clk *bclk = clk_get("bus_clk"); + struct clk *bclk = clk_get(NULL, "bus_clk"); unsigned long bclk_rate = clk_get_rate(bclk); clk_put(bclk); @@ -151,7 +151,7 @@ static struct clk *sh4202_onchip_clocks[] = { static int __init sh4202_clk_init(void) { - struct clk *clk = clk_get("master_clk"); + struct clk *clk = clk_get(NULL, "master_clk"); int i; for (i = 0; i < ARRAY_SIZE(sh4202_onchip_clocks); i++) { diff --git a/arch/sh/kernel/cpu/sh4/clock-sh7780.c b/arch/sh/kernel/cpu/sh4/clock-sh7780.c index 93ad367342c..9e6a216750c 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh7780.c +++ b/arch/sh/kernel/cpu/sh4/clock-sh7780.c @@ -98,7 +98,7 @@ static struct clk *sh7780_onchip_clocks[] = { static int __init sh7780_clk_init(void) { - struct clk *clk = clk_get("master_clk"); + struct clk *clk = clk_get(NULL, "master_clk"); int i; for (i = 0; i < ARRAY_SIZE(sh7780_onchip_clocks); i++) { diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c index f486c07e10e..7624677f662 100644 --- a/arch/sh/kernel/cpu/sh4/fpu.c +++ b/arch/sh/kernel/cpu/sh4/fpu.c @@ -282,11 +282,8 @@ ieee_fpe_handler (struct pt_regs *regs) grab_fpu(regs); restore_fpu(tsk); set_tsk_thread_flag(tsk, TIF_USEDFPU); - } else { - tsk->thread.trap_no = 11; - tsk->thread.error_code = 0; + } else force_sig(SIGFPE, tsk); - } regs->pc = nextpc; return 1; @@ -296,29 +293,29 @@ ieee_fpe_handler (struct pt_regs *regs) } asmlinkage void -do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) +do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, + unsigned long r7, struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); struct task_struct *tsk = current; - if (ieee_fpe_handler (®s)) + if (ieee_fpe_handler(regs)) return; - regs.pc += 2; - save_fpu(tsk, ®s); - tsk->thread.trap_no = 11; - tsk->thread.error_code = 0; + regs->pc += 2; + save_fpu(tsk, regs); force_sig(SIGFPE, tsk); } asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6, - unsigned long r7, struct pt_regs regs) + unsigned long r7, struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); struct task_struct *tsk = current; - grab_fpu(®s); - if (!user_mode(®s)) { + grab_fpu(regs); + if (!user_mode(regs)) { printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); return; } diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index c294de1e14a..afe0f1b1c03 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c @@ -79,16 +79,16 @@ int __init detect_cpu_and_cache_system(void) case 0x205: cpu_data->type = CPU_SH7750; cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | - CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA; + CPU_HAS_PERF_COUNTER; break; case 0x206: cpu_data->type = CPU_SH7750S; cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | - CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA; + CPU_HAS_PERF_COUNTER; break; case 0x1100: cpu_data->type = CPU_SH7751; - cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; + cpu_data->flags |= CPU_HAS_FPU; break; case 0x2000: cpu_data->type = CPU_SH73180; @@ -126,23 +126,22 @@ int __init detect_cpu_and_cache_system(void) break; case 0x8000: cpu_data->type = CPU_ST40RA; - cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; + cpu_data->flags |= CPU_HAS_FPU; break; case 0x8100: cpu_data->type = CPU_ST40GX1; - cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; + cpu_data->flags |= CPU_HAS_FPU; break; case 0x700: cpu_data->type = CPU_SH4_501; cpu_data->icache.ways = 2; cpu_data->dcache.ways = 2; - cpu_data->flags |= CPU_HAS_PTEA; break; case 0x600: cpu_data->type = CPU_SH4_202; cpu_data->icache.ways = 2; cpu_data->dcache.ways = 2; - cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; + cpu_data->flags |= CPU_HAS_FPU; break; case 0x500 ... 0x501: switch (prr) { @@ -160,7 +159,7 @@ int __init detect_cpu_and_cache_system(void) cpu_data->icache.ways = 2; cpu_data->dcache.ways = 2; - cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; + cpu_data->flags |= CPU_HAS_FPU; break; default: @@ -173,6 +172,10 @@ int __init detect_cpu_and_cache_system(void) cpu_data->dcache.ways = 1; #endif +#ifdef CONFIG_CPU_HAS_PTEA + cpu_data->flags |= CPU_HAS_PTEA; +#endif + /* * On anything that's not a direct-mapped cache, look to the CVR * for I/D-cache specifics. diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c index 50812d57c1c..bbcb06f18b0 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c @@ -2,6 +2,7 @@ * SH7750/SH7751 Setup * * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2006 Jamie Lenehan * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -10,6 +11,7 @@ #include <linux/platform_device.h> #include <linux/init.h> #include <linux/serial.h> +#include <linux/io.h> #include <asm/sci.h> static struct plat_sci_port sci_platform_data[] = { @@ -46,3 +48,71 @@ static int __init sh7750_devices_setup(void) ARRAY_SIZE(sh7750_devices)); } __initcall(sh7750_devices_setup); + +static struct ipr_data sh7750_ipr_map[] = { + /* IRQ, IPR-idx, shift, priority */ + { 16, 0, 12, 2 }, /* TMU0 TUNI*/ + { 17, 0, 12, 2 }, /* TMU1 TUNI */ + { 18, 0, 4, 2 }, /* TMU2 TUNI */ + { 19, 0, 4, 2 }, /* TMU2 TIPCI */ + { 27, 1, 12, 2 }, /* WDT ITI */ + { 20, 0, 0, 2 }, /* RTC ATI (alarm) */ + { 21, 0, 0, 2 }, /* RTC PRI (period) */ + { 22, 0, 0, 2 }, /* RTC CUI (carry) */ + { 23, 1, 4, 3 }, /* SCI ERI */ + { 24, 1, 4, 3 }, /* SCI RXI */ + { 25, 1, 4, 3 }, /* SCI TXI */ + { 40, 2, 4, 3 }, /* SCIF ERI */ + { 41, 2, 4, 3 }, /* SCIF RXI */ + { 42, 2, 4, 3 }, /* SCIF BRI */ + { 43, 2, 4, 3 }, /* SCIF TXI */ + { 34, 2, 8, 7 }, /* DMAC DMTE0 */ + { 35, 2, 8, 7 }, /* DMAC DMTE1 */ + { 36, 2, 8, 7 }, /* DMAC DMTE2 */ + { 37, 2, 8, 7 }, /* DMAC DMTE3 */ + { 28, 2, 8, 7 }, /* DMAC DMAE */ +}; + +static struct ipr_data sh7751_ipr_map[] = { + { 44, 2, 8, 7 }, /* DMAC DMTE4 */ + { 45, 2, 8, 7 }, /* DMAC DMTE5 */ + { 46, 2, 8, 7 }, /* DMAC DMTE6 */ + { 47, 2, 8, 7 }, /* DMAC DMTE7 */ + /* The following use INTC_INPRI00 for masking, which is a 32-bit + register, not a 16-bit register like the IPRx registers, so it + would need special support */ + /*{ 72, INTPRI00, 8, ? },*/ /* TMU3 TUNI */ + /*{ 76, INTPRI00, 12, ? },*/ /* TMU4 TUNI */ +}; + +static unsigned long ipr_offsets[] = { + 0xffd00004UL, /* 0: IPRA */ + 0xffd00008UL, /* 1: IPRB */ + 0xffd0000cUL, /* 2: IPRC */ + 0xffd00010UL, /* 3: IPRD */ +}; + +/* given the IPR index return the address of the IPR register */ +unsigned int map_ipridx_to_addr(int idx) +{ + if (idx >= ARRAY_SIZE(ipr_offsets)) + return 0; + return ipr_offsets[idx]; +} + +#define INTC_ICR 0xffd00000UL +#define INTC_ICR_IRLM (1<<7) + +/* enable individual interrupt mode for external interupts */ +void ipr_irq_enable_irlm(void) +{ + ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); +} + +void __init init_IRQ_ipr() +{ + make_ipr_irq(sh7750_ipr_map, ARRAY_SIZE(sh7750_ipr_map)); +#ifdef CONFIG_CPU_SUBTYPE_SH7751 + make_ipr_irq(sh7751_ipr_map, ARRAY_SIZE(sh7751_ipr_map)); +#endif +} diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7780.c b/arch/sh/kernel/cpu/sh4/setup-sh7780.c index 814ddb22653..9aeaa2ddaa2 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7780.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7780.c @@ -79,25 +79,27 @@ static int __init sh7780_devices_setup(void) __initcall(sh7780_devices_setup); static struct intc2_data intc2_irq_table[] = { - { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2 }, - { 21, 1, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY }, - { 22, 1, 1, 0, INTC_RTC_MSK, TIMER_PRIORITY }, - { 23, 1, 2, 0, INTC_RTC_MSK, TIMER_PRIORITY }, - { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, - { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, - { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, - { SCIF0_TXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, + { 28, 0, 24, 0, 0, 2 }, /* TMU0 */ - { SCIF1_ERI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, - { SCIF1_RXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, - { SCIF1_BRI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, - { SCIF1_TXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, + { 21, 1, 0, 0, 2, 2 }, + { 22, 1, 1, 0, 2, 2 }, + { 23, 1, 2, 0, 2, 2 }, - { PCIC0_IRQ, 0x10, 8, 0, INTC_PCIC0_MSK, PCIC0_PRIORITY }, - { PCIC1_IRQ, 0x10, 0, 0, INTC_PCIC1_MSK, PCIC1_PRIORITY }, - { PCIC2_IRQ, 0x14, 24, 0, INTC_PCIC2_MSK, PCIC2_PRIORITY }, - { PCIC3_IRQ, 0x14, 16, 0, INTC_PCIC3_MSK, PCIC3_PRIORITY }, - { PCIC4_IRQ, 0x14, 8, 0, INTC_PCIC4_MSK, PCIC4_PRIORITY }, + { 40, 8, 24, 0, 3, 3 }, /* SCIF0 ERI */ + { 41, 8, 24, 0, 3, 3 }, /* SCIF0 RXI */ + { 42, 8, 24, 0, 3, 3 }, /* SCIF0 BRI */ + { 43, 8, 24, 0, 3, 3 }, /* SCIF0 TXI */ + + { 76, 8, 16, 0, 4, 3 }, /* SCIF1 ERI */ + { 77, 8, 16, 0, 4, 3 }, /* SCIF1 RXI */ + { 78, 8, 16, 0, 4, 3 }, /* SCIF1 BRI */ + { 79, 8, 16, 0, 4, 3 }, /* SCIF1 TXI */ + + { 64, 0x10, 8, 0, 14, 2 }, /* PCIC0 */ + { 65, 0x10, 0, 0, 15, 2 }, /* PCIC1 */ + { 66, 0x14, 24, 0, 16, 2 }, /* PCIC2 */ + { 67, 0x14, 16, 0, 17, 2 }, /* PCIC3 */ + { 68, 0x14, 8, 0, 18, 2 }, /* PCIC4 */ }; void __init init_IRQ_intc2(void) diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 7bcc73f9b8d..55f43506995 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -19,7 +19,7 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/mm.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/page.h> #include <asm/cacheflush.h> #include <asm/cpu/sq.h> @@ -67,6 +67,7 @@ void sq_flush_range(unsigned long start, unsigned int len) /* Wait for completion */ store_queue_barrier(); } +EXPORT_SYMBOL(sq_flush_range); static inline void sq_mapping_list_add(struct sq_mapping *map) { @@ -166,7 +167,7 @@ unsigned long sq_remap(unsigned long phys, unsigned int size, map->size = size; map->name = name; - page = bitmap_find_free_region(sq_bitmap, 0x04000000, + page = bitmap_find_free_region(sq_bitmap, 0x04000000 >> PAGE_SHIFT, get_order(map->size)); if (unlikely(page < 0)) { ret = -ENOSPC; @@ -193,6 +194,7 @@ out: kmem_cache_free(sq_cache, map); return ret; } +EXPORT_SYMBOL(sq_remap); /** * sq_unmap - Unmap a Store Queue allocation @@ -234,6 +236,7 @@ void sq_unmap(unsigned long vaddr) kmem_cache_free(sq_cache, map); } +EXPORT_SYMBOL(sq_unmap); /* * Needlessly complex sysfs interface. Unfortunately it doesn't seem like @@ -402,7 +405,3 @@ module_exit(sq_api_exit); MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(sq_remap); -EXPORT_SYMBOL(sq_unmap); -EXPORT_SYMBOL(sq_flush_range); diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c index a00022722e9..60340823798 100644 --- a/arch/sh/kernel/early_printk.c +++ b/arch/sh/kernel/early_printk.c @@ -12,7 +12,7 @@ #include <linux/console.h> #include <linux/tty.h> #include <linux/init.h> -#include <asm/io.h> +#include <linux/io.h> #ifdef CONFIG_SH_STANDARD_BIOS #include <asm/sh_bios.h> @@ -62,17 +62,9 @@ static struct console bios_console = { #include <linux/serial_core.h> #include "../../../drivers/serial/sh-sci.h" -#ifdef CONFIG_CPU_SH4 -#define SCIF_REG 0xffe80000 -#elif defined(CONFIG_CPU_SUBTYPE_SH72060) -#define SCIF_REG 0xfffe9800 -#else -#error "Undefined SCIF for this subtype" -#endif - static struct uart_port scif_port = { - .mapbase = SCIF_REG, - .membase = (char __iomem *)SCIF_REG, + .mapbase = CONFIG_EARLY_SCIF_CONSOLE_PORT, + .membase = (char __iomem *)CONFIG_EARLY_SCIF_CONSOLE_PORT, }; static void scif_sercon_putc(int c) @@ -113,23 +105,29 @@ static struct console scif_console = { .index = -1, }; +#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS) +/* + * Simple SCIF init, primarily aimed at SH7750 and other similar SH-4 + * devices that aren't using sh-ipl+g. + */ static void scif_sercon_init(int baud) { - ctrl_outw(0, SCIF_REG + 8); - ctrl_outw(0, SCIF_REG); + ctrl_outw(0, scif_port.mapbase + 8); + ctrl_outw(0, scif_port.mapbase); /* Set baud rate */ ctrl_outb((CONFIG_SH_PCLK_FREQ + 16 * baud) / - (32 * baud) - 1, SCIF_REG + 4); - - ctrl_outw(12, SCIF_REG + 24); - ctrl_outw(8, SCIF_REG + 24); - ctrl_outw(0, SCIF_REG + 32); - ctrl_outw(0x60, SCIF_REG + 16); - ctrl_outw(0, SCIF_REG + 36); - ctrl_outw(0x30, SCIF_REG + 8); + (32 * baud) - 1, scif_port.mapbase + 4); + + ctrl_outw(12, scif_port.mapbase + 24); + ctrl_outw(8, scif_port.mapbase + 24); + ctrl_outw(0, scif_port.mapbase + 32); + ctrl_outw(0x60, scif_port.mapbase + 16); + ctrl_outw(0, scif_port.mapbase + 36); + ctrl_outw(0x30, scif_port.mapbase + 8); } -#endif +#endif /* CONFIG_CPU_SH4 && !CONFIG_SH_STANDARD_BIOS */ +#endif /* CONFIG_EARLY_SCIF_CONSOLE */ /* * Setup a default console, if more than one is compiled in, rely on the @@ -168,7 +166,7 @@ int __init setup_early_printk(char *opt) if (!strncmp(buf, "serial", 6)) { early_console = &scif_console; -#ifdef CONFIG_CPU_SH4 +#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS) scif_sercon_init(115200); #endif } diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S new file mode 100644 index 00000000000..29136a35d7c --- /dev/null +++ b/arch/sh/kernel/entry-common.S @@ -0,0 +1,433 @@ +/* $Id: entry.S,v 1.37 2004/06/11 13:02:46 doyu Exp $ + * + * linux/arch/sh/entry.S + * + * Copyright (C) 1999, 2000, 2002 Niibe Yutaka + * Copyright (C) 2003 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +! NOTE: +! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address +! to be jumped is too far, but it causes illegal slot exception. + +/* + * entry.S contains the system-call and fault low-level handling routines. + * This also contains the timer-interrupt handler, as well as all interrupts + * and faults that can result in a task-switch. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + * + * NOTE: This code uses a convention that instructions in the delay slot + * of a transfer-control instruction are indented by an extra space, thus: + * + * jmp @k0 ! control-transfer instruction + * ldc k1, ssr ! delay slot + * + * Stack layout in 'ret_from_syscall': + * ptrace needs to have all regs on the stack. + * if the order here is changed, it needs to be + * updated in ptrace.c and ptrace.h + * + * r0 + * ... + * r15 = stack pointer + * spc + * pr + * ssr + * gbr + * mach + * macl + * syscall # + * + */ + +#if defined(CONFIG_PREEMPT) +# define preempt_stop() cli +#else +# define preempt_stop() +# define resume_kernel __restore_all +#endif + +#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) +! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present. +! If both are configured, handle the debug traps (breakpoints) in SW, +! but still allow BIOS traps to FW. + + .align 2 +debug_kernel: +#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB) + /* Force BIOS call to FW (debug_trap put TRA in r8) */ + mov r8,r0 + shlr2 r0 + cmp/eq #0x3f,r0 + bt debug_kernel_fw +#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */ + +debug_enter: +#if defined(CONFIG_SH_KGDB) + /* Jump to kgdb, pass stacked regs as arg */ +debug_kernel_sw: + mov.l 3f, r0 + jmp @r0 + mov r15, r4 + .align 2 +3: .long kgdb_handle_exception +#endif /* CONFIG_SH_KGDB */ + +#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ + + + .align 2 +debug_trap: +#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) + mov #OFF_SR, r0 + mov.l @(r0,r15), r0 ! get status register + shll r0 + shll r0 ! kernel space? + bt/s debug_kernel +#endif + mov.l @r15, r0 ! Restore R0 value + mov.l 1f, r8 + jmp @r8 + nop + + .align 2 +ENTRY(exception_error) + ! +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 3f, r0 + jsr @r0 + nop +#endif + sti + mov.l 2f, r0 + jmp @r0 + nop + +! + .align 2 +1: .long break_point_trap_software +2: .long do_exception_error +#ifdef CONFIG_TRACE_IRQFLAGS +3: .long trace_hardirqs_on +#endif + + .align 2 +ret_from_exception: + preempt_stop() +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 4f, r0 + jsr @r0 + nop +#endif +ENTRY(ret_from_irq) + ! + mov #OFF_SR, r0 + mov.l @(r0,r15), r0 ! get status register + shll r0 + shll r0 ! kernel space? + get_current_thread_info r8, r0 + bt resume_kernel ! Yes, it's from kernel, go back soon + +#ifdef CONFIG_PREEMPT + bra resume_userspace + nop +ENTRY(resume_kernel) + mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count + tst r0, r0 + bf noresched +need_resched: + mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags + tst #_TIF_NEED_RESCHED, r0 ! need_resched set? + bt noresched + + mov #OFF_SR, r0 + mov.l @(r0,r15), r0 ! get status register + and #0xf0, r0 ! interrupts off (exception path)? + cmp/eq #0xf0, r0 + bt noresched + + mov.l 1f, r0 + mov.l r0, @(TI_PRE_COUNT,r8) + +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 3f, r0 + jsr @r0 + nop +#endif + sti + mov.l 2f, r0 + jsr @r0 + nop + mov #0, r0 + mov.l r0, @(TI_PRE_COUNT,r8) + cli +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 4f, r0 + jsr @r0 + nop +#endif + + bra need_resched + nop + +noresched: + bra __restore_all + nop + + .align 2 +1: .long PREEMPT_ACTIVE +2: .long schedule +#ifdef CONFIG_TRACE_IRQFLAGS +3: .long trace_hardirqs_on +4: .long trace_hardirqs_off +#endif +#endif + +ENTRY(resume_userspace) + ! r8: current_thread_info + cli +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r0 + jsr @r0 + nop +#endif + mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags + tst #_TIF_WORK_MASK, r0 + bt/s __restore_all + tst #_TIF_NEED_RESCHED, r0 + + .align 2 +work_pending: + ! r0: current_thread_info->flags + ! r8: current_thread_info + ! t: result of "tst #_TIF_NEED_RESCHED, r0" + bf/s work_resched + tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0 +work_notifysig: + bt/s __restore_all + mov r15, r4 + mov r12, r5 ! set arg1(save_r0) + mov r0, r6 + mov.l 2f, r1 + mov.l 3f, r0 + jmp @r1 + lds r0, pr +work_resched: +#ifndef CONFIG_PREEMPT + ! gUSA handling + mov.l @(OFF_SP,r15), r0 ! get user space stack pointer + mov r0, r1 + shll r0 + bf/s 1f + shll r0 + bf/s 1f + mov #OFF_PC, r0 + ! SP >= 0xc0000000 : gUSA mark + mov.l @(r0,r15), r2 ! get user space PC (program counter) + mov.l @(OFF_R0,r15), r3 ! end point + cmp/hs r3, r2 ! r2 >= r3? + bt 1f + add r3, r1 ! rewind point #2 + mov.l r1, @(r0,r15) ! reset PC to rewind point #2 + ! +1: +#endif + mov.l 1f, r1 + jsr @r1 ! schedule + nop + cli +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r0 + jsr @r0 + nop +#endif + ! + mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags + tst #_TIF_WORK_MASK, r0 + bt __restore_all + bra work_pending + tst #_TIF_NEED_RESCHED, r0 + + .align 2 +1: .long schedule +2: .long do_notify_resume +3: .long restore_all +#ifdef CONFIG_TRACE_IRQFLAGS +4: .long trace_hardirqs_on +5: .long trace_hardirqs_off +#endif + + .align 2 +syscall_exit_work: + ! r0: current_thread_info->flags + ! r8: current_thread_info + tst #_TIF_SYSCALL_TRACE, r0 + bt/s work_pending + tst #_TIF_NEED_RESCHED, r0 +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r0 + jsr @r0 + nop +#endif + sti + ! XXX setup arguments... + mov.l 4f, r0 ! do_syscall_trace + jsr @r0 + nop + bra resume_userspace + nop + + .align 2 +syscall_trace_entry: + ! Yes it is traced. + ! XXX setup arguments... + mov.l 4f, r11 ! Call do_syscall_trace which notifies + jsr @r11 ! superior (will chomp R[0-7]) + nop + ! Reload R0-R4 from kernel stack, where the + ! parent may have modified them using + ! ptrace(POKEUSR). (Note that R0-R2 are + ! used by the system call handler directly + ! from the kernel stack anyway, so don't need + ! to be reloaded here.) This allows the parent + ! to rewrite system calls and args on the fly. + mov.l @(OFF_R4,r15), r4 ! arg0 + mov.l @(OFF_R5,r15), r5 + mov.l @(OFF_R6,r15), r6 + mov.l @(OFF_R7,r15), r7 ! arg3 + mov.l @(OFF_R3,r15), r3 ! syscall_nr + ! + mov.l 2f, r10 ! Number of syscalls + cmp/hs r10, r3 + bf syscall_call + mov #-ENOSYS, r0 + bra syscall_exit + mov.l r0, @(OFF_R0,r15) ! Return value + +__restore_all: + mov.l 1f, r0 + jmp @r0 + nop + + .align 2 +1: .long restore_all + + .align 2 +not_syscall_tra: + bra debug_trap + nop + + .align 2 +syscall_badsys: ! Bad syscall number + mov #-ENOSYS, r0 + bra resume_userspace + mov.l r0, @(OFF_R0,r15) ! Return value + + +/* + * Syscall interface: + * + * Syscall #: R3 + * Arguments #0 to #3: R4--R7 + * Arguments #4 to #6: R0, R1, R2 + * TRA: (number of arguments + 0x10) x 4 + * + * This code also handles delegating other traps to the BIOS/gdb stub + * according to: + * + * Trap number + * (TRA>>2) Purpose + * -------- ------- + * 0x0-0xf old syscall ABI + * 0x10-0x1f new syscall ABI + * 0x20-0xff delegated through debug_trap to BIOS/gdb stub. + * + * Note: When we're first called, the TRA value must be shifted + * right 2 bits in order to get the value that was used as the "trapa" + * argument. + */ + + .align 2 + .globl ret_from_fork +ret_from_fork: + mov.l 1f, r8 + jsr @r8 + mov r0, r4 + bra syscall_exit + nop + .align 2 +1: .long schedule_tail + ! +ENTRY(system_call) +#if !defined(CONFIG_CPU_SH2) + mov.l 1f, r9 + mov.l @r9, r8 ! Read from TRA (Trap Address) Register +#endif + ! + ! Is the trap argument >= 0x20? (TRA will be >= 0x80) + mov #0x7f, r9 + cmp/hi r9, r8 + bt/s not_syscall_tra + mov #OFF_TRA, r9 + add r15, r9 + mov.l r8, @r9 ! set TRA value to tra +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r10 + jsr @r10 + nop +#endif + sti + + ! + get_current_thread_info r8, r10 + mov.l @(TI_FLAGS,r8), r8 + mov #_TIF_SYSCALL_TRACE, r10 + tst r10, r8 + bf syscall_trace_entry + ! + mov.l 2f, r8 ! Number of syscalls + cmp/hs r8, r3 + bt syscall_badsys + ! +syscall_call: + shll2 r3 ! x4 + mov.l 3f, r8 ! Load the address of sys_call_table + add r8, r3 + mov.l @r3, r8 + jsr @r8 ! jump to specific syscall handler + nop + mov.l @(OFF_R0,r15), r12 ! save r0 + mov.l r0, @(OFF_R0,r15) ! save the return value + ! +syscall_exit: + cli +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 6f, r0 + jsr @r0 + nop +#endif + ! + get_current_thread_info r8, r0 + mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags + tst #_TIF_ALLWORK_MASK, r0 + bf syscall_exit_work + bra __restore_all + nop + .align 2 +#if !defined(CONFIG_CPU_SH2) +1: .long TRA +#endif +2: .long NR_syscalls +3: .long sys_call_table +4: .long do_syscall_trace +#ifdef CONFIG_TRACE_IRQFLAGS +5: .long trace_hardirqs_on +6: .long trace_hardirqs_off +#endif diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S index f5f53d14f24..6aca4bc6ec5 100644 --- a/arch/sh/kernel/head.S +++ b/arch/sh/kernel/head.S @@ -33,7 +33,7 @@ ENTRY(empty_zero_page) .long 0x00360000 /* INITRD_START */ .long 0x000a0000 /* INITRD_SIZE */ .long 0 - .balign 4096,0,4096 + .balign PAGE_SIZE,0,PAGE_SIZE .text /* @@ -53,8 +53,10 @@ ENTRY(_stext) ldc r0, sr ! Initialize global interrupt mask mov #0, r0 +#ifdef CONFIG_CPU_HAS_SR_RB ldc r0, r6_bank - +#endif + /* * Prefetch if possible to reduce cache miss penalty. * @@ -68,11 +70,14 @@ ENTRY(_stext) ! mov.l 2f, r0 mov r0, r15 ! Set initial r15 (stack pointer) - mov #(THREAD_SIZE >> 8), r1 + mov #(THREAD_SIZE >> 10), r1 shll8 r1 ! r1 = THREAD_SIZE + shll2 r1 sub r1, r0 ! +#ifdef CONFIG_CPU_HAS_SR_RB ldc r0, r7_bank ! ... and initial thread_info - +#endif + ! Clear BSS area mov.l 3f, r1 add #4, r1 @@ -95,7 +100,11 @@ ENTRY(_stext) nop .balign 4 +#if defined(CONFIG_CPU_SH2) +1: .long 0x000000F0 ! IMASK=0xF +#else 1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF +#endif 2: .long init_thread_union+THREAD_SIZE 3: .long __bss_start 4: .long _end diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 944128ce970..67be2b6e8cd 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -12,7 +12,7 @@ #include <linux/kernel_stat.h> #include <linux/seq_file.h> #include <linux/io.h> -#include <asm/irq.h> +#include <linux/irq.h> #include <asm/processor.h> #include <asm/uaccess.h> #include <asm/thread_info.h> @@ -78,15 +78,16 @@ union irq_ctx { u32 stack[THREAD_SIZE/sizeof(u32)]; }; -static union irq_ctx *hardirq_ctx[NR_CPUS]; -static union irq_ctx *softirq_ctx[NR_CPUS]; +static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly; +static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; #endif asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { - struct pt_regs *old_regs = set_irq_regs(®s); + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + struct pt_regs *old_regs = set_irq_regs(regs); int irq; #ifdef CONFIG_4KSTACKS union irq_ctx *curctx, *irqctx; @@ -111,7 +112,7 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, #endif #ifdef CONFIG_CPU_HAS_INTEVT - irq = (ctrl_inl(INTEVT) >> 5) - 16; + irq = evt2irq(ctrl_inl(INTEVT)); #else irq = r4; #endif @@ -135,17 +136,24 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, irqctx->tinfo.task = curctx->tinfo.task; irqctx->tinfo.previous_sp = current_stack_pointer; + /* + * Copy the softirq bits in preempt_count so that the + * softirq checks work in the hardirq context. + */ + irqctx->tinfo.preempt_count = + (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) | + (curctx->tinfo.preempt_count & SOFTIRQ_MASK); + __asm__ __volatile__ ( "mov %0, r4 \n" - "mov r15, r9 \n" + "mov r15, r8 \n" "jsr @%1 \n" /* swith to the irq stack */ " mov %2, r15 \n" /* restore the stack (ring zero) */ - "mov r9, r15 \n" + "mov r8, r15 \n" : /* no outputs */ : "r" (irq), "r" (generic_handle_irq), "r" (isp) - /* XXX: A somewhat excessive clobber list? -PFM */ : "memory", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "t", "pr" ); @@ -193,7 +201,7 @@ void irq_ctx_init(int cpu) irqctx->tinfo.task = NULL; irqctx->tinfo.exec_domain = NULL; irqctx->tinfo.cpu = cpu; - irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET; + irqctx->tinfo.preempt_count = 0; irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); softirq_ctx[cpu] = irqctx; @@ -239,13 +247,38 @@ asmlinkage void do_softirq(void) "mov r9, r15 \n" : /* no outputs */ : "r" (__do_softirq), "r" (isp) - /* XXX: A somewhat excessive clobber list? -PFM */ : "memory", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" ); + + /* + * Shouldnt happen, we returned above if in_interrupt(): + */ + WARN_ON_ONCE(softirq_count()); } local_irq_restore(flags); } EXPORT_SYMBOL(do_softirq); #endif + +void __init init_IRQ(void) +{ +#ifdef CONFIG_CPU_HAS_PINT_IRQ + init_IRQ_pint(); +#endif + +#ifdef CONFIG_CPU_HAS_INTC2_IRQ + init_IRQ_intc2(); +#endif + +#ifdef CONFIG_CPU_HAS_IPR_IRQ + init_IRQ_ipr(); +#endif + + /* Perform the machine specific initialisation */ + if (sh_mv.mv_init_irq) + sh_mv.mv_init_irq(); + + irq_ctx_init(smp_processor_id()); +} diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index a52b13ac6b7..f3e2631be14 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -385,10 +385,11 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne asmlinkage int sys_fork(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); #ifdef CONFIG_MMU - return do_fork(SIGCHLD, regs.regs[15], ®s, 0, NULL, NULL); + return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL); #else /* fork almost works, enough to trick you into looking elsewhere :-( */ return -EINVAL; @@ -398,11 +399,12 @@ asmlinkage int sys_fork(unsigned long r4, unsigned long r5, asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, unsigned long parent_tidptr, unsigned long child_tidptr, - struct pt_regs regs) + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); if (!newsp) - newsp = regs.regs[15]; - return do_fork(clone_flags, newsp, ®s, 0, + newsp = regs->regs[15]; + return do_fork(clone_flags, newsp, regs, 0, (int __user *)parent_tidptr, (int __user *)child_tidptr); } @@ -418,9 +420,10 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, */ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], ®s, + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs, 0, NULL, NULL); } @@ -429,8 +432,9 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, */ asmlinkage int sys_execve(char *ufilename, char **uargv, char **uenvp, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); int error; char *filename; @@ -442,7 +446,7 @@ asmlinkage int sys_execve(char *ufilename, char **uargv, error = do_execve(filename, (char __user * __user *)uargv, (char __user * __user *)uenvp, - ®s); + regs); if (error == 0) { task_lock(current); current->ptrace &= ~PT_DTRACE; @@ -472,9 +476,7 @@ unsigned long get_wchan(struct task_struct *p) return pc; } -asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs regs) +asmlinkage void break_point_trap(void) { /* Clear tracing. */ #if defined(CONFIG_CPU_SH4A) @@ -492,8 +494,10 @@ asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { - regs.pc -= 2; + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + + regs->pc -= 2; force_sig(SIGTRAP, current); } diff --git a/arch/sh/kernel/relocate_kernel.S b/arch/sh/kernel/relocate_kernel.S index 8221b37c977..c66cb3209db 100644 --- a/arch/sh/kernel/relocate_kernel.S +++ b/arch/sh/kernel/relocate_kernel.S @@ -7,11 +7,9 @@ * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ - #include <linux/linkage.h> - -#define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */ - +#include <asm/addrspace.h> +#include <asm/page.h> .globl relocate_new_kernel relocate_new_kernel: @@ -20,8 +18,8 @@ relocate_new_kernel: /* r6 = start_address */ /* r7 = vbr_reg */ - mov.l 10f,r8 /* 4096 */ - mov.l 11f,r9 /* 0xa0000000 */ + mov.l 10f,r8 /* PAGE_SIZE */ + mov.l 11f,r9 /* P2SEG */ /* stack setting */ add r8,r5 @@ -32,7 +30,7 @@ relocate_new_kernel: 0: mov.l @r4+,r0 /* cmd = *ind++ */ -1: /* addr = (cmd | 0xa0000000) & 0xfffffff0 */ +1: /* addr = (cmd | P2SEG) & 0xfffffff0 */ mov r0,r2 or r9,r2 mov #-16,r1 @@ -92,7 +90,7 @@ relocate_new_kernel: 10: .long PAGE_SIZE 11: - .long 0xa0000000 + .long P2SEG relocate_new_kernel_end: diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 36d86f9ac38..696ca75752d 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -392,6 +392,7 @@ static int __init topology_init(void) subsys_initcall(topology_init); static const char *cpu_name[] = { + [CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619", [CPU_SH7604] = "SH7604", [CPU_SH7300] = "SH7300", [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706", [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708", @@ -404,6 +405,7 @@ static const char *cpu_name[] = { [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501", [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780", [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343", + [CPU_SH7785] = "SH7785", [CPU_SH_NONE] = "Unknown" }; diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c index 8a2fd19dc9e..c706f3bfd89 100644 --- a/arch/sh/kernel/sh_ksyms.c +++ b/arch/sh/kernel/sh_ksyms.c @@ -73,8 +73,6 @@ DECLARE_EXPORT(__lshrdi3); DECLARE_EXPORT(__movstr); DECLARE_EXPORT(__movstrSI16); -EXPORT_SYMBOL(strcpy); - #ifdef CONFIG_CPU_SH4 DECLARE_EXPORT(__movstr_i4_even); DECLARE_EXPORT(__movstr_i4_odd); diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index 5213f5bc6ce..50d7c4993be 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c @@ -37,7 +37,7 @@ asmlinkage int sys_sigsuspend(old_sigset_t mask, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { mask &= _BLOCKABLE; spin_lock_irq(¤t->sighand->siglock); @@ -52,7 +52,7 @@ sys_sigsuspend(old_sigset_t mask, return -ERESTARTNOHAND; } -asmlinkage int +asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user *act, struct old_sigaction __user *oact) { @@ -87,9 +87,11 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { - return do_sigaltstack(uss, uoss, regs.regs[15]); + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + + return do_sigaltstack(uss, uoss, regs->regs[15]); } @@ -98,7 +100,11 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, */ #define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ -#define TRAP16 0xc310 /* Syscall w/no args (NR in R3) */ +#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A) +#define TRAP_NOARG 0xc320 /* Syscall w/no args (NR in R3) */ +#else +#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) */ +#endif #define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */ struct sigframe @@ -194,9 +200,10 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { - struct sigframe __user *frame = (struct sigframe __user *)regs.regs[15]; + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + struct sigframe __user *frame = (struct sigframe __user *)regs->regs[15]; sigset_t set; int r0; @@ -216,7 +223,7 @@ asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->sc, &r0)) + if (restore_sigcontext(regs, &frame->sc, &r0)) goto badframe; return r0; @@ -227,9 +234,10 @@ badframe: asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { - struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs.regs[15]; + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15]; sigset_t set; stack_t st; int r0; @@ -246,14 +254,14 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &r0)) + if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) goto badframe; if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs.regs[15]); + do_sigaltstack(&st, NULL, regs->regs[15]); return r0; @@ -350,7 +358,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, } else { /* Generate return code (system call to sigreturn) */ err |= __put_user(MOVW(7), &frame->retcode[0]); - err |= __put_user(TRAP16, &frame->retcode[1]); + err |= __put_user(TRAP_NOARG, &frame->retcode[1]); err |= __put_user(OR_R0_R0, &frame->retcode[2]); err |= __put_user(OR_R0_R0, &frame->retcode[3]); err |= __put_user(OR_R0_R0, &frame->retcode[4]); @@ -430,7 +438,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, } else { /* Generate return code (system call to rt_sigreturn) */ err |= __put_user(MOVW(7), &frame->retcode[0]); - err |= __put_user(TRAP16, &frame->retcode[1]); + err |= __put_user(TRAP_NOARG, &frame->retcode[1]); err |= __put_user(OR_R0_R0, &frame->retcode[2]); err |= __put_user(OR_R0_R0, &frame->retcode[3]); err |= __put_user(OR_R0_R0, &frame->retcode[4]); diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c new file mode 100644 index 00000000000..0d5268afe80 --- /dev/null +++ b/arch/sh/kernel/stacktrace.c @@ -0,0 +1,43 @@ +/* + * arch/sh/kernel/stacktrace.c + * + * Stack trace management functions + * + * Copyright (C) 2006 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/sched.h> +#include <linux/stacktrace.h> +#include <linux/thread_info.h> +#include <asm/ptrace.h> + +/* + * Save stack-backtrace addresses into a stack_trace buffer. + */ +void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +{ + unsigned long *sp; + + if (!task) + task = current; + if (task == current) + sp = (unsigned long *)current_stack_pointer; + else + sp = (unsigned long *)task->thread.sp; + + while (!kstack_end(sp)) { + unsigned long addr = *sp++; + + if (__kernel_text_address(addr)) { + if (trace->skip > 0) + trace->skip--; + else + trace->entries[trace->nr_entries++] = addr; + if (trace->nr_entries >= trace->max_entries) + break; + } + } +} diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index 8fde95001c3..5083b6ed4b3 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -33,14 +33,15 @@ */ asmlinkage int sys_pipe(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); int fd[2]; int error; error = do_pipe(fd); if (!error) { - regs.regs[1] = fd[1]; + regs->regs[1] = fd[1]; return fd[0]; } return error; @@ -50,6 +51,7 @@ unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ EXPORT_SYMBOL(shm_align_mask); +#ifdef CONFIG_MMU /* * To avoid cache aliases, we map the shared page with same color. */ @@ -135,6 +137,7 @@ full_search: addr = COLOUR_ALIGN(addr, pgoff); } } +#endif /* CONFIG_MMU */ static inline long do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 57e708d7b52..c206c9504c4 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -13,6 +13,8 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/profile.h> +#include <linux/timex.h> +#include <linux/sched.h> #include <asm/clock.h> #include <asm/rtc.h> #include <asm/timer.h> @@ -50,15 +52,20 @@ unsigned long long __attribute__ ((weak)) sched_clock(void) #ifndef CONFIG_GENERIC_TIME void do_gettimeofday(struct timeval *tv) { + unsigned long flags; unsigned long seq; unsigned long usec, sec; do { - seq = read_seqbegin(&xtime_lock); + /* + * Turn off IRQs when grabbing xtime_lock, so that + * the sys_timer get_offset code doesn't have to handle it. + */ + seq = read_seqbegin_irqsave(&xtime_lock, flags); usec = get_timer_offset(); sec = xtime.tv_sec; - usec += xtime.tv_nsec / 1000; - } while (read_seqretry(&xtime_lock, seq)); + usec += xtime.tv_nsec / NSEC_PER_USEC; + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); while (usec >= 1000000) { usec -= 1000000; @@ -85,7 +92,7 @@ int do_settimeofday(struct timespec *tv) * wall time. Discover what correction gettimeofday() would have * made, and then undo it! */ - nsec -= 1000 * get_timer_offset(); + nsec -= get_timer_offset() * NSEC_PER_USEC; wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); @@ -169,6 +176,108 @@ static struct sysdev_class timer_sysclass = { .resume = timer_resume, }; +#ifdef CONFIG_NO_IDLE_HZ +static int timer_dyn_tick_enable(void) +{ + struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick; + unsigned long flags; + int ret = -ENODEV; + + if (dyn_tick) { + spin_lock_irqsave(&dyn_tick->lock, flags); + ret = 0; + if (!(dyn_tick->state & DYN_TICK_ENABLED)) { + ret = dyn_tick->enable(); + + if (ret == 0) + dyn_tick->state |= DYN_TICK_ENABLED; + } + spin_unlock_irqrestore(&dyn_tick->lock, flags); + } + + return ret; +} + +static int timer_dyn_tick_disable(void) +{ + struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick; + unsigned long flags; + int ret = -ENODEV; + + if (dyn_tick) { + spin_lock_irqsave(&dyn_tick->lock, flags); + ret = 0; + if (dyn_tick->state & DYN_TICK_ENABLED) { + ret = dyn_tick->disable(); + + if (ret == 0) + dyn_tick->state &= ~DYN_TICK_ENABLED; + } + spin_unlock_irqrestore(&dyn_tick->lock, flags); + } + + return ret; +} + +/* + * Reprogram the system timer for at least the calculated time interval. + * This function should be called from the idle thread with IRQs disabled, + * immediately before sleeping. + */ +void timer_dyn_reprogram(void) +{ + struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick; + unsigned long next, seq, flags; + + if (!dyn_tick) + return; + + spin_lock_irqsave(&dyn_tick->lock, flags); + if (dyn_tick->state & DYN_TICK_ENABLED) { + next = next_timer_interrupt(); + do { + seq = read_seqbegin(&xtime_lock); + dyn_tick->reprogram(next - jiffies); + } while (read_seqretry(&xtime_lock, seq)); + } + spin_unlock_irqrestore(&dyn_tick->lock, flags); +} + +static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf) +{ + return sprintf(buf, "%i\n", + (sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1); +} + +static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf, + size_t count) +{ + unsigned int enable = simple_strtoul(buf, NULL, 2); + + if (enable) + timer_dyn_tick_enable(); + else + timer_dyn_tick_disable(); + + return count; +} +static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick); + +/* + * dyntick=enable|disable + */ +static char dyntick_str[4] __initdata = ""; + +static int __init dyntick_setup(char *str) +{ + if (str) + strlcpy(dyntick_str, str, sizeof(dyntick_str)); + return 1; +} + +__setup("dyntick=", dyntick_setup); +#endif + static int __init timer_init_sysfs(void) { int ret = sysdev_class_register(&timer_sysclass); @@ -176,7 +285,22 @@ static int __init timer_init_sysfs(void) return ret; sys_timer->dev.cls = &timer_sysclass; - return sysdev_register(&sys_timer->dev); + ret = sysdev_register(&sys_timer->dev); + +#ifdef CONFIG_NO_IDLE_HZ + if (ret == 0 && sys_timer->dyn_tick) { + ret = sysdev_create_file(&sys_timer->dev, &attr_dyn_tick); + + /* + * Turn on dynamic tick after calibrate delay + * for correct bogomips + */ + if (ret == 0 && dyntick_str[0] == 'e') + ret = timer_dyn_tick_enable(); + } +#endif + + return ret; } device_initcall(timer_init_sysfs); @@ -200,6 +324,11 @@ void __init time_init(void) sys_timer = get_sys_timer(); printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); +#ifdef CONFIG_NO_IDLE_HZ + if (sys_timer->dyn_tick) + spin_lock_init(&sys_timer->dyn_tick->lock); +#endif + #if defined(CONFIG_SH_KGDB) /* * Set up kgdb as requested. We do it here because the serial diff --git a/arch/sh/kernel/timers/Makefile b/arch/sh/kernel/timers/Makefile index 151a6a304ce..bcf244ff6a1 100644 --- a/arch/sh/kernel/timers/Makefile +++ b/arch/sh/kernel/timers/Makefile @@ -5,4 +5,6 @@ obj-y := timer.o obj-$(CONFIG_SH_TMU) += timer-tmu.o +obj-$(CONFIG_SH_MTU2) += timer-mtu2.o +obj-$(CONFIG_SH_CMT) += timer-cmt.o diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c new file mode 100644 index 00000000000..a574b93a4e7 --- /dev/null +++ b/arch/sh/kernel/timers/timer-cmt.c @@ -0,0 +1,196 @@ +/* + * arch/sh/kernel/timers/timer-cmt.c - CMT Timer Support + * + * Copyright (C) 2005 Yoshinori Sato + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/seqlock.h> +#include <asm/timer.h> +#include <asm/rtc.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/clock.h> + +#if defined(CONFIG_CPU_SUBTYPE_SH7619) +#define CMT_CMSTR 0xf84a0070 +#define CMT_CMCSR_0 0xf84a0072 +#define CMT_CMCNT_0 0xf84a0074 +#define CMT_CMCOR_0 0xf84a0076 +#define CMT_CMCSR_1 0xf84a0078 +#define CMT_CMCNT_1 0xf84a007a +#define CMT_CMCOR_1 0xf84a007c + +#define STBCR3 0xf80a0000 +#define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR3) & ~0x10, STBCR3); } while(0) +#define CMT_CMCSR_INIT 0x0040 +#define CMT_CMCSR_CALIB 0x0000 +#elif defined(CONFIG_CPU_SUBTYPE_SH7206) +#define CMT_CMSTR 0xfffec000 +#define CMT_CMCSR_0 0xfffec002 +#define CMT_CMCNT_0 0xfffec004 +#define CMT_CMCOR_0 0xfffec006 + +#define STBCR4 0xfffe040c +#define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR4) & ~0x04, STBCR4); } while(0) +#define CMT_CMCSR_INIT 0x0040 +#define CMT_CMCSR_CALIB 0x0000 +#else +#error "Unknown CPU SUBTYPE" +#endif + +static unsigned long cmt_timer_get_offset(void) +{ + int count; + static unsigned short count_p = 0xffff; /* for the first call after boot */ + static unsigned long jiffies_p = 0; + + /* + * cache volatile jiffies temporarily; we have IRQs turned off. + */ + unsigned long jiffies_t; + + /* timer count may underflow right here */ + count = ctrl_inw(CMT_CMCOR_0); + count -= ctrl_inw(CMT_CMCNT_0); + + jiffies_t = jiffies; + + /* + * avoiding timer inconsistencies (they are rare, but they happen)... + * there is one kind of problem that must be avoided here: + * 1. the timer counter underflows + */ + + if (jiffies_t == jiffies_p) { + if (count > count_p) { + /* the nutcase */ + if (ctrl_inw(CMT_CMCSR_0) & 0x80) { /* Check CMF bit */ + count -= LATCH; + } else { + printk("%s (): hardware timer problem?\n", + __FUNCTION__); + } + } + } else + jiffies_p = jiffies_t; + + count_p = count; + + count = ((LATCH-1) - count) * TICK_SIZE; + count = (count + LATCH/2) / LATCH; + + return count; +} + +static irqreturn_t cmt_timer_interrupt(int irq, void *dev_id) +{ + unsigned long timer_status; + + /* Clear CMF bit */ + timer_status = ctrl_inw(CMT_CMCSR_0); + timer_status &= ~0x80; + ctrl_outw(timer_status, CMT_CMCSR_0); + + /* + * Here we are in the timer irq handler. We just have irqs locally + * disabled but we don't know if the timer_bh is running on the other + * CPU. We need to avoid to SMP race with it. NOTE: we don' t need + * the irq version of write_lock because as just said we have irq + * locally disabled. -arca + */ + write_seqlock(&xtime_lock); + handle_timer_tick(); + write_sequnlock(&xtime_lock); + + return IRQ_HANDLED; +} + +static struct irqaction cmt_irq = { + .name = "timer", + .handler = cmt_timer_interrupt, + .flags = IRQF_DISABLED | IRQF_TIMER, + .mask = CPU_MASK_NONE, +}; + +static void cmt_clk_init(struct clk *clk) +{ + u8 divisor = CMT_CMCSR_INIT & 0x3; + ctrl_inw(CMT_CMCSR_0); + ctrl_outw(CMT_CMCSR_INIT, CMT_CMCSR_0); + clk->parent = clk_get(NULL, "module_clk"); + clk->rate = clk->parent->rate / (8 << (divisor << 1)); +} + +static void cmt_clk_recalc(struct clk *clk) +{ + u8 divisor = ctrl_inw(CMT_CMCSR_0) & 0x3; + clk->rate = clk->parent->rate / (8 << (divisor << 1)); +} + +static struct clk_ops cmt_clk_ops = { + .init = cmt_clk_init, + .recalc = cmt_clk_recalc, +}; + +static struct clk cmt0_clk = { + .name = "cmt0_clk", + .ops = &cmt_clk_ops, +}; + +static int cmt_timer_start(void) +{ + ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR); + return 0; +} + +static int cmt_timer_stop(void) +{ + ctrl_outw(ctrl_inw(CMT_CMSTR) & ~0x01, CMT_CMSTR); + return 0; +} + +static int cmt_timer_init(void) +{ + unsigned long interval; + + cmt_clock_enable(); + + setup_irq(CONFIG_SH_TIMER_IRQ, &cmt_irq); + + cmt0_clk.parent = clk_get(NULL, "module_clk"); + + cmt_timer_stop(); + + interval = cmt0_clk.parent->rate / 8 / HZ; + printk(KERN_INFO "Interval = %ld\n", interval); + + ctrl_outw(interval, CMT_CMCOR_0); + + clk_register(&cmt0_clk); + clk_enable(&cmt0_clk); + + cmt_timer_start(); + + return 0; +} + +struct sys_timer_ops cmt_timer_ops = { + .init = cmt_timer_init, + .start = cmt_timer_start, + .stop = cmt_timer_stop, +#ifndef CONFIG_GENERIC_TIME + .get_offset = cmt_timer_get_offset, +#endif +}; + +struct sys_timer cmt_timer = { + .name = "cmt", + .ops = &cmt_timer_ops, +}; diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c new file mode 100644 index 00000000000..fffcd1c0987 --- /dev/null +++ b/arch/sh/kernel/timers/timer-mtu2.c @@ -0,0 +1,200 @@ +/* + * arch/sh/kernel/timers/timer-mtu2.c - MTU2 Timer Support + * + * Copyright (C) 2005 Paul Mundt + * + * Based off of arch/sh/kernel/timers/timer-tmu.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/seqlock.h> +#include <asm/timer.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/clock.h> + +/* + * We use channel 1 for our lowly system timer. Channel 2 would be the other + * likely candidate, but we leave it alone as it has higher divisors that + * would be of more use to other more interesting applications. + * + * TODO: Presently we only implement a 16-bit single-channel system timer. + * However, we can implement channel cascade if we go the overflow route and + * get away with using 2 MTU2 channels as a 32-bit timer. + */ +#define MTU2_TSTR 0xfffe4280 +#define MTU2_TCR_1 0xfffe4380 +#define MTU2_TMDR_1 0xfffe4381 +#define MTU2_TIOR_1 0xfffe4382 +#define MTU2_TIER_1 0xfffe4384 +#define MTU2_TSR_1 0xfffe4385 +#define MTU2_TCNT_1 0xfffe4386 /* 16-bit counter */ +#define MTU2_TGRA_1 0xfffe438a + +#define STBCR3 0xfffe0408 + +#define MTU2_TSTR_CST1 (1 << 1) /* Counter Start 1 */ + +#define MTU2_TSR_TGFA (1 << 0) /* GRA compare match */ + +#define MTU2_TIER_TGIEA (1 << 0) /* GRA compare match interrupt enable */ + +#define MTU2_TCR_INIT 0x22 + +#define MTU2_TCR_CALIB 0x00 + +static unsigned long mtu2_timer_get_offset(void) +{ + int count; + static int count_p = 0x7fff; /* for the first call after boot */ + static unsigned long jiffies_p = 0; + + /* + * cache volatile jiffies temporarily; we have IRQs turned off. + */ + unsigned long jiffies_t; + + /* timer count may underflow right here */ + count = ctrl_inw(MTU2_TCNT_1); /* read the latched count */ + + jiffies_t = jiffies; + + /* + * avoiding timer inconsistencies (they are rare, but they happen)... + * there is one kind of problem that must be avoided here: + * 1. the timer counter underflows + */ + + if (jiffies_t == jiffies_p) { + if (count > count_p) { + if (ctrl_inb(MTU2_TSR_1) & MTU2_TSR_TGFA) { + count -= LATCH; + } else { + printk("%s (): hardware timer problem?\n", + __FUNCTION__); + } + } + } else + jiffies_p = jiffies_t; + + count_p = count; + + count = ((LATCH-1) - count) * TICK_SIZE; + count = (count + LATCH/2) / LATCH; + + return count; +} + +static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id) +{ + unsigned long timer_status; + + /* Clear TGFA bit */ + timer_status = ctrl_inb(MTU2_TSR_1); + timer_status &= ~MTU2_TSR_TGFA; + ctrl_outb(timer_status, MTU2_TSR_1); + + /* Do timer tick */ + write_seqlock(&xtime_lock); + handle_timer_tick(); + write_sequnlock(&xtime_lock); + + return IRQ_HANDLED; +} + +static struct irqaction mtu2_irq = { + .name = "timer", + .handler = mtu2_timer_interrupt, + .flags = IRQF_DISABLED | IRQF_TIMER, + .mask = CPU_MASK_NONE, +}; + +static unsigned int divisors[] = { 1, 4, 16, 64, 1, 1, 256 }; + +static void mtu2_clk_init(struct clk *clk) +{ + u8 idx = MTU2_TCR_INIT & 0x7; + + clk->rate = clk->parent->rate / divisors[idx]; + /* Start TCNT counting */ + ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR); + +} + +static void mtu2_clk_recalc(struct clk *clk) +{ + u8 idx = ctrl_inb(MTU2_TCR_1) & 0x7; + clk->rate = clk->parent->rate / divisors[idx]; +} + +static struct clk_ops mtu2_clk_ops = { + .init = mtu2_clk_init, + .recalc = mtu2_clk_recalc, +}; + +static struct clk mtu2_clk1 = { + .name = "mtu2_clk1", + .ops = &mtu2_clk_ops, +}; + +static int mtu2_timer_start(void) +{ + ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR); + return 0; +} + +static int mtu2_timer_stop(void) +{ + ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR); + return 0; +} + +static int mtu2_timer_init(void) +{ + u8 tmp; + unsigned long interval; + + setup_irq(CONFIG_SH_TIMER_IRQ, &mtu2_irq); + + mtu2_clk1.parent = clk_get(NULL, "module_clk"); + + ctrl_outb(ctrl_inb(STBCR3) & (~0x20), STBCR3); + + /* Normal operation */ + ctrl_outb(0, MTU2_TMDR_1); + ctrl_outb(MTU2_TCR_INIT, MTU2_TCR_1); + ctrl_outb(0x01, MTU2_TIOR_1); + + /* Enable underflow interrupt */ + ctrl_outb(ctrl_inb(MTU2_TIER_1) | MTU2_TIER_TGIEA, MTU2_TIER_1); + + interval = CONFIG_SH_PCLK_FREQ / 16 / HZ; + printk(KERN_INFO "Interval = %ld\n", interval); + + ctrl_outw(interval, MTU2_TGRA_1); + ctrl_outw(0, MTU2_TCNT_1); + + clk_register(&mtu2_clk1); + clk_enable(&mtu2_clk1); + + return 0; +} + +struct sys_timer_ops mtu2_timer_ops = { + .init = mtu2_timer_init, + .start = mtu2_timer_start, + .stop = mtu2_timer_stop, +#ifndef CONFIG_GENERIC_TIME + .get_offset = mtu2_timer_get_offset, +#endif +}; + +struct sys_timer mtu2_timer = { + .name = "mtu2", + .ops = &mtu2_timer_ops, +}; diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c index 24927015dc3..e060e71d078 100644 --- a/arch/sh/kernel/timers/timer-tmu.c +++ b/arch/sh/kernel/timers/timer-tmu.c @@ -17,7 +17,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/interrupt.h> -#include <linux/spinlock.h> #include <linux/seqlock.h> #include <asm/timer.h> #include <asm/rtc.h> @@ -31,13 +30,9 @@ #define TMU0_TCR_CALIB 0x0000 -static DEFINE_SPINLOCK(tmu0_lock); - static unsigned long tmu_timer_get_offset(void) { int count; - unsigned long flags; - static int count_p = 0x7fffffff; /* for the first call after boot */ static unsigned long jiffies_p = 0; @@ -46,7 +41,6 @@ static unsigned long tmu_timer_get_offset(void) */ unsigned long jiffies_t; - spin_lock_irqsave(&tmu0_lock, flags); /* timer count may underflow right here */ count = ctrl_inl(TMU0_TCNT); /* read the latched count */ @@ -72,7 +66,6 @@ static unsigned long tmu_timer_get_offset(void) jiffies_p = jiffies_t; count_p = count; - spin_unlock_irqrestore(&tmu0_lock, flags); count = ((LATCH-1) - count) * TICK_SIZE; count = (count + LATCH/2) / LATCH; @@ -106,7 +99,7 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy) static struct irqaction tmu_irq = { .name = "timer", .handler = tmu_timer_interrupt, - .flags = IRQF_DISABLED, + .flags = IRQF_DISABLED | IRQF_TIMER, .mask = CPU_MASK_NONE, }; @@ -149,9 +142,9 @@ static int tmu_timer_init(void) { unsigned long interval; - setup_irq(TIMER_IRQ, &tmu_irq); + setup_irq(CONFIG_SH_TIMER_IRQ, &tmu_irq); - tmu0_clk.parent = clk_get("module_clk"); + tmu0_clk.parent = clk_get(NULL, "module_clk"); /* Start TMU0 */ tmu_timer_stop(); diff --git a/arch/sh/kernel/timers/timer.c b/arch/sh/kernel/timers/timer.c index dc1f631053a..a6bcc913d25 100644 --- a/arch/sh/kernel/timers/timer.c +++ b/arch/sh/kernel/timers/timer.c @@ -17,6 +17,12 @@ static struct sys_timer *sys_timers[] __initdata = { #ifdef CONFIG_SH_TMU &tmu_timer, #endif +#ifdef CONFIG_SH_MTU2 + &mtu2_timer, +#endif +#ifdef CONFIG_SH_CMT + &cmt_timer, +#endif NULL, }; diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 53dfa55f315..3762d9dc204 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -18,13 +18,14 @@ #include <linux/module.h> #include <linux/kallsyms.h> #include <linux/io.h> +#include <linux/debug_locks.h> #include <asm/system.h> #include <asm/uaccess.h> #ifdef CONFIG_SH_KGDB #include <asm/kgdb.h> -#define CHK_REMOTE_DEBUG(regs) \ -{ \ +#define CHK_REMOTE_DEBUG(regs) \ +{ \ if (kgdb_debug_hook && !user_mode(regs))\ (*kgdb_debug_hook)(regs); \ } @@ -33,8 +34,13 @@ #endif #ifdef CONFIG_CPU_SH2 -#define TRAP_RESERVED_INST 4 -#define TRAP_ILLEGAL_SLOT_INST 6 +# define TRAP_RESERVED_INST 4 +# define TRAP_ILLEGAL_SLOT_INST 6 +# define TRAP_ADDRESS_ERROR 9 +# ifdef CONFIG_CPU_SH2A +# define TRAP_DIVZERO_ERROR 17 +# define TRAP_DIVOVF_ERROR 18 +# endif #else #define TRAP_RESERVED_INST 12 #define TRAP_ILLEGAL_SLOT_INST 13 @@ -88,7 +94,7 @@ void die(const char * str, struct pt_regs * regs, long err) if (!user_mode(regs) || in_interrupt()) dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + - (unsigned long)task_stack_page(current)); + (unsigned long)task_stack_page(current)); bust_spinlocks(0); spin_unlock_irq(&die_lock); @@ -102,8 +108,6 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs, die(str, regs, err); } -static int handle_unaligned_notify_count = 10; - /* * try and fix up kernelspace address errors * - userspace errors just cause EFAULT to be returned, resulting in SEGV @@ -198,7 +202,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) if (copy_to_user(dst,src,4)) goto fetch_fault; ret = 0; - break; + break; case 2: /* mov.[bwl] to memory, possibly with pre-decrement */ if (instruction & 4) @@ -222,7 +226,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) if (copy_from_user(dst,src,4)) goto fetch_fault; ret = 0; - break; + break; case 6: /* mov.[bwl] from memory, possibly with post-increment */ src = (unsigned char*) *rm; @@ -230,7 +234,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) *rm += count; dst = (unsigned char*) rn; *(unsigned long*)dst = 0; - + #ifdef __LITTLE_ENDIAN__ if (copy_from_user(dst, src, count)) goto fetch_fault; @@ -241,7 +245,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) } #else dst += 4-count; - + if (copy_from_user(dst, src, count)) goto fetch_fault; @@ -320,7 +324,8 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) return -EFAULT; /* kernel */ - die("delay-slot-insn faulting in handle_unaligned_delayslot", regs, 0); + die("delay-slot-insn faulting in handle_unaligned_delayslot", + regs, 0); } return handle_unaligned_ins(instruction,regs); @@ -342,6 +347,13 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) #define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4) #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) +/* + * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit + * opcodes.. + */ +#ifndef CONFIG_CPU_SH2A +static int handle_unaligned_notify_count = 10; + static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) { u_int rm; @@ -354,7 +366,8 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) if (user_mode(regs) && handle_unaligned_notify_count>0) { handle_unaligned_notify_count--; - printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", + printk(KERN_NOTICE "Fixing up unaligned userspace access " + "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", current->comm,current->pid,(u16*)regs->pc,instruction); } @@ -478,32 +491,58 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) regs->pc += 2; return ret; } +#endif /* CONFIG_CPU_SH2A */ + +#ifdef CONFIG_CPU_HAS_SR_RB +#define lookup_exception_vector(x) \ + __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x))) +#else +#define lookup_exception_vector(x) \ + __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x))) +#endif /* - * Handle various address error exceptions + * Handle various address error exceptions: + * - instruction address error: + * misaligned PC + * PC >= 0x80000000 in user mode + * - data address error (read and write) + * misaligned data access + * access to >= 0x80000000 is user mode + * Unfortuntaly we can't distinguish between instruction address error + * and data address errors caused by read acceses. */ -asmlinkage void do_address_error(struct pt_regs *regs, +asmlinkage void do_address_error(struct pt_regs *regs, unsigned long writeaccess, unsigned long address) { - unsigned long error_code; + unsigned long error_code = 0; mm_segment_t oldfs; + siginfo_t info; +#ifndef CONFIG_CPU_SH2A u16 instruction; int tmp; +#endif - asm volatile("stc r2_bank,%0": "=r" (error_code)); + /* Intentional ifdef */ +#ifdef CONFIG_CPU_HAS_SR_RB + lookup_exception_vector(error_code); +#endif oldfs = get_fs(); if (user_mode(regs)) { + int si_code = BUS_ADRERR; + local_irq_enable(); - current->thread.error_code = error_code; - current->thread.trap_no = (writeaccess) ? 8 : 7; /* bad PC is not something we can fix */ - if (regs->pc & 1) + if (regs->pc & 1) { + si_code = BUS_ADRALN; goto uspace_segv; + } +#ifndef CONFIG_CPU_SH2A set_fs(USER_DS); if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { /* Argh. Fault on the instruction itself. @@ -518,14 +557,23 @@ asmlinkage void do_address_error(struct pt_regs *regs, if (tmp==0) return; /* sorted */ +#endif - uspace_segv: - printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm); - force_sig(SIGSEGV, current); +uspace_segv: + printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " + "access (PC %lx PR %lx)\n", current->comm, regs->pc, + regs->pr); + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = si_code; + info.si_addr = (void *) address; + force_sig_info(SIGBUS, &info, current); } else { if (regs->pc & 1) die("unaligned program counter", regs, error_code); +#ifndef CONFIG_CPU_SH2A set_fs(KERNEL_DS); if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { /* Argh. Fault on the instruction itself. @@ -537,6 +585,12 @@ asmlinkage void do_address_error(struct pt_regs *regs, handle_unaligned_access(instruction, regs); set_fs(oldfs); +#else + printk(KERN_NOTICE "Killing process \"%s\" due to unaligned " + "access\n", current->comm); + + force_sig(SIGSEGV, current); +#endif } } @@ -548,7 +602,7 @@ int is_dsp_inst(struct pt_regs *regs) { unsigned short inst; - /* + /* * Safe guard if DSP mode is already enabled or we're lacking * the DSP altogether. */ @@ -569,27 +623,49 @@ int is_dsp_inst(struct pt_regs *regs) #define is_dsp_inst(regs) (0) #endif /* CONFIG_SH_DSP */ +#ifdef CONFIG_CPU_SH2A +asmlinkage void do_divide_error(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs __regs) +{ + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + siginfo_t info; + + switch (r4) { + case TRAP_DIVZERO_ERROR: + info.si_code = FPE_INTDIV; + break; + case TRAP_DIVOVF_ERROR: + info.si_code = FPE_INTOVF; + break; + } + + force_sig_info(SIGFPE, &info, current); +} +#endif + /* arch/sh/kernel/cpu/sh4/fpu.c */ extern int do_fpu_inst(unsigned short, struct pt_regs *); extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, struct pt_regs regs); + unsigned long r6, unsigned long r7, struct pt_regs __regs); asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); unsigned long error_code; struct task_struct *tsk = current; #ifdef CONFIG_SH_FPU_EMU - unsigned short inst; + unsigned short inst = 0; int err; - get_user(inst, (unsigned short*)regs.pc); + get_user(inst, (unsigned short*)regs->pc); - err = do_fpu_inst(inst, ®s); + err = do_fpu_inst(inst, regs); if (!err) { - regs.pc += 2; + regs->pc += 2; return; } /* not a FPU inst. */ @@ -597,20 +673,19 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, #ifdef CONFIG_SH_DSP /* Check if it's a DSP instruction */ - if (is_dsp_inst(®s)) { + if (is_dsp_inst(regs)) { /* Enable DSP mode, and restart instruction. */ - regs.sr |= SR_DSP; + regs->sr |= SR_DSP; return; } #endif - asm volatile("stc r2_bank, %0": "=r" (error_code)); + lookup_exception_vector(error_code); + local_irq_enable(); - tsk->thread.error_code = error_code; - tsk->thread.trap_no = TRAP_RESERVED_INST; - CHK_REMOTE_DEBUG(®s); + CHK_REMOTE_DEBUG(regs); force_sig(SIGILL, tsk); - die_if_no_fixup("reserved instruction", ®s, error_code); + die_if_no_fixup("reserved instruction", regs, error_code); } #ifdef CONFIG_SH_FPU_EMU @@ -658,39 +733,41 @@ static int emulate_branch(unsigned short inst, struct pt_regs* regs) asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); unsigned long error_code; struct task_struct *tsk = current; #ifdef CONFIG_SH_FPU_EMU - unsigned short inst; + unsigned short inst = 0; - get_user(inst, (unsigned short *)regs.pc + 1); - if (!do_fpu_inst(inst, ®s)) { - get_user(inst, (unsigned short *)regs.pc); - if (!emulate_branch(inst, ®s)) + get_user(inst, (unsigned short *)regs->pc + 1); + if (!do_fpu_inst(inst, regs)) { + get_user(inst, (unsigned short *)regs->pc); + if (!emulate_branch(inst, regs)) return; /* fault in branch.*/ } /* not a FPU inst. */ #endif - asm volatile("stc r2_bank, %0": "=r" (error_code)); + lookup_exception_vector(error_code); + local_irq_enable(); - tsk->thread.error_code = error_code; - tsk->thread.trap_no = TRAP_RESERVED_INST; - CHK_REMOTE_DEBUG(®s); + CHK_REMOTE_DEBUG(regs); force_sig(SIGILL, tsk); - die_if_no_fixup("illegal slot instruction", ®s, error_code); + die_if_no_fixup("illegal slot instruction", regs, error_code); } asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); long ex; - asm volatile("stc r2_bank, %0" : "=r" (ex)); - die_if_kernel("exception", ®s, ex); + + lookup_exception_vector(ex); + die_if_kernel("exception", regs, ex); } #if defined(CONFIG_SH_STANDARD_BIOS) @@ -735,12 +812,16 @@ void *set_exception_table_vec(unsigned int vec, void *handler) { extern void *exception_handling_table[]; void *old_handler; - + old_handler = exception_handling_table[vec]; exception_handling_table[vec] = handler; return old_handler; } +extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs __regs); + void __init trap_init(void) { set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst); @@ -759,7 +840,15 @@ void __init trap_init(void) set_exception_table_evt(0x800, do_fpu_state_restore); set_exception_table_evt(0x820, do_fpu_state_restore); #endif - + +#ifdef CONFIG_CPU_SH2 + set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_handler); +#endif +#ifdef CONFIG_CPU_SH2A + set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error); + set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error); +#endif + /* Setup VBR for boot cpu */ per_cpu_trap_init(); } @@ -784,6 +873,11 @@ void show_trace(struct task_struct *tsk, unsigned long *sp, } printk("\n"); + + if (!tsk) + tsk = current; + + debug_show_held_locks(tsk); } void show_stack(struct task_struct *tsk, unsigned long *sp) diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 9dd606464d2..4e0362f5038 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -4,8 +4,12 @@ menu "Processor selection" # Processor families # config CPU_SH2 + select SH_WRITETHROUGH if !CPU_SH2A bool - select SH_WRITETHROUGH + +config CPU_SH2A + bool + select CPU_SH2 config CPU_SH3 bool @@ -16,6 +20,7 @@ config CPU_SH4 bool select CPU_HAS_INTEVT select CPU_HAS_SR_RB + select CPU_HAS_PTEA if !CPU_SUBTYPE_ST40 config CPU_SH4A bool @@ -40,6 +45,16 @@ config CPU_SUBTYPE_SH7604 bool "Support SH7604 processor" select CPU_SH2 +config CPU_SUBTYPE_SH7619 + bool "Support SH7619 processor" + select CPU_SH2 + +comment "SH-2A Processor Support" + +config CPU_SUBTYPE_SH7206 + bool "Support SH7206 processor" + select CPU_SH2A + comment "SH-3 Processor Support" config CPU_SUBTYPE_SH7300 @@ -89,6 +104,7 @@ comment "SH-4 Processor Support" config CPU_SUBTYPE_SH7750 bool "Support SH7750 processor" select CPU_SH4 + select CPU_HAS_IPR_IRQ help Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU. @@ -104,15 +120,18 @@ config CPU_SUBTYPE_SH7750R bool "Support SH7750R processor" select CPU_SH4 select CPU_SUBTYPE_SH7750 + select CPU_HAS_IPR_IRQ config CPU_SUBTYPE_SH7750S bool "Support SH7750S processor" select CPU_SH4 select CPU_SUBTYPE_SH7750 + select CPU_HAS_IPR_IRQ config CPU_SUBTYPE_SH7751 bool "Support SH7751 processor" select CPU_SH4 + select CPU_HAS_IPR_IRQ help Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU, or if you have a HD6417751R CPU. @@ -121,6 +140,7 @@ config CPU_SUBTYPE_SH7751R bool "Support SH7751R processor" select CPU_SH4 select CPU_SUBTYPE_SH7751 + select CPU_HAS_IPR_IRQ config CPU_SUBTYPE_SH7760 bool "Support SH7760 processor" @@ -157,6 +177,11 @@ config CPU_SUBTYPE_SH7780 select CPU_SH4A select CPU_HAS_INTC2_IRQ +config CPU_SUBTYPE_SH7785 + bool "Support SH7785 processor" + select CPU_SH4A + select CPU_HAS_INTC2_IRQ + comment "SH4AL-DSP Processor Support" config CPU_SUBTYPE_SH73180 @@ -216,13 +241,22 @@ config MEMORY_SIZE config 32BIT bool "Support 32-bit physical addressing through PMB" - depends on CPU_SH4A && MMU + depends on CPU_SH4A && MMU && (!X2TLB || BROKEN) default y help If you say Y here, physical addressing will be extended to 32-bits through the SH-4A PMB. If this is not set, legacy 29-bit physical addressing will be used. +config X2TLB + bool "Enable extended TLB mode" + depends on CPU_SUBTYPE_SH7785 && MMU && EXPERIMENTAL + help + Selecting this option will enable the extended mode of the SH-X2 + TLB. For legacy SH-X behaviour and interoperability, say N. For + all of the fun new features and a willingless to submit bug reports, + say Y. + config VSYSCALL bool "Support vsyscall page" depends on MMU @@ -237,16 +271,52 @@ config VSYSCALL (the default value) say Y. choice + prompt "Kernel page size" + default PAGE_SIZE_4KB + +config PAGE_SIZE_4KB + bool "4kB" + help + This is the default page size used by all SuperH CPUs. + +config PAGE_SIZE_8KB + bool "8kB" + depends on EXPERIMENTAL && X2TLB + help + This enables 8kB pages as supported by SH-X2 and later MMUs. + +config PAGE_SIZE_64KB + bool "64kB" + depends on EXPERIMENTAL && CPU_SH4 + help + This enables support for 64kB pages, possible on all SH-4 + CPUs and later. Highly experimental, not recommended. + +endchoice + +choice prompt "HugeTLB page size" depends on HUGETLB_PAGE && CPU_SH4 && MMU default HUGETLB_PAGE_SIZE_64K config HUGETLB_PAGE_SIZE_64K - bool "64K" + bool "64kB" + +config HUGETLB_PAGE_SIZE_256K + bool "256kB" + depends on X2TLB config HUGETLB_PAGE_SIZE_1MB bool "1MB" +config HUGETLB_PAGE_SIZE_4MB + bool "4MB" + depends on X2TLB + +config HUGETLB_PAGE_SIZE_64MB + bool "64MB" + depends on X2TLB + endchoice source "mm/Kconfig" @@ -274,7 +344,6 @@ config SH_DIRECT_MAPPED config SH_WRITETHROUGH bool "Use write-through caching" - default y if CPU_SH2 help Selecting this option will configure the caches in write-through mode, as opposed to the default write-back configuration. diff --git a/arch/sh/mm/cache-sh2.c b/arch/sh/mm/cache-sh2.c index 2689cb24ea2..6614033f6be 100644 --- a/arch/sh/mm/cache-sh2.c +++ b/arch/sh/mm/cache-sh2.c @@ -5,6 +5,7 @@ * * Released under the terms of the GNU GPL v2.0. */ + #include <linux/init.h> #include <linux/mm.h> @@ -14,37 +15,43 @@ #include <asm/cacheflush.h> #include <asm/io.h> -/* - * Calculate the OC address and set the way bit on the SH-2. - * - * We must have already jump_to_P2()'ed prior to calling this - * function, since we rely on CCR manipulation to do the - * Right Thing(tm). - */ -unsigned long __get_oc_addr(unsigned long set, unsigned long way) +void __flush_wback_region(void *start, int size) { - unsigned long ccr; - - /* - * On SH-2 the way bit isn't tracked in the address field - * if we're doing address array access .. instead, we need - * to manually switch out the way in the CCR. - */ - ccr = ctrl_inl(CCR); - ccr &= ~0x00c0; - ccr |= way << cpu_data->dcache.way_shift; - - /* - * Despite the number of sets being halved, we end up losing - * the first 2 ways to OCRAM instead of the last 2 (if we're - * 4-way). As a result, forcibly setting the W1 bit handily - * bumps us up 2 ways. - */ - if (ccr & CCR_CACHE_ORA) - ccr |= 1 << (cpu_data->dcache.way_shift + 1); - - ctrl_outl(ccr, CCR); - - return CACHE_OC_ADDRESS_ARRAY | (set << cpu_data->dcache.entry_shift); + unsigned long v; + unsigned long begin, end; + + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) + & ~(L1_CACHE_BYTES-1); + for (v = begin; v < end; v+=L1_CACHE_BYTES) { + /* FIXME cache purge */ + ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); + } +} + +void __flush_purge_region(void *start, int size) +{ + unsigned long v; + unsigned long begin, end; + + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) + & ~(L1_CACHE_BYTES-1); + for (v = begin; v < end; v+=L1_CACHE_BYTES) { + ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); + } +} + +void __flush_invalidate_region(void *start, int size) +{ + unsigned long v; + unsigned long begin, end; + + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) + & ~(L1_CACHE_BYTES-1); + for (v = begin; v < end; v+=L1_CACHE_BYTES) { + ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); + } } diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index e48cc22724d..ae531affccb 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -11,12 +11,8 @@ */ #include <linux/init.h> #include <linux/mm.h> -#include <asm/addrspace.h> -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <asm/cache.h> -#include <asm/io.h> -#include <asm/pgalloc.h> +#include <linux/io.h> +#include <linux/mutex.h> #include <asm/mmu_context.h> #include <asm/cacheflush.h> @@ -83,9 +79,9 @@ static void __init emit_cache_params(void) */ /* Worst case assumed to be 64k cache, direct-mapped i.e. 4 synonym bits. */ -#define MAX_P3_SEMAPHORES 16 +#define MAX_P3_MUTEXES 16 -struct semaphore p3map_sem[MAX_P3_SEMAPHORES]; +struct mutex p3map_mutex[MAX_P3_MUTEXES]; void __init p3_cache_init(void) { @@ -115,7 +111,7 @@ void __init p3_cache_init(void) panic("%s failed.", __FUNCTION__); for (i = 0; i < cpu_data->dcache.n_aliases; i++) - sema_init(&p3map_sem[i], 1); + mutex_init(&p3map_mutex[i]); } /* @@ -229,7 +225,7 @@ static inline void flush_cache_4096(unsigned long start, */ if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG) || (start < CACHE_OC_ADDRESS_ARRAY)) - exec_offset = 0x20000000; + exec_offset = 0x20000000; local_irq_save(flags); __flush_cache_4096(start | SH_CACHE_ASSOC, @@ -250,7 +246,7 @@ void flush_dcache_page(struct page *page) /* Loop all the D-cache */ n = cpu_data->dcache.n_aliases; - for (i = 0; i < n; i++, addr += PAGE_SIZE) + for (i = 0; i < n; i++, addr += 4096) flush_cache_4096(addr, phys); } diff --git a/arch/sh/mm/clear_page.S b/arch/sh/mm/clear_page.S index 7b96425ae27..8a706131e52 100644 --- a/arch/sh/mm/clear_page.S +++ b/arch/sh/mm/clear_page.S @@ -1,12 +1,12 @@ -/* $Id: clear_page.S,v 1.13 2003/08/25 17:03:10 lethal Exp $ - * +/* * __clear_user_page, __clear_user, clear_page implementation of SuperH * * Copyright (C) 2001 Kaz Kojima * Copyright (C) 2001, 2002 Niibe Yutaka - * + * Copyright (C) 2006 Paul Mundt */ #include <linux/linkage.h> +#include <asm/page.h> /* * clear_page_slow @@ -18,11 +18,11 @@ /* * r0 --- scratch * r4 --- to - * r5 --- to + 4096 + * r5 --- to + PAGE_SIZE */ ENTRY(clear_page_slow) mov r4,r5 - mov.w .Llimit,r0 + mov.l .Llimit,r0 add r0,r5 mov #0,r0 ! @@ -50,7 +50,7 @@ ENTRY(clear_page_slow) ! rts nop -.Llimit: .word (4096-28) +.Llimit: .long (PAGE_SIZE-28) ENTRY(__clear_user) ! @@ -164,10 +164,10 @@ ENTRY(__clear_user) * r0 --- scratch * r4 --- to * r5 --- orig_to - * r6 --- to + 4096 + * r6 --- to + PAGE_SIZE */ ENTRY(__clear_user_page) - mov.w .L4096,r0 + mov.l .Lpsz,r0 mov r4,r6 add r0,r6 mov #0,r0 @@ -191,7 +191,7 @@ ENTRY(__clear_user_page) ! rts nop -.L4096: .word 4096 +.Lpsz: .long PAGE_SIZE #endif diff --git a/arch/sh/mm/copy_page.S b/arch/sh/mm/copy_page.S index 1addffe117c..397c94c9731 100644 --- a/arch/sh/mm/copy_page.S +++ b/arch/sh/mm/copy_page.S @@ -1,12 +1,12 @@ -/* $Id: copy_page.S,v 1.8 2003/08/25 17:03:10 lethal Exp $ - * +/* * copy_page, __copy_user_page, __copy_user implementation of SuperH * * Copyright (C) 2001 Niibe Yutaka & Kaz Kojima * Copyright (C) 2002 Toshinobu Sugioka - * + * Copyright (C) 2006 Paul Mundt */ #include <linux/linkage.h> +#include <asm/page.h> /* * copy_page_slow @@ -18,7 +18,7 @@ /* * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch - * r8 --- from + 4096 + * r8 --- from + PAGE_SIZE * r9 --- not used * r10 --- to * r11 --- from @@ -30,7 +30,7 @@ ENTRY(copy_page_slow) mov r4,r10 mov r5,r11 mov r5,r8 - mov.w .L4096,r0 + mov.l .Lpsz,r0 add r0,r8 ! 1: mov.l @r11+,r0 @@ -80,7 +80,7 @@ ENTRY(copy_page_slow) /* * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch - * r8 --- from + 4096 + * r8 --- from + PAGE_SIZE * r9 --- orig_to * r10 --- to * r11 --- from @@ -94,7 +94,7 @@ ENTRY(__copy_user_page) mov r5,r11 mov r6,r9 mov r5,r8 - mov.w .L4096,r0 + mov.l .Lpsz,r0 add r0,r8 ! 1: ocbi @r9 @@ -129,7 +129,7 @@ ENTRY(__copy_user_page) rts nop #endif -.L4096: .word 4096 +.Lpsz: .long PAGE_SIZE /* * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n); * Return the number of bytes NOT copied diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 68663b8f99a..716ebf568af 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -26,13 +26,19 @@ extern void die(const char *,struct pt_regs *,long); * and the problem, and then passes it off to one of the appropriate * routines. */ -asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, - unsigned long address) +asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, + unsigned long writeaccess, + unsigned long address) { struct task_struct *tsk; struct mm_struct *mm; struct vm_area_struct * vma; unsigned long page; + int si_code; + siginfo_t info; + + trace_hardirqs_on(); + local_irq_enable(); #ifdef CONFIG_SH_KGDB if (kgdb_nofault && kgdb_bus_err_hook) @@ -41,6 +47,46 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, tsk = current; mm = tsk->mm; + si_code = SEGV_MAPERR; + + if (unlikely(address >= TASK_SIZE)) { + /* + * Synchronize this task's top level page-table + * with the 'reference' page table. + * + * Do _not_ use "tsk" here. We might be inside + * an interrupt in the middle of a task switch.. + */ + int offset = pgd_index(address); + pgd_t *pgd, *pgd_k; + pud_t *pud, *pud_k; + pmd_t *pmd, *pmd_k; + + pgd = get_TTB() + offset; + pgd_k = swapper_pg_dir + offset; + + /* This will never happen with the folded page table. */ + if (!pgd_present(*pgd)) { + if (!pgd_present(*pgd_k)) + goto bad_area_nosemaphore; + set_pgd(pgd, *pgd_k); + return; + } + + pud = pud_offset(pgd, address); + pud_k = pud_offset(pgd_k, address); + if (pud_present(*pud) || !pud_present(*pud_k)) + goto bad_area_nosemaphore; + set_pud(pud, *pud_k); + + pmd = pmd_offset(pud, address); + pmd_k = pmd_offset(pud_k, address); + if (pmd_present(*pmd) || !pmd_present(*pmd_k)) + goto bad_area_nosemaphore; + set_pmd(pmd, *pmd_k); + + return; + } /* * If we're in an interrupt or have no user @@ -65,6 +111,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, * we can handle it.. */ good_area: + si_code = SEGV_ACCERR; if (writeaccess) { if (!(vma->vm_flags & VM_WRITE)) goto bad_area; @@ -104,10 +151,13 @@ survive: bad_area: up_read(&mm->mmap_sem); +bad_area_nosemaphore: if (user_mode(regs)) { - tsk->thread.address = address; - tsk->thread.error_code = writeaccess; - force_sig(SIGSEGV, tsk); + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = si_code; + info.si_addr = (void *) address; + force_sig_info(SIGSEGV, &info, tsk); return; } @@ -127,11 +177,9 @@ no_context: printk(KERN_ALERT "Unable to handle kernel paging request"); printk(" at virtual address %08lx\n", address); printk(KERN_ALERT "pc = %08lx\n", regs->pc); - asm volatile("mov.l %1, %0" - : "=r" (page) - : "m" (__m(MMU_TTB))); + page = (unsigned long)get_TTB(); if (page) { - page = ((unsigned long *) page)[address >> 22]; + page = ((unsigned long *) page)[address >> PGDIR_SHIFT]; printk(KERN_ALERT "*pde = %08lx\n", page); if (page & _PAGE_PRESENT) { page &= PAGE_MASK; @@ -166,98 +214,13 @@ do_sigbus: * Send a sigbus, regardless of whether we were in kernel * or user mode. */ - tsk->thread.address = address; - tsk->thread.error_code = writeaccess; - tsk->thread.trap_no = 14; - force_sig(SIGBUS, tsk); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + force_sig_info(SIGBUS, &info, tsk); /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) goto no_context; } - -#ifdef CONFIG_SH_STORE_QUEUES -/* - * This is a special case for the SH-4 store queues, as pages for this - * space still need to be faulted in before it's possible to flush the - * store queue cache for writeout to the remapped region. - */ -#define P3_ADDR_MAX (P4SEG_STORE_QUE + 0x04000000) -#else -#define P3_ADDR_MAX P4SEG -#endif - -/* - * Called with interrupts disabled. - */ -asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs, - unsigned long writeaccess, - unsigned long address) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - pte_t entry; - struct mm_struct *mm = current->mm; - spinlock_t *ptl; - int ret = 1; - -#ifdef CONFIG_SH_KGDB - if (kgdb_nofault && kgdb_bus_err_hook) - kgdb_bus_err_hook(); -#endif - - /* - * We don't take page faults for P1, P2, and parts of P4, these - * are always mapped, whether it be due to legacy behaviour in - * 29-bit mode, or due to PMB configuration in 32-bit mode. - */ - if (address >= P3SEG && address < P3_ADDR_MAX) { - pgd = pgd_offset_k(address); - mm = NULL; - } else { - if (unlikely(address >= TASK_SIZE || !mm)) - return 1; - - pgd = pgd_offset(mm, address); - } - - pud = pud_offset(pgd, address); - if (pud_none_or_clear_bad(pud)) - return 1; - pmd = pmd_offset(pud, address); - if (pmd_none_or_clear_bad(pmd)) - return 1; - - if (mm) - pte = pte_offset_map_lock(mm, pmd, address, &ptl); - else - pte = pte_offset_kernel(pmd, address); - - entry = *pte; - if (unlikely(pte_none(entry) || pte_not_present(entry))) - goto unlock; - if (unlikely(writeaccess && !pte_write(entry))) - goto unlock; - - if (writeaccess) - entry = pte_mkdirty(entry); - entry = pte_mkyoung(entry); - -#ifdef CONFIG_CPU_SH4 - /* - * ITLB is not affected by "ldtlb" instruction. - * So, we need to flush the entry by ourselves. - */ - __flush_tlb_page(get_asid(), address & PAGE_MASK); -#endif - - set_pte(pte, entry); - update_mmu_cache(NULL, address, entry); - ret = 0; -unlock: - if (mm) - pte_unmap_unlock(pte, ptl); - return ret; -} diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 7154d1ce978..59f4cc18235 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -84,30 +84,22 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) pmd_t *pmd; pte_t *pte; - pgd = swapper_pg_dir + pgd_index(addr); + pgd = pgd_offset_k(addr); if (pgd_none(*pgd)) { pgd_ERROR(*pgd); return; } - pud = pud_offset(pgd, addr); - if (pud_none(*pud)) { - pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC); - set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER)); - if (pmd != pmd_offset(pud, 0)) { - pud_ERROR(*pud); - return; - } + pud = pud_alloc(NULL, pgd, addr); + if (unlikely(!pud)) { + pud_ERROR(*pud); + return; } - pmd = pmd_offset(pud, addr); - if (pmd_none(*pmd)) { - pte = (pte_t *)get_zeroed_page(GFP_ATOMIC); - set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER)); - if (pte != pte_offset_kernel(pmd, 0)) { - pmd_ERROR(*pmd); - return; - } + pmd = pmd_alloc(NULL, pud, addr); + if (unlikely(!pmd)) { + pmd_ERROR(*pmd); + return; } pte = pte_offset_kernel(pmd, addr); @@ -155,9 +147,6 @@ extern char __init_begin, __init_end; /* * paging_init() sets up the page tables - * - * This routines also unmaps the page at virtual kernel address 0, so - * that we can trap those pesky NULL-reference errors in the kernel. */ void __init paging_init(void) { @@ -180,14 +169,11 @@ void __init paging_init(void) */ { unsigned long max_dma, low, start_pfn; - pgd_t *pg_dir; - int i; - - /* We don't need kernel mapping as hardware support that. */ - pg_dir = swapper_pg_dir; - for (i = 0; i < PTRS_PER_PGD; i++) - pgd_val(pg_dir[i]) = 0; + /* We don't need to map the kernel through the TLB, as + * it is permanatly mapped using P1. So clear the + * entire pgd. */ + memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir)); /* Turn on the MMU */ enable_mmu(); @@ -206,6 +192,10 @@ void __init paging_init(void) } } + /* Set an initial value for the MMU.TTB so we don't have to + * check for a null value. */ + set_TTB(swapper_pg_dir); + #elif defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4) /* * If we don't have CONFIG_MMU set and the processor in question @@ -227,7 +217,6 @@ static struct kcore_list kcore_mem, kcore_vmalloc; void __init mem_init(void) { - extern unsigned long empty_zero_page[1024]; int codesize, reservedpages, datasize, initsize; int tmp; extern unsigned long memory_start; diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c index a9fe80cfc23..11d54c14982 100644 --- a/arch/sh/mm/ioremap.c +++ b/arch/sh/mm/ioremap.c @@ -28,9 +28,7 @@ static inline void remap_area_pte(pte_t * pte, unsigned long address, { unsigned long end; unsigned long pfn; - pgprot_t pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | - _PAGE_DIRTY | _PAGE_ACCESSED | - _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | flags); + pgprot_t pgprot = __pgprot(pgprot_val(PAGE_KERNEL_NOCACHE) | flags); address &= ~PMD_MASK; end = address + size; diff --git a/arch/sh/mm/pg-dma.c b/arch/sh/mm/pg-dma.c index 1406d2e348c..bb23679369d 100644 --- a/arch/sh/mm/pg-dma.c +++ b/arch/sh/mm/pg-dma.c @@ -39,8 +39,6 @@ static void copy_page_dma(void *to, void *from) static void clear_page_dma(void *to) { - extern unsigned long empty_zero_page[1024]; - /* * We get invoked quite early on, if the DMAC hasn't been initialized * yet, fall back on the slow manual implementation. diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c index 07371ed7a31..3f98d2a4f93 100644 --- a/arch/sh/mm/pg-sh4.c +++ b/arch/sh/mm/pg-sh4.c @@ -6,22 +6,12 @@ * * Released under the terms of the GNU GPL v2.0. */ -#include <linux/init.h> -#include <linux/mman.h> #include <linux/mm.h> -#include <linux/threads.h> -#include <asm/addrspace.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <asm/cache.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/pgalloc.h> +#include <linux/mutex.h> #include <asm/mmu_context.h> #include <asm/cacheflush.h> -extern struct semaphore p3map_sem[]; +extern struct mutex p3map_mutex[]; #define CACHE_ALIAS (cpu_data->dcache.alias_mask) @@ -37,10 +27,6 @@ void clear_user_page(void *to, unsigned long address, struct page *page) if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) clear_page(to); else { - pgprot_t pgprot = __pgprot(_PAGE_PRESENT | - _PAGE_RW | _PAGE_CACHABLE | - _PAGE_DIRTY | _PAGE_ACCESSED | - _PAGE_HW_SHARED | _PAGE_FLAGS_HARD); unsigned long phys_addr = PHYSADDR(to); unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS); pgd_t *pgd = pgd_offset_k(p3_addr); @@ -50,8 +36,8 @@ void clear_user_page(void *to, unsigned long address, struct page *page) pte_t entry; unsigned long flags; - entry = pfn_pte(phys_addr >> PAGE_SHIFT, pgprot); - down(&p3map_sem[(address & CACHE_ALIAS)>>12]); + entry = pfn_pte(phys_addr >> PAGE_SHIFT, PAGE_KERNEL); + mutex_lock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); set_pte(pte, entry); local_irq_save(flags); __flush_tlb_page(get_asid(), p3_addr); @@ -59,7 +45,7 @@ void clear_user_page(void *to, unsigned long address, struct page *page) update_mmu_cache(NULL, p3_addr, entry); __clear_user_page((void *)p3_addr, to); pte_clear(&init_mm, p3_addr, pte); - up(&p3map_sem[(address & CACHE_ALIAS)>>12]); + mutex_unlock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); } } @@ -77,10 +63,6 @@ void copy_user_page(void *to, void *from, unsigned long address, if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) copy_page(to, from); else { - pgprot_t pgprot = __pgprot(_PAGE_PRESENT | - _PAGE_RW | _PAGE_CACHABLE | - _PAGE_DIRTY | _PAGE_ACCESSED | - _PAGE_HW_SHARED | _PAGE_FLAGS_HARD); unsigned long phys_addr = PHYSADDR(to); unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS); pgd_t *pgd = pgd_offset_k(p3_addr); @@ -90,8 +72,8 @@ void copy_user_page(void *to, void *from, unsigned long address, pte_t entry; unsigned long flags; - entry = pfn_pte(phys_addr >> PAGE_SHIFT, pgprot); - down(&p3map_sem[(address & CACHE_ALIAS)>>12]); + entry = pfn_pte(phys_addr >> PAGE_SHIFT, PAGE_KERNEL); + mutex_lock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); set_pte(pte, entry); local_irq_save(flags); __flush_tlb_page(get_asid(), p3_addr); @@ -99,7 +81,7 @@ void copy_user_page(void *to, void *from, unsigned long address, update_mmu_cache(NULL, p3_addr, entry); __copy_user_page((void *)p3_addr, from, to); pte_clear(&init_mm, p3_addr, pte); - up(&p3map_sem[(address & CACHE_ALIAS)>>12]); + mutex_unlock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); } } @@ -122,4 +104,3 @@ inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t } return pte; } - diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types index ac57638977e..0571755e9a8 100644 --- a/arch/sh/tools/mach-types +++ b/arch/sh/tools/mach-types @@ -30,3 +30,5 @@ R7780MP SH_R7780MP TITAN SH_TITAN SHMIN SH_SHMIN 7710VOIPGW SH_7710VOIPGW +7206SE SH_7206_SOLUTION_ENGINE +7619SE SH_7619_SOLUTION_ENGINE diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 3576b3cc505..7d4190e5565 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -638,7 +638,7 @@ int chan_out_fd(struct list_head *chans) return -1; } -void chan_interrupt(struct list_head *chans, struct work_struct *task, +void chan_interrupt(struct list_head *chans, struct delayed_work *task, struct tty_struct *tty, int irq) { struct list_head *ele, *next; diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 7b172160fe0..96f0189327a 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -56,7 +56,7 @@ static struct notifier_block reboot_notifier = { static LIST_HEAD(mc_requests); -static void mc_work_proc(void *unused) +static void mc_work_proc(struct work_struct *unused) { struct mconsole_entry *req; unsigned long flags; @@ -72,7 +72,7 @@ static void mc_work_proc(void *unused) } } -static DECLARE_WORK(mconsole_work, mc_work_proc, NULL); +static DECLARE_WORK(mconsole_work, mc_work_proc); static irqreturn_t mconsole_interrupt(int irq, void *dev_id) { diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index ec9eb8bd943..286bc0b3207 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -99,6 +99,7 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id) * same device, since it tests for (dev->flags & IFF_UP). So * there's no harm in delaying the device shutdown. */ schedule_work(&close_work); +#error this is not permitted - close_work will go out of scope goto out; } reactivate_fd(lp->fd, UM_ETH_IRQ); diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index ce9f3733f73..6dfe632f1c1 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -132,7 +132,7 @@ static int port_accept(struct port_list *port) DECLARE_MUTEX(ports_sem); struct list_head ports = LIST_HEAD_INIT(ports); -void port_work_proc(void *unused) +void port_work_proc(struct work_struct *unused) { struct port_list *port; struct list_head *ele; @@ -150,7 +150,7 @@ void port_work_proc(void *unused) local_irq_restore(flags); } -DECLARE_WORK(port_work, port_work_proc, NULL); +DECLARE_WORK(port_work, port_work_proc); static irqreturn_t port_interrupt(int irq, void *data) { diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index bbea88801d8..c7587fc3901 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -306,8 +306,8 @@ void mce_log_therm_throt_event(unsigned int cpu, __u64 status) */ static int check_interval = 5 * 60; /* 5 minutes */ -static void mcheck_timer(void *data); -static DECLARE_WORK(mcheck_work, mcheck_timer, NULL); +static void mcheck_timer(struct work_struct *work); +static DECLARE_DELAYED_WORK(mcheck_work, mcheck_timer); static void mcheck_check_cpu(void *info) { @@ -315,7 +315,7 @@ static void mcheck_check_cpu(void *info) do_machine_check(NULL, 0); } -static void mcheck_timer(void *data) +static void mcheck_timer(struct work_struct *work) { on_each_cpu(mcheck_check_cpu, NULL, 1, 1); schedule_delayed_work(&mcheck_work, check_interval * HZ); diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 62c2e747af5..9800147c4c6 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -753,14 +753,16 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta } struct create_idle { + struct work_struct work; struct task_struct *idle; struct completion done; int cpu; }; -void do_fork_idle(void *_c_idle) +void do_fork_idle(struct work_struct *work) { - struct create_idle *c_idle = _c_idle; + struct create_idle *c_idle = + container_of(work, struct create_idle, work); c_idle->idle = fork_idle(c_idle->cpu); complete(&c_idle->done); @@ -775,10 +777,10 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid) int timeout; unsigned long start_rip; struct create_idle c_idle = { + .work = __WORK_INITIALIZER(c_idle.work, do_fork_idle), .cpu = cpu, .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done), }; - DECLARE_WORK(work, do_fork_idle, &c_idle); /* allocate memory for gdts of secondary cpus. Hotplug is considered */ if (!cpu_gdt_descr[cpu].address && @@ -825,9 +827,9 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid) * thread. */ if (!keventd_up() || current_is_keventd()) - work.func(work.data); + c_idle.work.func(&c_idle.work); else { - schedule_work(&work); + schedule_work(&c_idle.work); wait_for_completion(&c_idle.done); } diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index e3ef544d2cf..9f05bc9b2da 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -563,7 +563,7 @@ static unsigned int cpufreq_delayed_issched = 0; static unsigned int cpufreq_init = 0; static struct work_struct cpufreq_delayed_get_work; -static void handle_cpufreq_delayed_get(void *v) +static void handle_cpufreq_delayed_get(struct work_struct *v) { unsigned int cpu; for_each_online_cpu(cpu) { @@ -639,7 +639,7 @@ static struct notifier_block time_cpufreq_notifier_block = { static int __init cpufreq_tsc(void) { - INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL); + INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get); if (!cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER)) cpufreq_init = 1; diff --git a/block/as-iosched.c b/block/as-iosched.c index 00242111a45..5934c4bfd52 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -1274,9 +1274,10 @@ static void as_merged_requests(request_queue_t *q, struct request *req, * * FIXME! dispatch queue is not a queue at all! */ -static void as_work_handler(void *data) +static void as_work_handler(struct work_struct *work) { - struct request_queue *q = data; + struct as_data *ad = container_of(work, struct as_data, antic_work); + struct request_queue *q = ad->q; unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); @@ -1332,7 +1333,7 @@ static void *as_init_queue(request_queue_t *q) ad->antic_timer.function = as_antic_timeout; ad->antic_timer.data = (unsigned long)q; init_timer(&ad->antic_timer); - INIT_WORK(&ad->antic_work, as_work_handler, q); + INIT_WORK(&ad->antic_work, as_work_handler); INIT_LIST_HEAD(&ad->fifo_list[REQ_SYNC]); INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]); diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index e9019ed39b7..84e9be07318 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1840,9 +1840,11 @@ queue_fail: return 1; } -static void cfq_kick_queue(void *data) +static void cfq_kick_queue(struct work_struct *work) { - request_queue_t *q = data; + struct cfq_data *cfqd = + container_of(work, struct cfq_data, unplug_work); + request_queue_t *q = cfqd->queue; unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); @@ -1986,7 +1988,7 @@ static void *cfq_init_queue(request_queue_t *q) cfqd->idle_class_timer.function = cfq_idle_class_timer; cfqd->idle_class_timer.data = (unsigned long) cfqd; - INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q); + INIT_WORK(&cfqd->unplug_work, cfq_kick_queue); cfqd->cfq_quantum = cfq_quantum; cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0]; diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 0f82e12f7b6..cc6e95f8e5d 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -34,7 +34,7 @@ */ #include <scsi/scsi_cmnd.h> -static void blk_unplug_work(void *data); +static void blk_unplug_work(struct work_struct *work); static void blk_unplug_timeout(unsigned long data); static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io); static void init_request_from_bio(struct request *req, struct bio *bio); @@ -227,7 +227,7 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) if (q->unplug_delay == 0) q->unplug_delay = 1; - INIT_WORK(&q->unplug_work, blk_unplug_work, q); + INIT_WORK(&q->unplug_work, blk_unplug_work); q->unplug_timer.function = blk_unplug_timeout; q->unplug_timer.data = (unsigned long)q; @@ -1631,9 +1631,9 @@ static void blk_backing_dev_unplug(struct backing_dev_info *bdi, } } -static void blk_unplug_work(void *data) +static void blk_unplug_work(struct work_struct *work) { - request_queue_t *q = data; + request_queue_t *q = container_of(work, request_queue_t, unplug_work); blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL, q->rq.count[READ] + q->rq.count[WRITE]); diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 5493c2fbbab..b3e210723a7 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -277,7 +277,7 @@ static int sg_io(struct file *file, request_queue_t *q, if (rq->bio) blk_queue_bounce(q, &rq->bio); - rq->timeout = (hdr->timeout * HZ) / 1000; + rq->timeout = jiffies_to_msecs(hdr->timeout); if (!rq->timeout) rq->timeout = q->sg_timeout; if (!rq->timeout) diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c index 9b5b1560106..2ebffb84f1d 100644 --- a/crypto/cryptomgr.c +++ b/crypto/cryptomgr.c @@ -40,9 +40,10 @@ struct cryptomgr_param { char template[CRYPTO_MAX_ALG_NAME]; }; -static void cryptomgr_probe(void *data) +static void cryptomgr_probe(struct work_struct *work) { - struct cryptomgr_param *param = data; + struct cryptomgr_param *param = + container_of(work, struct cryptomgr_param, work); struct crypto_template *tmpl; struct crypto_instance *inst; int err; @@ -112,7 +113,7 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) param->larval.type = larval->alg.cra_flags; param->larval.mask = larval->mask; - INIT_WORK(¶m->work, cryptomgr_probe, param); + INIT_WORK(¶m->work, cryptomgr_probe); schedule_work(¶m->work); return NOTIFY_STOP; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 068fe4f100b..02b30ae6a68 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -50,6 +50,7 @@ ACPI_MODULE_NAME("osl") struct acpi_os_dpc { acpi_osd_exec_callback function; void *context; + struct work_struct work; }; #ifdef CONFIG_ACPI_CUSTOM_DSDT @@ -564,12 +565,9 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */ acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number); } -static void acpi_os_execute_deferred(void *context) +static void acpi_os_execute_deferred(struct work_struct *work) { - struct acpi_os_dpc *dpc = NULL; - - - dpc = (struct acpi_os_dpc *)context; + struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); if (!dpc) { printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); return; @@ -602,7 +600,6 @@ acpi_status acpi_os_execute(acpi_execute_type type, { acpi_status status = AE_OK; struct acpi_os_dpc *dpc; - struct work_struct *task; ACPI_FUNCTION_TRACE("os_queue_for_execution"); @@ -615,28 +612,22 @@ acpi_status acpi_os_execute(acpi_execute_type type, /* * Allocate/initialize DPC structure. Note that this memory will be - * freed by the callee. The kernel handles the tq_struct list in a + * freed by the callee. The kernel handles the work_struct list in a * way that allows us to also free its memory inside the callee. * Because we may want to schedule several tasks with different * parameters we can't use the approach some kernel code uses of - * having a static tq_struct. - * We can save time and code by allocating the DPC and tq_structs - * from the same memory. + * having a static work_struct. */ - dpc = - kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct), - GFP_ATOMIC); + dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); if (!dpc) return_ACPI_STATUS(AE_NO_MEMORY); dpc->function = function; dpc->context = context; - task = (void *)(dpc + 1); - INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc); - - if (!queue_work(kacpid_wq, task)) { + INIT_WORK(&dpc->work, acpi_os_execute_deferred); + if (!queue_work(kacpid_wq, &dpc->work)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Call to queue_work() failed.\n")); kfree(dpc); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f8ec3896b79..8816e30fb7a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1081,7 +1081,7 @@ static unsigned int ata_id_xfermask(const u16 *id) * ata_port_queue_task - Queue port_task * @ap: The ata_port to queue port_task for * @fn: workqueue function to be scheduled - * @data: data value to pass to workqueue function + * @data: data for @fn to use * @delay: delay time for workqueue function * * Schedule @fn(@data) for execution after @delay jiffies using @@ -1096,7 +1096,7 @@ static unsigned int ata_id_xfermask(const u16 *id) * LOCKING: * Inherited from caller. */ -void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, +void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data, unsigned long delay) { int rc; @@ -1104,12 +1104,10 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK) return; - PREPARE_WORK(&ap->port_task, fn, data); + PREPARE_DELAYED_WORK(&ap->port_task, fn); + ap->port_task_data = data; - if (!delay) - rc = queue_work(ata_wq, &ap->port_task); - else - rc = queue_delayed_work(ata_wq, &ap->port_task, delay); + rc = queue_delayed_work(ata_wq, &ap->port_task, delay); /* rc == 0 means that another user is using port task */ WARN_ON(rc == 0); @@ -4588,10 +4586,11 @@ fsm_start: return poll_next; } -static void ata_pio_task(void *_data) +static void ata_pio_task(struct work_struct *work) { - struct ata_queued_cmd *qc = _data; - struct ata_port *ap = qc->ap; + struct ata_port *ap = + container_of(work, struct ata_port, port_task.work); + struct ata_queued_cmd *qc = ap->port_task_data; u8 status; int poll_next; @@ -5635,9 +5634,9 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host, ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN; #endif - INIT_WORK(&ap->port_task, NULL, NULL); - INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap); - INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap); + INIT_DELAYED_WORK(&ap->port_task, NULL); + INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug); + INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); INIT_LIST_HEAD(&ap->eh_done_q); init_waitqueue_head(&ap->eh_wait_q); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 76a85dfb730..08ad44b3e48 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -332,7 +332,7 @@ void ata_scsi_error(struct Scsi_Host *host) if (ap->pflags & ATA_PFLAG_LOADING) ap->pflags &= ~ATA_PFLAG_LOADING; else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) - queue_work(ata_aux_wq, &ap->hotplug_task); + queue_delayed_work(ata_aux_wq, &ap->hotplug_task, 0); if (ap->pflags & ATA_PFLAG_RECOVERED) ata_port_printk(ap, KERN_INFO, "EH complete\n"); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 8eaace94d96..664e1377b54 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2963,7 +2963,7 @@ static void ata_scsi_remove_dev(struct ata_device *dev) /** * ata_scsi_hotplug - SCSI part of hotplug - * @data: Pointer to ATA port to perform SCSI hotplug on + * @work: Pointer to ATA port to perform SCSI hotplug on * * Perform SCSI part of hotplug. It's executed from a separate * workqueue after EH completes. This is necessary because SCSI @@ -2973,9 +2973,10 @@ static void ata_scsi_remove_dev(struct ata_device *dev) * LOCKING: * Kernel thread context (may sleep). */ -void ata_scsi_hotplug(void *data) +void ata_scsi_hotplug(struct work_struct *work) { - struct ata_port *ap = data; + struct ata_port *ap = + container_of(work, struct ata_port, hotplug_task.work); int i; if (ap->pflags & ATA_PFLAG_UNLOADING) { @@ -3076,7 +3077,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, /** * ata_scsi_dev_rescan - initiate scsi_rescan_device() - * @data: Pointer to ATA port to perform scsi_rescan_device() + * @work: Pointer to ATA port to perform scsi_rescan_device() * * After ATA pass thru (SAT) commands are executed successfully, * libata need to propagate the changes to SCSI layer. This @@ -3086,9 +3087,10 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, * LOCKING: * Kernel thread context (may sleep). */ -void ata_scsi_dev_rescan(void *data) +void ata_scsi_dev_rescan(struct work_struct *work) { - struct ata_port *ap = data; + struct ata_port *ap = + container_of(work, struct ata_port, scsi_rescan_task); unsigned long flags; unsigned int i; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 107b2b56522..81ae41d5f23 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -94,7 +94,7 @@ extern struct scsi_transport_template ata_scsi_transport_template; extern void ata_scsi_scan_host(struct ata_port *ap); extern int ata_scsi_offline_dev(struct ata_device *dev); -extern void ata_scsi_hotplug(void *data); +extern void ata_scsi_hotplug(struct work_struct *work); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); @@ -124,7 +124,7 @@ extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); -extern void ata_scsi_dev_rescan(void *data); +extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); /* libata-eh.c */ diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 4ca6fa5dcb4..9ed7f58424a 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -154,19 +154,12 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(pdev, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(pdev, &tuple, &stk->parse)); - pdev->conf.ConfigBase = stk->parse.config.base; - pdev->conf.Present = stk->parse.config.rmask[0]; /* See if we have a manufacturer identifier. Use it to set is_kme for vendor quirks */ - tuple.DesiredTuple = CISTPL_MANFID; - if (!pcmcia_get_first_tuple(pdev, &tuple) && !pcmcia_get_tuple_data(pdev, &tuple) && !pcmcia_parse_tuple(pdev, &tuple, &stk->parse)) - is_kme = ((stk->parse.manfid.manf == MANFID_KME) && ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) || (stk->parse.manfid.card == PRODID_KME_KXLC005_B))); + is_kme = ((pdev->manf_id == MANFID_KME) && + ((pdev->card_id == PRODID_KME_KXLC005_A) || + (pdev->card_id == PRODID_KME_KXLC005_B))); /* Not sure if this is right... look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &stk->conf)); @@ -356,8 +349,10 @@ static struct pcmcia_device_id pcmcia_devices[] = { PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6), PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003), PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1), PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8), PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), + PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918), PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e), PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6), diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 87b17c33b3f..f4078612194 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -135,7 +135,7 @@ static int idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags); static int idt77252_proc_read(struct atm_dev *dev, loff_t * pos, char *page); -static void idt77252_softint(void *dev_id); +static void idt77252_softint(struct work_struct *work); static struct atmdev_ops idt77252_ops = @@ -2866,9 +2866,10 @@ out: } static void -idt77252_softint(void *dev_id) +idt77252_softint(struct work_struct *work) { - struct idt77252_dev *card = dev_id; + struct idt77252_dev *card = + container_of(work, struct idt77252_dev, tqueue); u32 stat; int done; @@ -3697,7 +3698,7 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id) card->pcidev = pcidev; sprintf(card->name, "idt77252-%d", card->index); - INIT_WORK(&card->tqueue, idt77252_softint, (void *)card); + INIT_WORK(&card->tqueue, idt77252_softint); membase = pci_resource_start(pcidev, 1); srambase = pci_resource_start(pcidev, 2); diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 6d111228cfa..2308e83e5f3 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -159,7 +159,7 @@ void aoecmd_work(struct aoedev *d); void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor); void aoecmd_ata_rsp(struct sk_buff *); void aoecmd_cfg_rsp(struct sk_buff *); -void aoecmd_sleepwork(void *vp); +void aoecmd_sleepwork(struct work_struct *); struct sk_buff *new_skb(ulong); int aoedev_init(void); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 8a13b1af8ba..97f7f535f41 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -408,9 +408,9 @@ rexmit_timer(ulong vp) /* this function performs work that has been deferred until sleeping is OK */ void -aoecmd_sleepwork(void *vp) +aoecmd_sleepwork(struct work_struct *work) { - struct aoedev *d = (struct aoedev *) vp; + struct aoedev *d = container_of(work, struct aoedev, work); if (d->flags & DEVFL_GDALLOC) aoeblk_gdalloc(d); diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index 6125921bbec..05a97197c91 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -88,7 +88,7 @@ aoedev_newdev(ulong nframes) kfree(d); return NULL; } - INIT_WORK(&d->work, aoecmd_sleepwork, d); + INIT_WORK(&d->work, aoecmd_sleepwork); spin_lock_init(&d->lock); init_timer(&d->timer); d->timer.data = (ulong) d; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 9e6d3a87cbe..3f1b38276e9 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -992,11 +992,11 @@ static void empty(void) { } -static DECLARE_WORK(floppy_work, NULL, NULL); +static DECLARE_WORK(floppy_work, NULL); static void schedule_bh(void (*handler) (void)) { - PREPARE_WORK(&floppy_work, (void (*)(void *))handler, NULL); + PREPARE_WORK(&floppy_work, (work_func_t)handler); schedule_work(&floppy_work); } @@ -1008,7 +1008,7 @@ static void cancel_activity(void) spin_lock_irqsave(&floppy_lock, flags); do_floppy = NULL; - PREPARE_WORK(&floppy_work, (void *)empty, NULL); + PREPARE_WORK(&floppy_work, (work_func_t)empty); del_timer(&fd_timer); spin_unlock_irqrestore(&floppy_lock, flags); } @@ -1868,7 +1868,7 @@ static void show_floppy(void) printk("fdc_busy=%lu\n", fdc_busy); if (do_floppy) printk("do_floppy=%p\n", do_floppy); - if (floppy_work.pending) + if (work_pending(&floppy_work)) printk("floppy_work.func=%p\n", floppy_work.func); if (timer_pending(&fd_timer)) printk("fd_timer.function=%p\n", fd_timer.function); @@ -4498,7 +4498,7 @@ static void floppy_release_irq_and_dma(void) printk("floppy timer still active:%s\n", timeout_message); if (timer_pending(&fd_timer)) printk("auxiliary floppy timer still active\n"); - if (floppy_work.pending) + if (work_pending(&floppy_work)) printk("work still pending\n"); #endif old_fdc = fdc; diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 40a11e56797..9d9bff23f42 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -352,19 +352,19 @@ static enum action (*phase)(void); static void run_fsm(void); -static void ps_tq_int( void *data); +static void ps_tq_int(struct work_struct *work); -static DECLARE_WORK(fsm_tq, ps_tq_int, NULL); +static DECLARE_DELAYED_WORK(fsm_tq, ps_tq_int); static void schedule_fsm(void) { if (!nice) - schedule_work(&fsm_tq); + schedule_delayed_work(&fsm_tq, 0); else schedule_delayed_work(&fsm_tq, nice-1); } -static void ps_tq_int(void *data) +static void ps_tq_int(struct work_struct *work) { run_fsm(); } diff --git a/drivers/block/paride/pseudo.h b/drivers/block/paride/pseudo.h index 932342d7a8e..bc370329414 100644 --- a/drivers/block/paride/pseudo.h +++ b/drivers/block/paride/pseudo.h @@ -35,7 +35,7 @@ #include <linux/sched.h> #include <linux/workqueue.h> -static void ps_tq_int( void *data); +static void ps_tq_int(struct work_struct *work); static void (* ps_continuation)(void); static int (* ps_ready)(void); @@ -45,7 +45,7 @@ static int ps_nice = 0; static DEFINE_SPINLOCK(ps_spinlock __attribute__((unused))); -static DECLARE_WORK(ps_tq, ps_tq_int, NULL); +static DECLARE_DELAYED_WORK(ps_tq, ps_tq_int); static void ps_set_intr(void (*continuation)(void), int (*ready)(void), @@ -63,14 +63,14 @@ static void ps_set_intr(void (*continuation)(void), if (!ps_tq_active) { ps_tq_active = 1; if (!ps_nice) - schedule_work(&ps_tq); + schedule_delayed_work(&ps_tq, 0); else schedule_delayed_work(&ps_tq, ps_nice-1); } spin_unlock_irqrestore(&ps_spinlock,flags); } -static void ps_tq_int(void *data) +static void ps_tq_int(struct work_struct *work) { void (*con)(void); unsigned long flags; @@ -92,7 +92,7 @@ static void ps_tq_int(void *data) } ps_tq_active = 1; if (!ps_nice) - schedule_work(&ps_tq); + schedule_delayed_work(&ps_tq, 0); else schedule_delayed_work(&ps_tq, ps_nice-1); spin_unlock_irqrestore(&ps_spinlock,flags); diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 47d6975268f..54509eb3391 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1244,9 +1244,10 @@ out: return IRQ_RETVAL(handled); } -static void carm_fsm_task (void *_data) +static void carm_fsm_task (struct work_struct *work) { - struct carm_host *host = _data; + struct carm_host *host = + container_of(work, struct carm_host, fsm_task); unsigned long flags; unsigned int state; int rc, i, next_dev; @@ -1619,7 +1620,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) host->pdev = pdev; host->flags = pci_dac ? FL_DAC : 0; spin_lock_init(&host->lock); - INIT_WORK(&host->fsm_task, carm_fsm_task, host); + INIT_WORK(&host->fsm_task, carm_fsm_task); init_completion(&host->probe_comp); for (i = 0; i < ARRAY_SIZE(host->req); i++) diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 0d5c73f0726..2098eff91e1 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -376,7 +376,7 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int stalled_pipe); static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd); static void ub_reset_enter(struct ub_dev *sc, int try); -static void ub_reset_task(void *arg); +static void ub_reset_task(struct work_struct *work); static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun); static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, struct ub_capacity *ret); @@ -1558,9 +1558,9 @@ static void ub_reset_enter(struct ub_dev *sc, int try) schedule_work(&sc->reset_work); } -static void ub_reset_task(void *arg) +static void ub_reset_task(struct work_struct *work) { - struct ub_dev *sc = arg; + struct ub_dev *sc = container_of(work, struct ub_dev, reset_work); unsigned long flags; struct list_head *p; struct ub_lun *lun; @@ -2179,7 +2179,7 @@ static int ub_probe(struct usb_interface *intf, usb_init_urb(&sc->work_urb); tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc); atomic_set(&sc->poison, 0); - INIT_WORK(&sc->reset_work, ub_reset_task, sc); + INIT_WORK(&sc->reset_work, ub_reset_task); init_waitqueue_head(&sc->reset_wait); init_timer(&sc->work_timer); diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 516751754aa..9256985cbe3 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -157,9 +157,10 @@ static void bcm203x_complete(struct urb *urb) } } -static void bcm203x_work(void *user_data) +static void bcm203x_work(struct work_struct *work) { - struct bcm203x_data *data = user_data; + struct bcm203x_data *data = + container_of(work, struct bcm203x_data, work); if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) BT_ERR("Can't submit URB"); @@ -246,7 +247,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id release_firmware(firmware); - INIT_WORK(&data->work, bcm203x_work, (void *) data); + INIT_WORK(&data->work, bcm203x_work); usb_set_intfdata(intf, data); diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index cbc07250b89..acfb6a430dc 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -892,43 +892,10 @@ static void bluecard_detach(struct pcmcia_device *link) } -static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) -{ - int i; - - i = pcmcia_get_first_tuple(handle, tuple); - if (i != CS_SUCCESS) - return CS_NO_MORE_ITEMS; - - i = pcmcia_get_tuple_data(handle, tuple); - if (i != CS_SUCCESS) - return i; - - return pcmcia_parse_tuple(handle, tuple, parse); -} - static int bluecard_config(struct pcmcia_device *link) { bluecard_info_t *info = link->priv; - tuple_t tuple; - u_short buf[256]; - cisparse_t parse; - int i, n, last_ret, last_fn; - - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.Attributes = 0; - - /* Get configuration register information */ - tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(link, &tuple, &parse); - if (last_ret != CS_SUCCESS) { - last_fn = ParseTuple; - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; + int i, n; link->conf.ConfigIndex = 0x20; link->io.NumPorts1 = 64; @@ -966,9 +933,6 @@ static int bluecard_config(struct pcmcia_device *link) return 0; -cs_failed: - cs_error(link, last_fn, last_ret); - failed: bluecard_release(link); return -ENODEV; diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 3a96a0babc6..aae3abace58 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -713,22 +713,7 @@ static int bt3c_config(struct pcmcia_device *link) u_short buf[256]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; - int i, j, try, last_ret, last_fn; - - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.Attributes = 0; - - /* Get configuration register information */ - tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(link, &tuple, &parse); - if (last_ret != CS_SUCCESS) { - last_fn = ParseTuple; - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; + int i, j, try; /* First pass: look for a config entry that looks normal. */ tuple.TupleData = (cisdata_t *)buf; @@ -802,9 +787,6 @@ found_port: return 0; -cs_failed: - cs_error(link, last_fn, last_ret); - failed: bt3c_release(link); return -ENODEV; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 3b29086b7c3..92648ef2f5d 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -644,22 +644,7 @@ static int btuart_config(struct pcmcia_device *link) u_short buf[256]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; - int i, j, try, last_ret, last_fn; - - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.Attributes = 0; - - /* Get configuration register information */ - tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(link, &tuple, &parse); - if (last_ret != CS_SUCCESS) { - last_fn = ParseTuple; - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; + int i, j, try; /* First pass: look for a config entry that looks normal. */ tuple.TupleData = (cisdata_t *) buf; @@ -734,9 +719,6 @@ found_port: return 0; -cs_failed: - cs_error(link, last_fn, last_ret); - failed: btuart_release(link); return -ENODEV; diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 07eafbc5dc3..77b99eecbc4 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -626,22 +626,7 @@ static int dtl1_config(struct pcmcia_device *link) u_short buf[256]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; - int i, last_ret, last_fn; - - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.Attributes = 0; - - /* Get configuration register information */ - tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(link, &tuple, &parse); - if (last_ret != CS_SUCCESS) { - last_fn = ParseTuple; - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; + int i; tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; @@ -690,9 +675,6 @@ static int dtl1_config(struct pcmcia_device *link) return 0; -cs_failed: - cs_error(link, last_fn, last_ret); - failed: dtl1_release(link); return -ENODEV; diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index e608dadece2..acb2de5e3a9 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -926,9 +926,10 @@ cy_sched_event(struct cyclades_port *info, int event) * had to poll every port to see if that port needed servicing. */ static void -do_softint(void *private_) +do_softint(struct work_struct *work) { - struct cyclades_port *info = (struct cyclades_port *) private_; + struct cyclades_port *info = + container_of(work, struct cyclades_port, tqueue); struct tty_struct *tty; tty = info->tty; @@ -5328,7 +5329,7 @@ cy_init(void) info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue, do_softint); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->shutdown_wait); @@ -5403,7 +5404,7 @@ cy_init(void) info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue, do_softint); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->shutdown_wait); diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index 60c1695db30..806f9ce5f47 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c @@ -500,9 +500,9 @@ via_dmablit_timer(unsigned long data) static void -via_dmablit_workqueue(void *data) +via_dmablit_workqueue(struct work_struct *work) { - drm_via_blitq_t *blitq = (drm_via_blitq_t *) data; + drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq); drm_device_t *dev = blitq->dev; unsigned long irqsave; drm_via_sg_info_t *cur_sg; @@ -571,7 +571,7 @@ via_init_dmablit(drm_device_t *dev) DRM_INIT_WAITQUEUE(blitq->blit_queue + j); } DRM_INIT_WAITQUEUE(&blitq->busy_queue); - INIT_WORK(&blitq->wq, via_dmablit_workqueue, blitq); + INIT_WORK(&blitq->wq, via_dmablit_workqueue); init_timer(&blitq->poll_timer); blitq->poll_timer.function = &via_dmablit_timer; blitq->poll_timer.data = (unsigned long) blitq; diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 706733c0b36..7c71eb77980 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -200,7 +200,7 @@ static int pc_ioctl(struct tty_struct *, struct file *, static int info_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); static void pc_set_termios(struct tty_struct *, struct termios *); -static void do_softint(void *); +static void do_softint(struct work_struct *work); static void pc_stop(struct tty_struct *); static void pc_start(struct tty_struct *); static void pc_throttle(struct tty_struct * tty); @@ -1505,7 +1505,7 @@ static void post_fep_init(unsigned int crd) ch->brdchan = bc; ch->mailbox = gd; - INIT_WORK(&ch->tqueue, do_softint, ch); + INIT_WORK(&ch->tqueue, do_softint); ch->board = &boards[crd]; spin_lock_irqsave(&epca_lock, flags); @@ -2566,9 +2566,9 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) /* --------------------- Begin do_softint ----------------------- */ -static void do_softint(void *private_) +static void do_softint(struct work_struct *work) { /* Begin do_softint */ - struct channel *ch = (struct channel *) private_; + struct channel *ch = container_of(work, struct channel, tqueue); /* Called in response to a modem change event */ if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */ struct tty_struct *tty = ch->tty; diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 15a4ea89632..93b55196251 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -723,9 +723,10 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) * ------------------------------------------------------------------- */ -static void do_softint(void *private_) +static void do_softint(struct work_struct *work) { - struct esp_struct *info = (struct esp_struct *) private_; + struct esp_struct *info = + container_of(work, struct esp_struct, tqueue); struct tty_struct *tty; tty = info->tty; @@ -746,9 +747,10 @@ static void do_softint(void *private_) * do_serial_hangup() -> tty->hangup() -> esp_hangup() * */ -static void do_serial_hangup(void *private_) +static void do_serial_hangup(struct work_struct *work) { - struct esp_struct *info = (struct esp_struct *) private_; + struct esp_struct *info = + container_of(work, struct esp_struct, tqueue_hangup); struct tty_struct *tty; tty = info->tty; @@ -2501,8 +2503,8 @@ static int __init espserial_init(void) info->magic = ESP_MAGIC; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; - INIT_WORK(&info->tqueue, do_softint, info); - INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); + INIT_WORK(&info->tqueue, do_softint); + INIT_WORK(&info->tqueue_hangup, do_serial_hangup); info->config.rx_timeout = rx_timeout; info->config.flow_on = flow_on; info->config.flow_off = flow_off; diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index 817dc409ac2..23b25ada65e 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -102,7 +102,7 @@ static void gen_rtc_interrupt(unsigned long arg); * Routine to poll RTC seconds field for change as often as possible, * after first RTC_UIE use timer to reduce polling */ -static void genrtc_troutine(void *data) +static void genrtc_troutine(struct work_struct *work) { unsigned int tmp = get_rtc_ss(); @@ -255,7 +255,7 @@ static inline int gen_set_rtc_irq_bit(unsigned char bit) irq_active = 1; stop_rtc_timers = 0; lostint = 0; - INIT_WORK(&genrtc_task, genrtc_troutine, NULL); + INIT_WORK(&genrtc_task, genrtc_troutine); oldsecs = get_rtc_ss(); init_timer(&timer_task); diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 2cf63e7305a..82a41d5b4ed 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -69,7 +69,7 @@ #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) struct hvsi_struct { - struct work_struct writer; + struct delayed_work writer; struct work_struct handshaker; wait_queue_head_t emptyq; /* woken when outbuf is emptied */ wait_queue_head_t stateq; /* woken when HVSI state changes */ @@ -744,9 +744,10 @@ static int hvsi_handshake(struct hvsi_struct *hp) return 0; } -static void hvsi_handshaker(void *arg) +static void hvsi_handshaker(struct work_struct *work) { - struct hvsi_struct *hp = (struct hvsi_struct *)arg; + struct hvsi_struct *hp = + container_of(work, struct hvsi_struct, handshaker); if (hvsi_handshake(hp) >= 0) return; @@ -951,9 +952,10 @@ static void hvsi_push(struct hvsi_struct *hp) } /* hvsi_write_worker will keep rescheduling itself until outbuf is empty */ -static void hvsi_write_worker(void *arg) +static void hvsi_write_worker(struct work_struct *work) { - struct hvsi_struct *hp = (struct hvsi_struct *)arg; + struct hvsi_struct *hp = + container_of(work, struct hvsi_struct, writer.work); unsigned long flags; #ifdef DEBUG static long start_j = 0; @@ -1287,8 +1289,8 @@ static int __init hvsi_console_init(void) } hp = &hvsi_ports[hvsi_count]; - INIT_WORK(&hp->writer, hvsi_write_worker, hp); - INIT_WORK(&hp->handshaker, hvsi_handshaker, hp); + INIT_DELAYED_WORK(&hp->writer, hvsi_write_worker); + INIT_WORK(&hp->handshaker, hvsi_handshaker); init_waitqueue_head(&hp->emptyq); init_waitqueue_head(&hp->stateq); spin_lock_init(&hp->lock); diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 54d93f0345e..c213fdbdb2b 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -84,8 +84,8 @@ static void iiSendPendingMail(i2eBordStrPtr); static void serviceOutgoingFifo(i2eBordStrPtr); // Functions defined in ip2.c as part of interrupt handling -static void do_input(void *); -static void do_status(void *); +static void do_input(struct work_struct *); +static void do_status(struct work_struct *); //*************** //* Debug Data * @@ -331,8 +331,8 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh) pCh->ClosingWaitTime = 30*HZ; // Initialize task queue objects - INIT_WORK(&pCh->tqueue_input, do_input, pCh); - INIT_WORK(&pCh->tqueue_status, do_status, pCh); + INIT_WORK(&pCh->tqueue_input, do_input); + INIT_WORK(&pCh->tqueue_status, do_status); #ifdef IP2DEBUG_TRACE pCh->trace = ip2trace; @@ -1573,7 +1573,7 @@ i2StripFifo(i2eBordStrPtr pB) #ifdef USE_IQ schedule_work(&pCh->tqueue_input); #else - do_input(pCh); + do_input(&pCh->tqueue_input); #endif // Note we do not need to maintain any flow-control credits at this @@ -1810,7 +1810,7 @@ i2StripFifo(i2eBordStrPtr pB) #ifdef USE_IQ schedule_work(&pCh->tqueue_status); #else - do_status(pCh); + do_status(&pCh->tqueue_status); #endif } } diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index a3f32d46d2f..cda2459c1d6 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -189,12 +189,12 @@ static int ip2_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static void set_irq(int, int); -static void ip2_interrupt_bh(i2eBordStrPtr pB); +static void ip2_interrupt_bh(struct work_struct *work); static irqreturn_t ip2_interrupt(int irq, void *dev_id); static void ip2_poll(unsigned long arg); static inline void service_all_boards(void); -static void do_input(void *p); -static void do_status(void *p); +static void do_input(struct work_struct *); +static void do_status(struct work_struct *); static void ip2_wait_until_sent(PTTY,int); @@ -918,7 +918,7 @@ ip2_init_board( int boardnum ) pCh++; } ex_exit: - INIT_WORK(&pB->tqueue_interrupt, (void(*)(void*)) ip2_interrupt_bh, pB); + INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh); return; err_release_region: @@ -1125,8 +1125,8 @@ service_all_boards(void) /******************************************************************************/ -/* Function: ip2_interrupt_bh(pB) */ -/* Parameters: pB - pointer to the board structure */ +/* Function: ip2_interrupt_bh(work) */ +/* Parameters: work - pointer to the board structure */ /* Returns: Nothing */ /* */ /* Description: */ @@ -1135,8 +1135,9 @@ service_all_boards(void) /* */ /******************************************************************************/ static void -ip2_interrupt_bh(i2eBordStrPtr pB) +ip2_interrupt_bh(struct work_struct *work) { + i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt); // pB better well be set or we have a problem! We can only get // here from the IMMEDIATE queue. Here, we process the boards. // Checking pB doesn't cost much and it saves us from the sanity checkers. @@ -1245,9 +1246,9 @@ ip2_poll(unsigned long arg) ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); } -static void do_input(void *p) +static void do_input(struct work_struct *work) { - i2ChanStrPtr pCh = p; + i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input); unsigned long flags; ip2trace(CHANN, ITRC_INPUT, 21, 0 ); @@ -1279,9 +1280,9 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) } } -static void do_status(void *p) +static void do_status(struct work_struct *work) { - i2ChanStrPtr pCh = p; + i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status); int status; status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) ); diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 58c955e390b..1637c1d9a4b 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -530,9 +530,9 @@ sched_again: /* Interrupt handlers */ -static void isicom_bottomhalf(void *data) +static void isicom_bottomhalf(struct work_struct *work) { - struct isi_port *port = (struct isi_port *) data; + struct isi_port *port = container_of(work, struct isi_port, bh_tqueue); struct tty_struct *tty = port->tty; if (!tty) @@ -1474,9 +1474,9 @@ static void isicom_start(struct tty_struct *tty) } /* hangup et all */ -static void do_isicom_hangup(void *data) +static void do_isicom_hangup(struct work_struct *work) { - struct isi_port *port = data; + struct isi_port *port = container_of(work, struct isi_port, hangup_tq); struct tty_struct *tty; tty = port->tty; @@ -1966,8 +1966,8 @@ static int __devinit isicom_setup(void) port->channel = channel; port->close_delay = 50 * HZ/100; port->closing_wait = 3000 * HZ/100; - INIT_WORK(&port->hangup_tq, do_isicom_hangup, port); - INIT_WORK(&port->bh_tqueue, isicom_bottomhalf, port); + INIT_WORK(&port->hangup_tq, do_isicom_hangup); + INIT_WORK(&port->bh_tqueue, isicom_bottomhalf); port->status = 0; init_waitqueue_head(&port->open_wait); init_waitqueue_head(&port->close_wait); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index ffdf9df1a67..bd9195e1795 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -663,7 +663,7 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp); static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp); -static void stli_dohangup(void *arg); +static void stli_dohangup(struct work_struct *); static int stli_setport(stliport_t *portp); static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); @@ -1990,9 +1990,9 @@ static void stli_start(struct tty_struct *tty) * aren't that time critical). */ -static void stli_dohangup(void *arg) +static void stli_dohangup(struct work_struct *ugly_api) { - stliport_t *portp = (stliport_t *) arg; + stliport_t *portp = container_of(ugly_api, stliport_t, tqhangup); if (portp->tty != NULL) { tty_hangup(portp->tty); } @@ -2898,7 +2898,7 @@ static int stli_initports(stlibrd_t *brdp) portp->baud_base = STL_BAUDBASE; portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; - INIT_WORK(&portp->tqhangup, stli_dohangup, portp); + INIT_WORK(&portp->tqhangup, stli_dohangup); init_waitqueue_head(&portp->open_wait); init_waitqueue_head(&portp->close_wait); init_waitqueue_head(&portp->raw_wait); diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 96cb1f07332..2d025a9fd14 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -222,7 +222,7 @@ static struct semaphore moxaBuffSem; /* * static functions: */ -static void do_moxa_softint(void *); +static void do_moxa_softint(struct work_struct *); static int moxa_open(struct tty_struct *, struct file *); static void moxa_close(struct tty_struct *, struct file *); static int moxa_write(struct tty_struct *, const unsigned char *, int); @@ -363,7 +363,7 @@ static int __init moxa_init(void) for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) { ch->type = PORT_16550A; ch->port = i; - INIT_WORK(&ch->tqueue, do_moxa_softint, ch); + INIT_WORK(&ch->tqueue, do_moxa_softint); ch->tty = NULL; ch->close_delay = 5 * HZ / 10; ch->closing_wait = 30 * HZ; @@ -509,9 +509,9 @@ static void __exit moxa_exit(void) module_init(moxa_init); module_exit(moxa_exit); -static void do_moxa_softint(void *private_) +static void do_moxa_softint(struct work_struct *work) { - struct moxa_str *ch = (struct moxa_str *) private_; + struct moxa_str *ch = container_of(work, struct moxa_str, tqueue); struct tty_struct *tty; if (ch && (tty = ch->tty)) { diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 048d91142c1..5ed2486b758 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -389,7 +389,7 @@ static int mxser_init(void); /* static void mxser_poll(unsigned long); */ static int mxser_get_ISA_conf(int, struct mxser_hwconf *); static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *); -static void mxser_do_softint(void *); +static void mxser_do_softint(struct work_struct *); static int mxser_open(struct tty_struct *, struct file *); static void mxser_close(struct tty_struct *, struct file *); static int mxser_write(struct tty_struct *, const unsigned char *, int); @@ -590,7 +590,7 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf) info->custom_divisor = hwconf->baud_base[i] * 16; info->close_delay = 5 * HZ / 10; info->closing_wait = 30 * HZ; - INIT_WORK(&info->tqueue, mxser_do_softint, info); + INIT_WORK(&info->tqueue, mxser_do_softint); info->normal_termios = mxvar_sdriver->init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); @@ -917,9 +917,10 @@ static int mxser_init(void) return 0; } -static void mxser_do_softint(void *private_) +static void mxser_do_softint(struct work_struct *work) { - struct mxser_struct *info = private_; + struct mxser_struct *info = + container_of(work, struct mxser_struct, tqueue); struct tty_struct *tty; tty = info->tty; diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 50d20aafeb1..211c93fda6f 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1764,29 +1764,11 @@ static int cm4000_config(struct pcmcia_device * link, int devno) int rc; /* read the config-tuples */ - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if ((fail_rc = pcmcia_get_first_tuple(link, &tuple)) != CS_SUCCESS) { - fail_fn = GetFirstTuple; - goto cs_failed; - } - if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) { - fail_fn = GetTupleData; - goto cs_failed; - } - if ((fail_rc = - pcmcia_parse_tuple(link, &tuple, &parse)) != CS_SUCCESS) { - fail_fn = ParseTuple; - goto cs_failed; - } - - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - link->io.BasePort2 = 0; link->io.NumPorts2 = 0; link->io.Attributes2 = 0; @@ -1841,8 +1823,6 @@ static int cm4000_config(struct pcmcia_device * link, int devno) return 0; -cs_failed: - cs_error(link, fail_fn, fail_rc); cs_release: cm4000_release(link); return -ENODEV; @@ -1973,14 +1953,14 @@ static int __init cmm_init(void) printk(KERN_INFO "%s\n", version); cmm_class = class_create(THIS_MODULE, "cardman_4000"); - if (!cmm_class) - return -1; + if (IS_ERR(cmm_class)) + return PTR_ERR(cmm_class); major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); - return -1; + return major; } rc = pcmcia_register_driver(&cm4000_driver); diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 55cf4be4297..9b1ff7e8f89 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -523,29 +523,11 @@ static int reader_config(struct pcmcia_device *link, int devno) int fail_fn, fail_rc; int rc; - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if ((fail_rc = pcmcia_get_first_tuple(link, &tuple)) != CS_SUCCESS) { - fail_fn = GetFirstTuple; - goto cs_failed; - } - if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) { - fail_fn = GetTupleData; - goto cs_failed; - } - if ((fail_rc = pcmcia_parse_tuple(link, &tuple, &parse)) - != CS_SUCCESS) { - fail_fn = ParseTuple; - goto cs_failed; - } - - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - link->io.BasePort2 = 0; link->io.NumPorts2 = 0; link->io.Attributes2 = 0; @@ -609,8 +591,6 @@ static int reader_config(struct pcmcia_device *link, int devno) return 0; -cs_failed: - cs_error(link, fail_fn, fail_rc); cs_release: reader_release(link); return -ENODEV; @@ -721,14 +701,14 @@ static int __init cm4040_init(void) printk(KERN_INFO "%s\n", version); cmx_class = class_create(THIS_MODULE, "cardman_4040"); - if (!cmx_class) - return -1; + if (IS_ERR(cmx_class)) + return PTR_ERR(cmx_class); major = register_chrdev(0, DEVICE_NAME, &reader_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); - return -1; + return major; } rc = pcmcia_register_driver(&reader_driver); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 1a0bc30b79d..1bd12296dca 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -421,7 +421,7 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id); /* * Bottom half interrupt handlers */ -static void bh_handler(void* Context); +static void bh_handler(struct work_struct *work); static void bh_transmit(MGSLPC_INFO *info); static void bh_status(MGSLPC_INFO *info); @@ -547,7 +547,7 @@ static int mgslpc_probe(struct pcmcia_device *link) memset(info, 0, sizeof(MGSLPC_INFO)); info->magic = MGSLPC_MAGIC; - INIT_WORK(&info->task, bh_handler, info); + INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; @@ -604,17 +604,10 @@ static int mgslpc_config(struct pcmcia_device *link) if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_config(0x%p)\n", link); - /* read CONFIG tuple to find its configuration registers */ - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; /* get CIS configuration entry */ @@ -842,9 +835,9 @@ static int bh_action(MGSLPC_INFO *info) return rc; } -static void bh_handler(void* Context) +static void bh_handler(struct work_struct *work) { - MGSLPC_INFO *info = (MGSLPC_INFO*)Context; + MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task); int action; if (!info) diff --git a/drivers/char/random.c b/drivers/char/random.c index d40df30c2b1..4c6782a1ecd 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1422,9 +1422,9 @@ static struct keydata { static unsigned int ip_cnt; -static void rekey_seq_generator(void *private_); +static void rekey_seq_generator(struct work_struct *work); -static DECLARE_WORK(rekey_work, rekey_seq_generator, NULL); +static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator); /* * Lock avoidance: @@ -1438,7 +1438,7 @@ static DECLARE_WORK(rekey_work, rekey_seq_generator, NULL); * happen, and even if that happens only a not perfectly compliant * ISN is generated, nothing fatal. */ -static void rekey_seq_generator(void *private_) +static void rekey_seq_generator(struct work_struct *work) { struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)]; diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 5ab32b38f45..722dd3e7418 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -1516,9 +1516,9 @@ static void rc_start(struct tty_struct * tty) * do_rc_hangup() -> tty->hangup() -> rc_hangup() * */ -static void do_rc_hangup(void *private_) +static void do_rc_hangup(struct work_struct *ugly_api) { - struct riscom_port *port = (struct riscom_port *) private_; + struct riscom_port *port = container_of(ugly_api, struct riscom_port, tqueue_hangup); struct tty_struct *tty; tty = port->tty; @@ -1567,9 +1567,9 @@ static void rc_set_termios(struct tty_struct * tty, struct termios * old_termios } } -static void do_softint(void *private_) +static void do_softint(struct work_struct *ugly_api) { - struct riscom_port *port = (struct riscom_port *) private_; + struct riscom_port *port = container_of(ugly_api, struct riscom_port, tqueue); struct tty_struct *tty; if(!(tty = port->tty)) @@ -1632,8 +1632,8 @@ static inline int rc_init_drivers(void) memset(rc_port, 0, sizeof(rc_port)); for (i = 0; i < RC_NPORT * RC_NBOARD; i++) { rc_port[i].magic = RISCOM8_MAGIC; - INIT_WORK(&rc_port[i].tqueue, do_softint, &rc_port[i]); - INIT_WORK(&rc_port[i].tqueue_hangup, do_rc_hangup, &rc_port[i]); + INIT_WORK(&rc_port[i].tqueue, do_softint); + INIT_WORK(&rc_port[i].tqueue_hangup, do_rc_hangup); rc_port[i].close_delay = 50 * HZ/100; rc_port[i].closing_wait = 3000 * HZ/100; init_waitqueue_head(&rc_port[i].open_wait); diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 3af7f0958c5..9ba13af234b 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -706,9 +706,9 @@ cd2401_rx_interrupt(int irq, void *dev_id) * had to poll every port to see if that port needed servicing. */ static void -do_softint(void *private_) +do_softint(struct work_struct *ugly_api) { - struct cyclades_port *info = (struct cyclades_port *) private_; + struct cyclades_port *info = container_of(ugly_api, struct cyclades_port, tqueue); struct tty_struct *tty; tty = info->tty; @@ -2273,7 +2273,7 @@ scrn[1] = '\0'; info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue, do_softint); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); /* info->session */ diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index c084149153d..fc87070f186 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -765,7 +765,7 @@ static void sonypi_setbluetoothpower(u8 state) sonypi_device.bluetooth_power = state; } -static void input_keyrelease(void *data) +static void input_keyrelease(struct work_struct *work) { struct sonypi_keypress kp; @@ -1412,7 +1412,7 @@ static int __devinit sonypi_probe(struct platform_device *dev) goto err_inpdev_unregister; } - INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL); + INIT_WORK(&sonypi_device.input_work, input_keyrelease); } sonypi_enable(0); diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 7e1bd9562c2..99137ab66b6 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -2261,9 +2261,10 @@ static void sx_start(struct tty_struct * tty) * do_sx_hangup() -> tty->hangup() -> sx_hangup() * */ -static void do_sx_hangup(void *private_) +static void do_sx_hangup(struct work_struct *work) { - struct specialix_port *port = (struct specialix_port *) private_; + struct specialix_port *port = + container_of(work, struct specialix_port, tqueue_hangup); struct tty_struct *tty; func_enter(); @@ -2336,9 +2337,10 @@ static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios } -static void do_softint(void *private_) +static void do_softint(struct work_struct *work) { - struct specialix_port *port = (struct specialix_port *) private_; + struct specialix_port *port = + container_of(work, struct specialix_port, tqueue); struct tty_struct *tty; func_enter(); @@ -2411,8 +2413,8 @@ static int sx_init_drivers(void) memset(sx_port, 0, sizeof(sx_port)); for (i = 0; i < SX_NPORT * SX_NBOARD; i++) { sx_port[i].magic = SPECIALIX_MAGIC; - INIT_WORK(&sx_port[i].tqueue, do_softint, &sx_port[i]); - INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup, &sx_port[i]); + INIT_WORK(&sx_port[i].tqueue, do_softint); + INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup); sx_port[i].close_delay = 50 * HZ/100; sx_port[i].closing_wait = 3000 * HZ/100; init_waitqueue_head(&sx_port[i].open_wait); diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 522e88e395c..5e2de62bce7 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -500,7 +500,7 @@ static int stl_echatintr(stlbrd_t *brdp); static int stl_echmcaintr(stlbrd_t *brdp); static int stl_echpciintr(stlbrd_t *brdp); static int stl_echpci64intr(stlbrd_t *brdp); -static void stl_offintr(void *private); +static void stl_offintr(struct work_struct *); static stlbrd_t *stl_allocbrd(void); static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); @@ -2081,14 +2081,12 @@ static int stl_echpci64intr(stlbrd_t *brdp) /* * Service an off-level request for some channel. */ -static void stl_offintr(void *private) +static void stl_offintr(struct work_struct *work) { - stlport_t *portp; + stlport_t *portp = container_of(work, stlport_t, tqueue); struct tty_struct *tty; unsigned int oldsigs; - portp = private; - #ifdef DEBUG printk("stl_offintr(portp=%x)\n", (int) portp); #endif @@ -2156,7 +2154,7 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) portp->baud_base = STL_BAUDBASE; portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; - INIT_WORK(&portp->tqueue, stl_offintr, portp); + INIT_WORK(&portp->tqueue, stl_offintr); init_waitqueue_head(&portp->open_wait); init_waitqueue_head(&portp->close_wait); portp->stats.brd = portp->brdnr; diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 06784adcc35..147c30da81e 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -802,7 +802,7 @@ static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, u /* * Bottom half interrupt handlers */ -static void mgsl_bh_handler(void* Context); +static void mgsl_bh_handler(struct work_struct *work); static void mgsl_bh_receive(struct mgsl_struct *info); static void mgsl_bh_transmit(struct mgsl_struct *info); static void mgsl_bh_status(struct mgsl_struct *info); @@ -1071,9 +1071,10 @@ static int mgsl_bh_action(struct mgsl_struct *info) /* * Perform bottom half processing of work items queued by ISR. */ -static void mgsl_bh_handler(void* Context) +static void mgsl_bh_handler(struct work_struct *work) { - struct mgsl_struct *info = (struct mgsl_struct*)Context; + struct mgsl_struct *info = + container_of(work, struct mgsl_struct, task); int action; if (!info) @@ -4337,7 +4338,7 @@ static struct mgsl_struct* mgsl_allocate_device(void) } else { memset(info, 0, sizeof(struct mgsl_struct)); info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, mgsl_bh_handler, info); + INIT_WORK(&info->task, mgsl_bh_handler); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index d4334c79f8d..07f34d43dc7 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -485,7 +485,7 @@ static void enable_loopback(struct slgt_info *info); static void set_rate(struct slgt_info *info, u32 data_rate); static int bh_action(struct slgt_info *info); -static void bh_handler(void* context); +static void bh_handler(struct work_struct *work); static void bh_transmit(struct slgt_info *info); static void isr_serial(struct slgt_info *info); static void isr_rdma(struct slgt_info *info); @@ -1878,9 +1878,9 @@ static int bh_action(struct slgt_info *info) /* * perform bottom half processing */ -static void bh_handler(void* context) +static void bh_handler(struct work_struct *work) { - struct slgt_info *info = context; + struct slgt_info *info = container_of(work, struct slgt_info, task); int action; if (!info) @@ -3326,7 +3326,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev } else { memset(info, 0, sizeof(struct slgt_info)); info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, bh_handler, info); + INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->raw_rx_size = DMABUFSIZE; info->close_delay = 5*HZ/10; @@ -4799,6 +4799,6 @@ static void rx_timeout(unsigned long context) spin_lock_irqsave(&info->lock, flags); info->pending_bh |= BH_RECEIVE; spin_unlock_irqrestore(&info->lock, flags); - bh_handler(info); + bh_handler(&info->task); } diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 3e932b68137..13a57245cf2 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -602,7 +602,7 @@ static void enable_loopback(SLMP_INFO *info, int enable); static void set_rate(SLMP_INFO *info, u32 data_rate); static int bh_action(SLMP_INFO *info); -static void bh_handler(void* Context); +static void bh_handler(struct work_struct *work); static void bh_receive(SLMP_INFO *info); static void bh_transmit(SLMP_INFO *info); static void bh_status(SLMP_INFO *info); @@ -2063,9 +2063,9 @@ int bh_action(SLMP_INFO *info) /* Perform bottom half processing of work items queued by ISR. */ -void bh_handler(void* Context) +void bh_handler(struct work_struct *work) { - SLMP_INFO *info = (SLMP_INFO*)Context; + SLMP_INFO *info = container_of(work, SLMP_INFO, task); int action; if (!info) @@ -3805,7 +3805,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) } else { memset(info, 0, sizeof(SLMP_INFO)); info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, bh_handler, info); + INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 5f49280779f..c64f5bcff94 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -219,13 +219,13 @@ static struct sysrq_key_op sysrq_term_op = { .enable_mask = SYSRQ_ENABLE_SIGNAL, }; -static void moom_callback(void *ignored) +static void moom_callback(struct work_struct *ignored) { out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], GFP_KERNEL, 0); } -static DECLARE_WORK(moom_work, moom_callback, NULL); +static DECLARE_WORK(moom_work, moom_callback); static void sysrq_handle_moom(int key, struct tty_struct *tty) { diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 6e1329d404d..774fa861169 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -325,9 +325,9 @@ static void user_reader_timeout(unsigned long ptr) schedule_work(&chip->work); } -static void timeout_work(void *ptr) +static void timeout_work(struct work_struct *work) { - struct tpm_chip *chip = ptr; + struct tpm_chip *chip = container_of(work, struct tpm_chip, work); down(&chip->buffer_mutex); atomic_set(&chip->data_pending, 0); @@ -1105,7 +1105,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend init_MUTEX(&chip->tpm_mutex); INIT_LIST_HEAD(&chip->list); - INIT_WORK(&chip->work, timeout_work, chip); + INIT_WORK(&chip->work, timeout_work); init_timer(&chip->user_read_timer); chip->user_read_timer.function = user_reader_timeout; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 50dc49205a2..b3cfc8bc613 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1254,7 +1254,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); /** * do_tty_hangup - actual handler for hangup events - * @data: tty device + * @work: tty device * * This can be called by the "eventd" kernel thread. That is process * synchronous but doesn't hold any locks, so we need to make sure we @@ -1274,9 +1274,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); * tasklist_lock to walk task list for hangup event * */ -static void do_tty_hangup(void *data) +static void do_tty_hangup(struct work_struct *work) { - struct tty_struct *tty = (struct tty_struct *) data; + struct tty_struct *tty = + container_of(work, struct tty_struct, hangup_work); struct file * cons_filp = NULL; struct file *filp, *f = NULL; struct task_struct *p; @@ -1433,7 +1434,7 @@ void tty_vhangup(struct tty_struct * tty) printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); #endif - do_tty_hangup((void *) tty); + do_tty_hangup(&tty->hangup_work); } EXPORT_SYMBOL(tty_vhangup); @@ -3304,12 +3305,13 @@ int tty_ioctl(struct inode * inode, struct file * file, * Nasty bug: do_SAK is being called in interrupt context. This can * deadlock. We punt it up to process context. AKPM - 16Mar2001 */ -static void __do_SAK(void *arg) +static void __do_SAK(struct work_struct *work) { + struct tty_struct *tty = + container_of(work, struct tty_struct, SAK_work); #ifdef TTY_SOFT_SAK tty_hangup(tty); #else - struct tty_struct *tty = arg; struct task_struct *g, *p; int session; int i; @@ -3388,7 +3390,7 @@ void do_SAK(struct tty_struct *tty) { if (!tty) return; - PREPARE_WORK(&tty->SAK_work, __do_SAK, tty); + PREPARE_WORK(&tty->SAK_work, __do_SAK); schedule_work(&tty->SAK_work); } @@ -3396,7 +3398,7 @@ EXPORT_SYMBOL(do_SAK); /** * flush_to_ldisc - * @private_: tty structure passed from work queue. + * @work: tty structure passed from work queue. * * This routine is called out of the software interrupt to flush data * from the buffer chain to the line discipline. @@ -3406,9 +3408,10 @@ EXPORT_SYMBOL(do_SAK); * receive_buf method is single threaded for each tty instance. */ -static void flush_to_ldisc(void *private_) +static void flush_to_ldisc(struct work_struct *work) { - struct tty_struct *tty = (struct tty_struct *) private_; + struct tty_struct *tty = + container_of(work, struct tty_struct, buf.work.work); unsigned long flags; struct tty_ldisc *disc; struct tty_buffer *tbuf, *head; @@ -3553,7 +3556,7 @@ void tty_flip_buffer_push(struct tty_struct *tty) spin_unlock_irqrestore(&tty->buf.lock, flags); if (tty->low_latency) - flush_to_ldisc((void *) tty); + flush_to_ldisc(&tty->buf.work.work); else schedule_delayed_work(&tty->buf.work, 1); } @@ -3580,17 +3583,17 @@ static void initialize_tty_struct(struct tty_struct *tty) tty->overrun_time = jiffies; tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); - INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); + INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); init_MUTEX(&tty->buf.pty_sem); mutex_init(&tty->termios_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); - INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); + INIT_WORK(&tty->hangup_work, do_tty_hangup); mutex_init(&tty->atomic_read_lock); mutex_init(&tty->atomic_write_lock); spin_lock_init(&tty->read_lock); INIT_LIST_HEAD(&tty->tty_files); - INIT_WORK(&tty->SAK_work, NULL, NULL); + INIT_WORK(&tty->SAK_work, NULL); } /* diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 87587b4385a..75ff0286e1a 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -155,7 +155,7 @@ static void con_flush_chars(struct tty_struct *tty); static void set_vesa_blanking(char __user *p); static void set_cursor(struct vc_data *vc); static void hide_cursor(struct vc_data *vc); -static void console_callback(void *ignored); +static void console_callback(struct work_struct *ignored); static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); @@ -174,7 +174,7 @@ static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ static int blankinterval = 10*60*HZ; static int vesa_off_interval; -static DECLARE_WORK(console_work, console_callback, NULL); +static DECLARE_WORK(console_work, console_callback); /* * fg_console is the current virtual console, @@ -2154,7 +2154,7 @@ out: * with other console code and prevention of re-entrancy is * ensured with console_sem. */ -static void console_callback(void *ignored) +static void console_callback(struct work_struct *ignored) { acquire_console_sem(); diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index 05f8ce2cfb4..b418b16e910 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -31,9 +31,11 @@ #include <linux/connector.h> #include <linux/delay.h> -void cn_queue_wrapper(void *data) +void cn_queue_wrapper(struct work_struct *work) { - struct cn_callback_data *d = data; + struct cn_callback_entry *cbq = + container_of(work, struct cn_callback_entry, work.work); + struct cn_callback_data *d = &cbq->data; d->callback(d->callback_priv); @@ -57,7 +59,7 @@ static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struc memcpy(&cbq->id.id, id, sizeof(struct cb_id)); cbq->data.callback = callback; - INIT_WORK(&cbq->work, &cn_queue_wrapper, &cbq->data); + INIT_DELAYED_WORK(&cbq->work, &cn_queue_wrapper); return cbq; } diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index b49bacfd8de..5e7cd45d10e 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -135,40 +135,39 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v spin_lock_bh(&dev->cbdev->queue_lock); list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) { if (cn_cb_equal(&__cbq->id.id, &msg->id)) { - if (likely(!test_bit(0, &__cbq->work.pending) && + if (likely(!test_bit(WORK_STRUCT_PENDING, + &__cbq->work.work.management) && __cbq->data.ddata == NULL)) { __cbq->data.callback_priv = msg; __cbq->data.ddata = data; __cbq->data.destruct_data = destruct_data; - if (queue_work(dev->cbdev->cn_queue, - &__cbq->work)) + if (queue_delayed_work( + dev->cbdev->cn_queue, + &__cbq->work, 0)) err = 0; } else { - struct work_struct *w; struct cn_callback_data *d; - w = kzalloc(sizeof(*w) + sizeof(*d), GFP_ATOMIC); - if (w) { - d = (struct cn_callback_data *)(w+1); - + __cbq = kzalloc(sizeof(*__cbq), GFP_ATOMIC); + if (__cbq) { + d = &__cbq->data; d->callback_priv = msg; d->callback = __cbq->data.callback; d->ddata = data; d->destruct_data = destruct_data; - d->free = w; + d->free = __cbq; - INIT_LIST_HEAD(&w->entry); - w->pending = 0; - w->func = &cn_queue_wrapper; - w->data = d; - init_timer(&w->timer); + INIT_DELAYED_WORK(&__cbq->work, + &cn_queue_wrapper); - if (queue_work(dev->cbdev->cn_queue, w)) + if (queue_delayed_work( + dev->cbdev->cn_queue, + &__cbq->work, 0)) err = 0; else { - kfree(w); + kfree(__cbq); err = -EINVAL; } } else diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index dd0c2623e27..7a7c6e6dfe4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -42,7 +42,7 @@ static DEFINE_SPINLOCK(cpufreq_driver_lock); /* internal prototypes */ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); -static void handle_update(void *data); +static void handle_update(struct work_struct *work); /** * Two notifier lists: the "policy" list is involved in the @@ -665,7 +665,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) mutex_init(&policy->lock); mutex_lock(&policy->lock); init_completion(&policy->kobj_unregister); - INIT_WORK(&policy->update, handle_update, (void *)(long)cpu); + INIT_WORK(&policy->update, handle_update); /* call driver. From then on the cpufreq must be able * to accept all calls to ->verify and ->setpolicy for this CPU @@ -895,9 +895,11 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) } -static void handle_update(void *data) +static void handle_update(struct work_struct *work) { - unsigned int cpu = (unsigned int)(long)data; + struct cpufreq_policy *policy = + container_of(work, struct cpufreq_policy, update); + unsigned int cpu = policy->cpu; dprintk("handle_update for cpu %u called\n", cpu); cpufreq_update_policy(cpu); } diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index c4c578defab..5ef5ede5b88 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -59,7 +59,7 @@ static unsigned int def_sampling_rate; #define MAX_SAMPLING_DOWN_FACTOR (10) #define TRANSITION_LATENCY_LIMIT (10 * 1000) -static void do_dbs_timer(void *data); +static void do_dbs_timer(struct work_struct *work); struct cpu_dbs_info_s { struct cpufreq_policy *cur_policy; @@ -82,7 +82,7 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */ * is recursive for the same process. -Venki */ static DEFINE_MUTEX (dbs_mutex); -static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); +static DECLARE_DELAYED_WORK(dbs_work, do_dbs_timer); struct dbs_tuners { unsigned int sampling_rate; @@ -420,7 +420,7 @@ static void dbs_check_cpu(int cpu) } } -static void do_dbs_timer(void *data) +static void do_dbs_timer(struct work_struct *work) { int i; lock_cpu_hotplug(); @@ -435,7 +435,6 @@ static void do_dbs_timer(void *data) static inline void dbs_timer_init(void) { - INIT_WORK(&dbs_work, do_dbs_timer, NULL); schedule_delayed_work(&dbs_work, usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); return; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index bf8aa45d4f0..e1cc5113c2a 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -47,13 +47,17 @@ static unsigned int def_sampling_rate; #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define TRANSITION_LATENCY_LIMIT (10 * 1000) -static void do_dbs_timer(void *data); +static void do_dbs_timer(struct work_struct *work); + +/* Sampling types */ +enum dbs_sample {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; struct cpu_dbs_info_s { cputime64_t prev_cpu_idle; cputime64_t prev_cpu_wall; struct cpufreq_policy *cur_policy; - struct work_struct work; + struct delayed_work work; + enum dbs_sample sample_type; unsigned int enable; struct cpufreq_frequency_table *freq_table; unsigned int freq_lo; @@ -407,30 +411,31 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) } } -/* Sampling types */ -enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; - -static void do_dbs_timer(void *data) +static void do_dbs_timer(struct work_struct *work) { unsigned int cpu = smp_processor_id(); struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); + enum dbs_sample sample_type = dbs_info->sample_type; /* We want all CPUs to do sampling nearly on same jiffy */ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + /* Permit rescheduling of this work item */ + work_release(work); + delay -= jiffies % delay; if (!dbs_info->enable) return; /* Common NORMAL_SAMPLE setup */ - INIT_WORK(&dbs_info->work, do_dbs_timer, (void *)DBS_NORMAL_SAMPLE); + dbs_info->sample_type = DBS_NORMAL_SAMPLE; if (!dbs_tuners_ins.powersave_bias || - (unsigned long) data == DBS_NORMAL_SAMPLE) { + sample_type == DBS_NORMAL_SAMPLE) { lock_cpu_hotplug(); dbs_check_cpu(dbs_info); unlock_cpu_hotplug(); if (dbs_info->freq_lo) { /* Setup timer for SUB_SAMPLE */ - INIT_WORK(&dbs_info->work, do_dbs_timer, - (void *)DBS_SUB_SAMPLE); + dbs_info->sample_type = DBS_SUB_SAMPLE; delay = dbs_info->freq_hi_jiffies; } } else { @@ -449,7 +454,8 @@ static inline void dbs_timer_init(unsigned int cpu) delay -= jiffies % delay; ondemand_powersave_bias_init(); - INIT_WORK(&dbs_info->work, do_dbs_timer, NULL); + INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer); + dbs_info->sample_type = DBS_NORMAL_SAMPLE; queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); } diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index 4630f1969a0..15edf40828b 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -140,12 +140,14 @@ ulong ds1374_get_rtc_time(void) return t1; } -static void ds1374_set_work(void *arg) +static ulong new_time; + +static void ds1374_set_work(struct work_struct *work) { ulong t1, t2; int limit = 10; /* arbitrary retry limit */ - t1 = *(ulong *) arg; + t1 = new_time; mutex_lock(&ds1374_mutex); @@ -167,11 +169,9 @@ static void ds1374_set_work(void *arg) "can't confirm time set from rtc chip\n"); } -static ulong new_time; - static struct workqueue_struct *ds1374_workqueue; -static DECLARE_WORK(ds1374_work, ds1374_set_work, &new_time); +static DECLARE_WORK(ds1374_work, ds1374_set_work); int ds1374_set_rtc_time(ulong nowtime) { @@ -180,7 +180,7 @@ int ds1374_set_rtc_time(ulong nowtime) if (in_interrupt()) queue_work(ds1374_workqueue, &ds1374_work); else - ds1374_set_work(&new_time); + ds1374_set_work(NULL); return 0; } diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index 2dd0a34d947..420377c8642 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -215,8 +215,15 @@ m41t00_set(void *arg) } static ulong new_time; +/* well, isn't this API just _lovely_? */ +static void +m41t00_barf(struct work_struct *unusable) +{ + m41t00_set(&new_time); +} + static struct workqueue_struct *m41t00_wq; -static DECLARE_WORK(m41t00_work, m41t00_set, &new_time); +static DECLARE_WORK(m41t00_work, m41t00_barf); int m41t00_set_rtc_time(ulong nowtime) diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index bef4759f70e..7efd28ac21e 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -192,20 +192,10 @@ static int ide_config(struct pcmcia_device *link) tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &stk->parse)); - link->conf.ConfigBase = stk->parse.config.base; - link->conf.Present = stk->parse.config.rmask[0]; - - tuple.DesiredTuple = CISTPL_MANFID; - if (!pcmcia_get_first_tuple(link, &tuple) && - !pcmcia_get_tuple_data(link, &tuple) && - !pcmcia_parse_tuple(link, &tuple, &stk->parse)) - is_kme = ((stk->parse.manfid.manf == MANFID_KME) && - ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) || - (stk->parse.manfid.card == PRODID_KME_KXLC005_B))); + + is_kme = ((link->manf_id == MANFID_KME) && + ((link->card_id == PRODID_KME_KXLC005_A) || + (link->card_id == PRODID_KME_KXLC005_B))); /* Not sure if this is right... look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf)); @@ -408,8 +398,10 @@ static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6), PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003), PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1), PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8), PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), + PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918), PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e), PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6), diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c index d90a3a1898c..8f4378a1631 100644 --- a/drivers/ieee1394/hosts.c +++ b/drivers/ieee1394/hosts.c @@ -31,9 +31,10 @@ #include "config_roms.h" -static void delayed_reset_bus(void * __reset_info) +static void delayed_reset_bus(struct work_struct *work) { - struct hpsb_host *host = (struct hpsb_host*)__reset_info; + struct hpsb_host *host = + container_of(work, struct hpsb_host, delayed_reset.work); int generation = host->csr.generation + 1; /* The generation field rolls over to 2 rather than 0 per IEEE @@ -145,7 +146,7 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra, atomic_set(&h->generation, 0); - INIT_WORK(&h->delayed_reset, delayed_reset_bus, h); + INIT_DELAYED_WORK(&h->delayed_reset, delayed_reset_bus); init_timer(&h->timeout); h->timeout.data = (unsigned long) h; @@ -234,7 +235,7 @@ int hpsb_update_config_rom_image(struct hpsb_host *host) * Config ROM in the near future. */ reset_delay = HZ; - PREPARE_WORK(&host->delayed_reset, delayed_reset_bus, host); + PREPARE_DELAYED_WORK(&host->delayed_reset, delayed_reset_bus); schedule_delayed_work(&host->delayed_reset, reset_delay); return 0; diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h index bc6dbfadb89..d553e38c954 100644 --- a/drivers/ieee1394/hosts.h +++ b/drivers/ieee1394/hosts.h @@ -62,7 +62,7 @@ struct hpsb_host { struct class_device class_dev; int update_config_rom; - struct work_struct delayed_reset; + struct delayed_work delayed_reset; unsigned int config_roms; struct list_head addr_space; diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 6986ac18828..cd156d4e779 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -493,20 +493,25 @@ static void sbp2util_notify_fetch_agent(struct scsi_id_instance_data *scsi_id, scsi_unblock_requests(scsi_id->scsi_host); } -static void sbp2util_write_orb_pointer(void *p) +static void sbp2util_write_orb_pointer(struct work_struct *work) { + struct scsi_id_instance_data *scsi_id = + container_of(work, struct scsi_id_instance_data, + protocol_work.work); quadlet_t data[2]; - data[0] = ORB_SET_NODE_ID( - ((struct scsi_id_instance_data *)p)->hi->host->node_id); - data[1] = ((struct scsi_id_instance_data *)p)->last_orb_dma; + data[0] = ORB_SET_NODE_ID(scsi_id->hi->host->node_id); + data[1] = scsi_id->last_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); - sbp2util_notify_fetch_agent(p, SBP2_ORB_POINTER_OFFSET, data, 8); + sbp2util_notify_fetch_agent(scsi_id, SBP2_ORB_POINTER_OFFSET, data, 8); } -static void sbp2util_write_doorbell(void *p) +static void sbp2util_write_doorbell(struct work_struct *work) { - sbp2util_notify_fetch_agent(p, SBP2_DOORBELL_OFFSET, NULL, 4); + struct scsi_id_instance_data *scsi_id = + container_of(work, struct scsi_id_instance_data, + protocol_work.work); + sbp2util_notify_fetch_agent(scsi_id, SBP2_DOORBELL_OFFSET, NULL, 4); } /* @@ -843,7 +848,7 @@ static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud INIT_LIST_HEAD(&scsi_id->scsi_list); spin_lock_init(&scsi_id->sbp2_command_orb_lock); atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING); - INIT_WORK(&scsi_id->protocol_work, NULL, NULL); + INIT_DELAYED_WORK(&scsi_id->protocol_work, NULL); ud->device.driver_data = scsi_id; @@ -2047,11 +2052,10 @@ static void sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id, * We do not accept new commands until the job is over. */ scsi_block_requests(scsi_id->scsi_host); - PREPARE_WORK(&scsi_id->protocol_work, + PREPARE_DELAYED_WORK(&scsi_id->protocol_work, last_orb ? sbp2util_write_doorbell: - sbp2util_write_orb_pointer, - scsi_id); - schedule_work(&scsi_id->protocol_work); + sbp2util_write_orb_pointer); + schedule_delayed_work(&scsi_id->protocol_work, 0); } } diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h index abbe48e646c..1b16d6b9cf1 100644 --- a/drivers/ieee1394/sbp2.h +++ b/drivers/ieee1394/sbp2.h @@ -348,7 +348,7 @@ struct scsi_id_instance_data { unsigned workarounds; atomic_t state; - struct work_struct protocol_work; + struct delayed_work protocol_work; }; /* For use in scsi_id_instance_data.state */ diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 7767a11b689..af939796750 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -55,11 +55,11 @@ struct addr_req { int status; }; -static void process_req(void *data); +static void process_req(struct work_struct *work); static DEFINE_MUTEX(lock); static LIST_HEAD(req_list); -static DECLARE_WORK(work, process_req, NULL); +static DECLARE_DELAYED_WORK(work, process_req); static struct workqueue_struct *addr_wq; void rdma_addr_register_client(struct rdma_addr_client *client) @@ -215,7 +215,7 @@ out: return ret; } -static void process_req(void *data) +static void process_req(struct work_struct *work) { struct addr_req *req, *temp_req; struct sockaddr_in *src_in, *dst_in; diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 20e9f64e67a..98272fbbfb3 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -285,9 +285,10 @@ err: kfree(tprops); } -static void ib_cache_task(void *work_ptr) +static void ib_cache_task(struct work_struct *_work) { - struct ib_update_work *work = work_ptr; + struct ib_update_work *work = + container_of(_work, struct ib_update_work, work); ib_cache_update(work->device, work->port_num); kfree(work); @@ -306,7 +307,7 @@ static void ib_cache_event(struct ib_event_handler *handler, event->event == IB_EVENT_CLIENT_REREGISTER) { work = kmalloc(sizeof *work, GFP_ATOMIC); if (work) { - INIT_WORK(&work->work, ib_cache_task, work); + INIT_WORK(&work->work, ib_cache_task); work->device = event->device; work->port_num = event->element.port_num; schedule_work(&work->work); diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index e5dc4530808..79c937bf696 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -101,7 +101,7 @@ struct cm_av { }; struct cm_work { - struct work_struct work; + struct delayed_work work; struct list_head list; struct cm_port *port; struct ib_mad_recv_wc *mad_recv_wc; /* Received MADs */ @@ -161,7 +161,7 @@ struct cm_id_private { atomic_t work_count; }; -static void cm_work_handler(void *data); +static void cm_work_handler(struct work_struct *work); static inline void cm_deref_id(struct cm_id_private *cm_id_priv) { @@ -668,8 +668,7 @@ static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id) return ERR_PTR(-ENOMEM); timewait_info->work.local_id = local_id; - INIT_WORK(&timewait_info->work.work, cm_work_handler, - &timewait_info->work); + INIT_DELAYED_WORK(&timewait_info->work.work, cm_work_handler); timewait_info->work.cm_event.event = IB_CM_TIMEWAIT_EXIT; return timewait_info; } @@ -2995,9 +2994,9 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent, } } -static void cm_work_handler(void *data) +static void cm_work_handler(struct work_struct *_work) { - struct cm_work *work = data; + struct cm_work *work = container_of(_work, struct cm_work, work.work); int ret; switch (work->cm_event.event) { @@ -3087,12 +3086,12 @@ static int cm_establish(struct ib_cm_id *cm_id) * we need to find the cm_id once we're in the context of the * worker thread, rather than holding a reference on it. */ - INIT_WORK(&work->work, cm_work_handler, work); + INIT_DELAYED_WORK(&work->work, cm_work_handler); work->local_id = cm_id->local_id; work->remote_id = cm_id->remote_id; work->mad_recv_wc = NULL; work->cm_event.event = IB_CM_USER_ESTABLISHED; - queue_work(cm.wq, &work->work); + queue_delayed_work(cm.wq, &work->work, 0); out: return ret; } @@ -3191,11 +3190,11 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, return; } - INIT_WORK(&work->work, cm_work_handler, work); + INIT_DELAYED_WORK(&work->work, cm_work_handler); work->cm_event.event = event; work->mad_recv_wc = mad_recv_wc; work->port = (struct cm_port *)mad_agent->context; - queue_work(cm.wq, &work->work); + queue_delayed_work(cm.wq, &work->work, 0); } static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv, diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index cf48f269743..985a6b564d8 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1340,9 +1340,9 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, return (id_priv->query_id < 0) ? id_priv->query_id : 0; } -static void cma_work_handler(void *data) +static void cma_work_handler(struct work_struct *_work) { - struct cma_work *work = data; + struct cma_work *work = container_of(_work, struct cma_work, work); struct rdma_id_private *id_priv = work->id; int destroy = 0; @@ -1373,7 +1373,7 @@ static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) return -ENOMEM; work->id = id_priv; - INIT_WORK(&work->work, cma_work_handler, work); + INIT_WORK(&work->work, cma_work_handler); work->old_state = CMA_ROUTE_QUERY; work->new_state = CMA_ROUTE_RESOLVED; work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; @@ -1430,7 +1430,7 @@ static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) return -ENOMEM; work->id = id_priv; - INIT_WORK(&work->work, cma_work_handler, work); + INIT_WORK(&work->work, cma_work_handler); work->old_state = CMA_ROUTE_QUERY; work->new_state = CMA_ROUTE_RESOLVED; work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; @@ -1583,7 +1583,7 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv) } work->id = id_priv; - INIT_WORK(&work->work, cma_work_handler, work); + INIT_WORK(&work->work, cma_work_handler); work->old_state = CMA_ADDR_QUERY; work->new_state = CMA_ADDR_RESOLVED; work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index cf797d7aea0..1039ad57d53 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -828,9 +828,9 @@ static int process_event(struct iwcm_id_private *cm_id_priv, * thread asleep on the destroy_comp list vs. an object destroyed * here synchronously when the last reference is removed. */ -static void cm_work_handler(void *arg) +static void cm_work_handler(struct work_struct *_work) { - struct iwcm_work *work = arg; + struct iwcm_work *work = container_of(_work, struct iwcm_work, work); struct iw_cm_event levent; struct iwcm_id_private *cm_id_priv = work->cm_id; unsigned long flags; @@ -900,7 +900,7 @@ static int cm_event_handler(struct iw_cm_id *cm_id, goto out; } - INIT_WORK(&work->work, cm_work_handler, work); + INIT_WORK(&work->work, cm_work_handler); work->cm_id = cm_id_priv; work->event = *iw_event; diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 3f9c16232c4..15f38d94b3a 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -65,8 +65,8 @@ static struct ib_mad_agent_private *find_mad_agent( static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info, struct ib_mad_private *mad); static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv); -static void timeout_sends(void *data); -static void local_completions(void *data); +static void timeout_sends(struct work_struct *work); +static void local_completions(struct work_struct *work); static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req, struct ib_mad_agent_private *agent_priv, u8 mgmt_class); @@ -356,10 +356,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, INIT_LIST_HEAD(&mad_agent_priv->wait_list); INIT_LIST_HEAD(&mad_agent_priv->done_list); INIT_LIST_HEAD(&mad_agent_priv->rmpp_list); - INIT_WORK(&mad_agent_priv->timed_work, timeout_sends, mad_agent_priv); + INIT_DELAYED_WORK(&mad_agent_priv->timed_work, timeout_sends); INIT_LIST_HEAD(&mad_agent_priv->local_list); - INIT_WORK(&mad_agent_priv->local_work, local_completions, - mad_agent_priv); + INIT_WORK(&mad_agent_priv->local_work, local_completions); atomic_set(&mad_agent_priv->refcount, 1); init_completion(&mad_agent_priv->comp); @@ -2198,12 +2197,12 @@ static void mad_error_handler(struct ib_mad_port_private *port_priv, /* * IB MAD completion callback */ -static void ib_mad_completion_handler(void *data) +static void ib_mad_completion_handler(struct work_struct *work) { struct ib_mad_port_private *port_priv; struct ib_wc wc; - port_priv = (struct ib_mad_port_private *)data; + port_priv = container_of(work, struct ib_mad_port_private, work); ib_req_notify_cq(port_priv->cq, IB_CQ_NEXT_COMP); while (ib_poll_cq(port_priv->cq, 1, &wc) == 1) { @@ -2324,7 +2323,7 @@ void ib_cancel_mad(struct ib_mad_agent *mad_agent, } EXPORT_SYMBOL(ib_cancel_mad); -static void local_completions(void *data) +static void local_completions(struct work_struct *work) { struct ib_mad_agent_private *mad_agent_priv; struct ib_mad_local_private *local; @@ -2334,7 +2333,8 @@ static void local_completions(void *data) struct ib_wc wc; struct ib_mad_send_wc mad_send_wc; - mad_agent_priv = (struct ib_mad_agent_private *)data; + mad_agent_priv = + container_of(work, struct ib_mad_agent_private, local_work); spin_lock_irqsave(&mad_agent_priv->lock, flags); while (!list_empty(&mad_agent_priv->local_list)) { @@ -2434,14 +2434,15 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr) return ret; } -static void timeout_sends(void *data) +static void timeout_sends(struct work_struct *work) { struct ib_mad_agent_private *mad_agent_priv; struct ib_mad_send_wr_private *mad_send_wr; struct ib_mad_send_wc mad_send_wc; unsigned long flags, delay; - mad_agent_priv = (struct ib_mad_agent_private *)data; + mad_agent_priv = container_of(work, struct ib_mad_agent_private, + timed_work.work); mad_send_wc.vendor_err = 0; spin_lock_irqsave(&mad_agent_priv->lock, flags); @@ -2799,7 +2800,7 @@ static int ib_mad_port_open(struct ib_device *device, ret = -ENOMEM; goto error8; } - INIT_WORK(&port_priv->work, ib_mad_completion_handler, port_priv); + INIT_WORK(&port_priv->work, ib_mad_completion_handler); spin_lock_irqsave(&ib_mad_port_list_lock, flags); list_add_tail(&port_priv->port_list, &ib_mad_port_list); diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index d06b59083f6..d5548e73e06 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -102,7 +102,7 @@ struct ib_mad_agent_private { struct list_head send_list; struct list_head wait_list; struct list_head done_list; - struct work_struct timed_work; + struct delayed_work timed_work; unsigned long timeout; struct list_head local_list; struct work_struct local_work; diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index 1ef79d015a1..3663fd7022b 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -45,8 +45,8 @@ enum rmpp_state { struct mad_rmpp_recv { struct ib_mad_agent_private *agent; struct list_head list; - struct work_struct timeout_work; - struct work_struct cleanup_work; + struct delayed_work timeout_work; + struct delayed_work cleanup_work; struct completion comp; enum rmpp_state state; spinlock_t lock; @@ -233,9 +233,10 @@ static void nack_recv(struct ib_mad_agent_private *agent, } } -static void recv_timeout_handler(void *data) +static void recv_timeout_handler(struct work_struct *work) { - struct mad_rmpp_recv *rmpp_recv = data; + struct mad_rmpp_recv *rmpp_recv = + container_of(work, struct mad_rmpp_recv, timeout_work.work); struct ib_mad_recv_wc *rmpp_wc; unsigned long flags; @@ -254,9 +255,10 @@ static void recv_timeout_handler(void *data) ib_free_recv_mad(rmpp_wc); } -static void recv_cleanup_handler(void *data) +static void recv_cleanup_handler(struct work_struct *work) { - struct mad_rmpp_recv *rmpp_recv = data; + struct mad_rmpp_recv *rmpp_recv = + container_of(work, struct mad_rmpp_recv, cleanup_work.work); unsigned long flags; spin_lock_irqsave(&rmpp_recv->agent->lock, flags); @@ -285,8 +287,8 @@ create_rmpp_recv(struct ib_mad_agent_private *agent, rmpp_recv->agent = agent; init_completion(&rmpp_recv->comp); - INIT_WORK(&rmpp_recv->timeout_work, recv_timeout_handler, rmpp_recv); - INIT_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler, rmpp_recv); + INIT_DELAYED_WORK(&rmpp_recv->timeout_work, recv_timeout_handler); + INIT_DELAYED_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler); spin_lock_init(&rmpp_recv->lock); rmpp_recv->state = RMPP_STATE_ACTIVE; atomic_set(&rmpp_recv->refcount, 1); diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 1706d3c7e95..e45afba7534 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -360,9 +360,10 @@ static void free_sm_ah(struct kref *kref) kfree(sm_ah); } -static void update_sm_ah(void *port_ptr) +static void update_sm_ah(struct work_struct *work) { - struct ib_sa_port *port = port_ptr; + struct ib_sa_port *port = + container_of(work, struct ib_sa_port, update_task); struct ib_sa_sm_ah *new_ah, *old_ah; struct ib_port_attr port_attr; struct ib_ah_attr ah_attr; @@ -992,8 +993,7 @@ static void ib_sa_add_one(struct ib_device *device) if (IS_ERR(sa_dev->port[i].agent)) goto err; - INIT_WORK(&sa_dev->port[i].update_task, - update_sm_ah, &sa_dev->port[i]); + INIT_WORK(&sa_dev->port[i].update_task, update_sm_ah); } ib_set_client_data(device, &sa_client, sa_dev); @@ -1010,7 +1010,7 @@ static void ib_sa_add_one(struct ib_device *device) goto err; for (i = 0; i <= e - s; ++i) - update_sm_ah(&sa_dev->port[i]); + update_sm_ah(&sa_dev->port[i].update_task); return; diff --git a/drivers/infiniband/core/uverbs_mem.c b/drivers/infiniband/core/uverbs_mem.c index efe147dbeb4..db12cc0841d 100644 --- a/drivers/infiniband/core/uverbs_mem.c +++ b/drivers/infiniband/core/uverbs_mem.c @@ -179,9 +179,10 @@ void ib_umem_release(struct ib_device *dev, struct ib_umem *umem) up_write(¤t->mm->mmap_sem); } -static void ib_umem_account(void *work_ptr) +static void ib_umem_account(struct work_struct *_work) { - struct ib_umem_account_work *work = work_ptr; + struct ib_umem_account_work *work = + container_of(_work, struct ib_umem_account_work, work); down_write(&work->mm->mmap_sem); work->mm->locked_vm -= work->diff; @@ -216,7 +217,7 @@ void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem) return; } - INIT_WORK(&work->work, ib_umem_account, work); + INIT_WORK(&work->work, ib_umem_account); work->mm = mm; work->diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT; diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c index 413754b1d8a..8536aeb96af 100644 --- a/drivers/infiniband/hw/ipath/ipath_user_pages.c +++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c @@ -214,9 +214,10 @@ struct ipath_user_pages_work { unsigned long num_pages; }; -static void user_pages_account(void *ptr) +static void user_pages_account(struct work_struct *_work) { - struct ipath_user_pages_work *work = ptr; + struct ipath_user_pages_work *work = + container_of(_work, struct ipath_user_pages_work, work); down_write(&work->mm->mmap_sem); work->mm->locked_vm -= work->num_pages; @@ -242,7 +243,7 @@ void ipath_release_user_pages_on_close(struct page **p, size_t num_pages) goto bail; - INIT_WORK(&work->work, user_pages_account, work); + INIT_WORK(&work->work, user_pages_account); work->mm = mm; work->num_pages = num_pages; diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index cd044ea2dfa..e948158a28d 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c @@ -57,7 +57,7 @@ static int catas_reset_disable; module_param_named(catas_reset_disable, catas_reset_disable, int, 0644); MODULE_PARM_DESC(catas_reset_disable, "disable reset on catastrophic event if nonzero"); -static void catas_reset(void *work_ptr) +static void catas_reset(struct work_struct *work) { struct mthca_dev *dev, *tmpdev; LIST_HEAD(tlist); @@ -203,7 +203,7 @@ void mthca_stop_catas_poll(struct mthca_dev *dev) int __init mthca_catas_init(void) { - INIT_WORK(&catas_work, catas_reset, NULL); + INIT_WORK(&catas_work, catas_reset); catas_wq = create_singlethread_workqueue("mthca_catas"); if (!catas_wq) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index f2b61851a49..99547996aba 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -136,11 +136,11 @@ struct ipoib_dev_priv { struct list_head multicast_list; struct rb_root multicast_tree; - struct work_struct pkey_task; - struct work_struct mcast_task; + struct delayed_work pkey_task; + struct delayed_work mcast_task; struct work_struct flush_task; struct work_struct restart_task; - struct work_struct ah_reap_task; + struct delayed_work ah_reap_task; struct ib_device *ca; u8 port; @@ -254,13 +254,13 @@ int ipoib_add_pkey_attr(struct net_device *dev); void ipoib_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_ah *address, u32 qpn); -void ipoib_reap_ah(void *dev_ptr); +void ipoib_reap_ah(struct work_struct *work); void ipoib_flush_paths(struct net_device *dev); struct ipoib_dev_priv *ipoib_intf_alloc(const char *format); int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port); -void ipoib_ib_dev_flush(void *dev); +void ipoib_ib_dev_flush(struct work_struct *work); void ipoib_ib_dev_cleanup(struct net_device *dev); int ipoib_ib_dev_open(struct net_device *dev); @@ -271,10 +271,10 @@ int ipoib_ib_dev_stop(struct net_device *dev); int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port); void ipoib_dev_cleanup(struct net_device *dev); -void ipoib_mcast_join_task(void *dev_ptr); +void ipoib_mcast_join_task(struct work_struct *work); void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb); -void ipoib_mcast_restart_task(void *dev_ptr); +void ipoib_mcast_restart_task(struct work_struct *work); int ipoib_mcast_start_thread(struct net_device *dev); int ipoib_mcast_stop_thread(struct net_device *dev, int flush); @@ -312,7 +312,7 @@ void ipoib_event(struct ib_event_handler *handler, int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey); int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey); -void ipoib_pkey_poll(void *dev); +void ipoib_pkey_poll(struct work_struct *work); int ipoib_pkey_dev_delay_open(struct net_device *dev); #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 8bf5e9ec7c9..f10fba5d326 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -400,10 +400,11 @@ static void __ipoib_reap_ah(struct net_device *dev) spin_unlock_irq(&priv->tx_lock); } -void ipoib_reap_ah(void *dev_ptr) +void ipoib_reap_ah(struct work_struct *work) { - struct net_device *dev = dev_ptr; - struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, ah_reap_task.work); + struct net_device *dev = priv->dev; __ipoib_reap_ah(dev); @@ -613,10 +614,11 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port) return 0; } -void ipoib_ib_dev_flush(void *_dev) +void ipoib_ib_dev_flush(struct work_struct *work) { - struct net_device *dev = (struct net_device *)_dev; - struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv; + struct ipoib_dev_priv *cpriv, *priv = + container_of(work, struct ipoib_dev_priv, flush_task); + struct net_device *dev = priv->dev; if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags) ) { ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n"); @@ -638,14 +640,14 @@ void ipoib_ib_dev_flush(void *_dev) */ if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { ipoib_ib_dev_up(dev); - ipoib_mcast_restart_task(dev); + ipoib_mcast_restart_task(&priv->restart_task); } mutex_lock(&priv->vlan_mutex); /* Flush any child interfaces too */ list_for_each_entry(cpriv, &priv->child_intfs, list) - ipoib_ib_dev_flush(cpriv->dev); + ipoib_ib_dev_flush(&cpriv->flush_task); mutex_unlock(&priv->vlan_mutex); } @@ -672,10 +674,11 @@ void ipoib_ib_dev_cleanup(struct net_device *dev) * change async notification is available. */ -void ipoib_pkey_poll(void *dev_ptr) +void ipoib_pkey_poll(struct work_struct *work) { - struct net_device *dev = dev_ptr; - struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, pkey_task.work); + struct net_device *dev = priv->dev; ipoib_pkey_dev_check_presence(dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 5ba3154320b..c0928024372 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -940,11 +940,11 @@ static void ipoib_setup(struct net_device *dev) INIT_LIST_HEAD(&priv->dead_ahs); INIT_LIST_HEAD(&priv->multicast_list); - INIT_WORK(&priv->pkey_task, ipoib_pkey_poll, priv->dev); - INIT_WORK(&priv->mcast_task, ipoib_mcast_join_task, priv->dev); - INIT_WORK(&priv->flush_task, ipoib_ib_dev_flush, priv->dev); - INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task, priv->dev); - INIT_WORK(&priv->ah_reap_task, ipoib_reap_ah, priv->dev); + INIT_DELAYED_WORK(&priv->pkey_task, ipoib_pkey_poll); + INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); + INIT_WORK(&priv->flush_task, ipoib_ib_dev_flush); + INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); + INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah); } struct ipoib_dev_priv *ipoib_intf_alloc(const char *name) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index d282d65e3ee..b04b72ca32e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -399,7 +399,8 @@ static void ipoib_mcast_join_complete(int status, mcast->backoff = 1; mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) - queue_work(ipoib_workqueue, &priv->mcast_task); + queue_delayed_work(ipoib_workqueue, + &priv->mcast_task, 0); mutex_unlock(&mcast_mutex); complete(&mcast->done); return; @@ -435,7 +436,8 @@ static void ipoib_mcast_join_complete(int status, if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) { if (status == -ETIMEDOUT) - queue_work(ipoib_workqueue, &priv->mcast_task); + queue_delayed_work(ipoib_workqueue, &priv->mcast_task, + 0); else queue_delayed_work(ipoib_workqueue, &priv->mcast_task, mcast->backoff * HZ); @@ -517,10 +519,11 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, mcast->query_id = ret; } -void ipoib_mcast_join_task(void *dev_ptr) +void ipoib_mcast_join_task(struct work_struct *work) { - struct net_device *dev = dev_ptr; - struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, mcast_task.work); + struct net_device *dev = priv->dev; if (!test_bit(IPOIB_MCAST_RUN, &priv->flags)) return; @@ -610,7 +613,7 @@ int ipoib_mcast_start_thread(struct net_device *dev) mutex_lock(&mcast_mutex); if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags)) - queue_work(ipoib_workqueue, &priv->mcast_task); + queue_delayed_work(ipoib_workqueue, &priv->mcast_task, 0); mutex_unlock(&mcast_mutex); spin_lock_irq(&priv->lock); @@ -818,10 +821,11 @@ void ipoib_mcast_dev_flush(struct net_device *dev) } } -void ipoib_mcast_restart_task(void *dev_ptr) +void ipoib_mcast_restart_task(struct work_struct *work) { - struct net_device *dev = dev_ptr; - struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, restart_task); + struct net_device *dev = priv->dev; struct dev_mc_list *mclist; struct ipoib_mcast *mcast, *tmcast; LIST_HEAD(remove_list); diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 18a00003499..693b7700289 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -48,7 +48,7 @@ static void iser_cq_tasklet_fn(unsigned long data); static void iser_cq_callback(struct ib_cq *cq, void *cq_context); -static void iser_comp_error_worker(void *data); +static void iser_comp_error_worker(struct work_struct *work); static void iser_cq_event_callback(struct ib_event *cause, void *context) { @@ -480,8 +480,7 @@ int iser_conn_init(struct iser_conn **ibconn) init_waitqueue_head(&ib_conn->wait); atomic_set(&ib_conn->post_recv_buf_count, 0); atomic_set(&ib_conn->post_send_buf_count, 0); - INIT_WORK(&ib_conn->comperror_work, iser_comp_error_worker, - ib_conn); + INIT_WORK(&ib_conn->comperror_work, iser_comp_error_worker); INIT_LIST_HEAD(&ib_conn->conn_list); spin_lock_init(&ib_conn->lock); @@ -754,9 +753,10 @@ int iser_post_send(struct iser_desc *tx_desc) return ret_val; } -static void iser_comp_error_worker(void *data) +static void iser_comp_error_worker(struct work_struct *work) { - struct iser_conn *ib_conn = data; + struct iser_conn *ib_conn = + container_of(work, struct iser_conn, comperror_work); /* getting here when the state is UP means that the conn is being * * terminated asynchronously from the iSCSI layer's perspective. */ diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 64ab5fc7cca..a6289595557 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -390,9 +390,10 @@ static void srp_disconnect_target(struct srp_target_port *target) wait_for_completion(&target->done); } -static void srp_remove_work(void *target_ptr) +static void srp_remove_work(struct work_struct *work) { - struct srp_target_port *target = target_ptr; + struct srp_target_port *target = + container_of(work, struct srp_target_port, work); spin_lock_irq(target->scsi_host->host_lock); if (target->state != SRP_TARGET_DEAD) { @@ -575,7 +576,7 @@ err: spin_lock_irq(target->scsi_host->host_lock); if (target->state == SRP_TARGET_CONNECTING) { target->state = SRP_TARGET_DEAD; - INIT_WORK(&target->work, srp_remove_work, target); + INIT_WORK(&target->work, srp_remove_work); schedule_work(&target->work); } spin_unlock_irq(target->scsi_host->host_lock); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index cbb93669d1c..8451b29a3db 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -567,9 +567,9 @@ static int atkbd_set_leds(struct atkbd *atkbd) * interrupt context. */ -static void atkbd_event_work(void *data) +static void atkbd_event_work(struct work_struct *work) { - struct atkbd *atkbd = data; + struct atkbd *atkbd = container_of(work, struct atkbd, event_work); mutex_lock(&atkbd->event_mutex); @@ -943,7 +943,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd->dev = dev; ps2_init(&atkbd->ps2dev, serio); - INIT_WORK(&atkbd->event_work, atkbd_event_work, atkbd); + INIT_WORK(&atkbd->event_work, atkbd_event_work); mutex_init(&atkbd->event_mutex); switch (serio->id.type) { diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 979b93e33da..b7f049b45b6 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -572,9 +572,9 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, * were in. */ static void -lkkbd_reinit (void *data) +lkkbd_reinit (struct work_struct *work) { - struct lkkbd *lk = data; + struct lkkbd *lk = container_of(work, struct lkkbd, tq); int division; unsigned char leds_on = 0; unsigned char leds_off = 0; @@ -651,7 +651,7 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) lk->serio = serio; lk->dev = input_dev; - INIT_WORK (&lk->tq, lkkbd_reinit, lk); + INIT_WORK (&lk->tq, lkkbd_reinit); lk->bell_volume = bell_volume; lk->keyclick_volume = keyclick_volume; lk->ctrlclick_volume = ctrlclick_volume; diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index cac4781103c..6cd887c5eb0 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -208,9 +208,9 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) * were in. */ -static void sunkbd_reinit(void *data) +static void sunkbd_reinit(struct work_struct *work) { - struct sunkbd *sunkbd = data; + struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); @@ -248,7 +248,7 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) sunkbd->serio = serio; sunkbd->dev = input_dev; init_waitqueue_head(&sunkbd->wait); - INIT_WORK(&sunkbd->tq, sunkbd_reinit, sunkbd); + INIT_WORK(&sunkbd->tq, sunkbd_reinit); snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys); serio_set_drvdata(serio, sunkbd); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 6f9b2c7cc9c..52bb2226ce2 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -888,9 +888,10 @@ static int psmouse_poll(struct psmouse *psmouse) * psmouse_resync() attempts to re-validate current protocol. */ -static void psmouse_resync(void *p) +static void psmouse_resync(struct work_struct *work) { - struct psmouse *psmouse = p, *parent = NULL; + struct psmouse *parent = NULL, *psmouse = + container_of(work, struct psmouse, resync_work); struct serio *serio = psmouse->ps2dev.serio; psmouse_ret_t rc = PSMOUSE_GOOD_DATA; int failed = 0, enabled = 0; @@ -1121,7 +1122,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) goto out; ps2_init(&psmouse->ps2dev, serio); - INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse); + INIT_WORK(&psmouse->resync_work, psmouse_resync); psmouse->dev = input_dev; snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys); diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index e5b1b60757b..b3e84d3bb7f 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -251,9 +251,9 @@ EXPORT_SYMBOL(ps2_command); * ps2_schedule_command(), to a PS/2 device (keyboard, mouse, etc.) */ -static void ps2_execute_scheduled_command(void *data) +static void ps2_execute_scheduled_command(struct work_struct *work) { - struct ps2work *ps2work = data; + struct ps2work *ps2work = container_of(work, struct ps2work, work); ps2_command(ps2work->ps2dev, ps2work->param, ps2work->command); kfree(ps2work); @@ -278,7 +278,7 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman ps2work->ps2dev = ps2dev; ps2work->command = command; memcpy(ps2work->param, param, send); - INIT_WORK(&ps2work->work, ps2_execute_scheduled_command, ps2work); + INIT_WORK(&ps2work->work, ps2_execute_scheduled_command); if (!schedule_work(&ps2work->work)) { kfree(ps2work); diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c index 6ae6eb32211..946c38cf6f8 100644 --- a/drivers/isdn/act2000/capi.c +++ b/drivers/isdn/act2000/capi.c @@ -627,8 +627,10 @@ handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) { } void -actcapi_dispatch(act2000_card *card) +actcapi_dispatch(struct work_struct *work) { + struct act2000_card *card = + container_of(work, struct act2000_card, rcv_tq); struct sk_buff *skb; actcapi_msg *msg; __u16 ccmd; diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h index 49f453c53c6..e55f6a931f6 100644 --- a/drivers/isdn/act2000/capi.h +++ b/drivers/isdn/act2000/capi.h @@ -356,7 +356,7 @@ extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int extern void actcapi_select_b2_protocol_req(act2000_card *, act2000_chan *); extern void actcapi_disconnect_b3_req(act2000_card *, act2000_chan *); extern void actcapi_connect_resp(act2000_card *, act2000_chan *, __u8); -extern void actcapi_dispatch(act2000_card *); +extern void actcapi_dispatch(struct work_struct *); #ifdef DEBUG_MSG extern void actcapi_debug_msg(struct sk_buff *skb, int); #else diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c index d89dcde4ead..90593e2ef87 100644 --- a/drivers/isdn/act2000/module.c +++ b/drivers/isdn/act2000/module.c @@ -192,8 +192,11 @@ act2000_set_msn(act2000_card *card, char *eazmsn) } static void -act2000_transmit(struct act2000_card *card) +act2000_transmit(struct work_struct *work) { + struct act2000_card *card = + container_of(work, struct act2000_card, snd_tq); + switch (card->bus) { case ACT2000_BUS_ISA: act2000_isa_send(card); @@ -207,8 +210,11 @@ act2000_transmit(struct act2000_card *card) } static void -act2000_receive(struct act2000_card *card) +act2000_receive(struct work_struct *work) { + struct act2000_card *card = + container_of(work, struct act2000_card, poll_tq); + switch (card->bus) { case ACT2000_BUS_ISA: act2000_isa_receive(card); @@ -227,7 +233,7 @@ act2000_poll(unsigned long data) act2000_card * card = (act2000_card *)data; unsigned long flags; - act2000_receive(card); + act2000_receive(&card->poll_tq); spin_lock_irqsave(&card->lock, flags); mod_timer(&card->ptimer, jiffies+3); spin_unlock_irqrestore(&card->lock, flags); @@ -578,9 +584,9 @@ act2000_alloccard(int bus, int port, int irq, char *id) skb_queue_head_init(&card->sndq); skb_queue_head_init(&card->rcvq); skb_queue_head_init(&card->ackq); - INIT_WORK(&card->snd_tq, (void *) (void *) act2000_transmit, card); - INIT_WORK(&card->rcv_tq, (void *) (void *) actcapi_dispatch, card); - INIT_WORK(&card->poll_tq, (void *) (void *) act2000_receive, card); + INIT_WORK(&card->snd_tq, act2000_transmit); + INIT_WORK(&card->rcv_tq, actcapi_dispatch); + INIT_WORK(&card->poll_tq, act2000_receive); init_timer(&card->ptimer); card->interface.owner = THIS_MODULE; card->interface.channels = ACT2000_BCH; diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 8c4fcb9027b..783a2552631 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -208,9 +208,10 @@ static void notify_down(u32 contr) } } -static void notify_handler(void *data) +static void notify_handler(struct work_struct *work) { - struct capi_notifier *np = data; + struct capi_notifier *np = + container_of(work, struct capi_notifier, work); switch (np->cmd) { case KCI_CONTRUP: @@ -235,7 +236,7 @@ static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci) if (!np) return -ENOMEM; - INIT_WORK(&np->work, notify_handler, np); + INIT_WORK(&np->work, notify_handler); np->cmd = cmd; np->controller = controller; np->applid = applid; @@ -248,10 +249,11 @@ static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci) /* -------- Receiver ------------------------------------------ */ -static void recv_handler(void *_ap) +static void recv_handler(struct work_struct *work) { struct sk_buff *skb; - struct capi20_appl *ap = (struct capi20_appl *) _ap; + struct capi20_appl *ap = + container_of(work, struct capi20_appl, recv_work); if ((!ap) || (ap->release_in_progress)) return; @@ -527,7 +529,7 @@ u16 capi20_register(struct capi20_appl *ap) ap->callback = NULL; init_MUTEX(&ap->recv_sem); skb_queue_head_init(&ap->recv_queue); - INIT_WORK(&ap->recv_work, recv_handler, (void *)ap); + INIT_WORK(&ap->recv_work, recv_handler); ap->release_in_progress = 0; write_unlock_irqrestore(&application_lock, flags); diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index 7bbfd85ab79..fd5d7364a48 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -194,41 +194,11 @@ static int avmcs_config(struct pcmcia_device *link) dev = link->priv; - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ do { - tuple.DesiredTuple = CISTPL_CONFIG; - i = pcmcia_get_first_tuple(link, &tuple); - if (i != CS_SUCCESS) break; - tuple.TupleData = buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - i = pcmcia_get_tuple_data(link, &tuple); - if (i != CS_SUCCESS) break; - i = pcmcia_parse_tuple(link, &tuple, &parse); - if (i != CS_SUCCESS) break; - link->conf.ConfigBase = parse.config.base; - } while (0); - if (i != CS_SUCCESS) { - cs_error(link, ParseTuple, i); - return -ENODEV; - } - - do { - - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = 254; - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_VERS_1; - devname[0] = 0; - if( !first_tuple(link, &tuple, &parse) && parse.version_1.ns > 1 ) { - strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], - sizeof(devname)); - } + if (link->prod_id[1]) + strlcpy(devname, link->prod_id[1], sizeof(devname)); + /* * find IO port */ diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index bec59010bc6..3b19caeba25 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -232,9 +232,10 @@ Amd7930_new_ph(struct IsdnCardState *cs) static void -Amd7930_bh(struct IsdnCardState *cs) +Amd7930_bh(struct work_struct *work) { - + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; if (!cs) @@ -789,7 +790,7 @@ Amd7930_init(struct IsdnCardState *cs) void __devinit setup_Amd7930(struct IsdnCardState *cs) { - INIT_WORK(&cs->tqueue, (void *)(void *) Amd7930_bh, cs); + INIT_WORK(&cs->tqueue, Amd7930_bh); cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index ac28e3278ad..876fec6c6be 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -216,41 +216,11 @@ static int avma1cs_config(struct pcmcia_device *link) DEBUG(0, "avma1cs_config(0x%p)\n", link); - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ do { - tuple.DesiredTuple = CISTPL_CONFIG; - i = pcmcia_get_first_tuple(link, &tuple); - if (i != CS_SUCCESS) break; - tuple.TupleData = buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - i = pcmcia_get_tuple_data(link, &tuple); - if (i != CS_SUCCESS) break; - i = pcmcia_parse_tuple(link, &tuple, &parse); - if (i != CS_SUCCESS) break; - link->conf.ConfigBase = parse.config.base; - } while (0); - if (i != CS_SUCCESS) { - cs_error(link, ParseTuple, i); - return -ENODEV; - } - - do { - - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = 254; - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_VERS_1; - devname[0] = 0; - if( !first_tuple(link, &tuple, &parse) && parse.version_1.ns > 1 ) { - strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], - sizeof(devname)); - } + if (link->prod_id[1]) + strlcpy(devname, link->prod_id[1], sizeof(devname)); + /* * find IO port */ diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 785b08554fc..cede72cdbb3 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1137,7 +1137,6 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow cs->tx_skb = NULL; cs->tx_cnt = 0; cs->event = 0; - cs->tqueue.data = cs; skb_queue_head_init(&cs->rq); skb_queue_head_init(&cs->sq); @@ -1554,7 +1553,7 @@ static void hisax_b_l2l1(struct PStack *st, int pr, void *arg); static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg); static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs); static void hisax_bc_close(struct BCState *bcs); -static void hisax_bh(struct IsdnCardState *cs); +static void hisax_bh(struct work_struct *work); static void EChannel_proc_rcv(struct hisax_d_if *d_if); int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[], @@ -1586,7 +1585,7 @@ int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[], hisax_d_if->cs = cs; cs->hw.hisax_d_if = hisax_d_if; cs->cardmsg = hisax_cardmsg; - INIT_WORK(&cs->tqueue, (void *)(void *)hisax_bh, cs); + INIT_WORK(&cs->tqueue, hisax_bh); cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1; for (i = 0; i < 2; i++) { cs->bcs[i].BC_SetStack = hisax_bc_setstack; @@ -1618,8 +1617,10 @@ static void hisax_sched_event(struct IsdnCardState *cs, int event) schedule_work(&cs->tqueue); } -static void hisax_bh(struct IsdnCardState *cs) +static void hisax_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); struct PStack *st; int pr; diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index e18e75be8ed..4e180d210fa 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -242,23 +242,6 @@ static int elsa_cs_config(struct pcmcia_device *link) DEBUG(0, "elsa_config(0x%p)\n", link); dev = link->priv; - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = 255; - tuple.TupleOffset = 0; - tuple.Attributes = 0; - i = first_tuple(link, &tuple, &parse); - if (i != CS_SUCCESS) { - last_fn = ParseTuple; - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index d852c9d998b..de9b1a4d6ba 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -1083,8 +1083,9 @@ tx_b_frame(struct hfc4s8s_btype *bch) /* bottom half handler for interrupt */ /*************************************/ static void -hfc4s8s_bh(hfc4s8s_hw * hw) +hfc4s8s_bh(struct work_struct *work) { + hfc4s8s_hw *hw = container_of(work, hfc4s8s_hw, tqueue); u_char b; struct hfc4s8s_l1 *l1p; volatile u_char *fifo_stat; @@ -1550,7 +1551,7 @@ setup_instance(hfc4s8s_hw * hw) goto out; } - INIT_WORK(&hw->tqueue, (void *) (void *) hfc4s8s_bh, hw); + INIT_WORK(&hw->tqueue, hfc4s8s_bh); if (request_irq (hw->irq, hfc4s8s_interrupt, IRQF_SHARED, hw->card_name, hw)) { diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index 6360e821472..8d9864453a2 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -549,10 +549,11 @@ setstack_2b(struct PStack *st, struct BCState *bcs) } static void -hfcd_bh(struct IsdnCardState *cs) +hfcd_bh(struct work_struct *work) { - if (!cs) - return; + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); + if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { switch (cs->dc.hfcd.ph_state) { case (0): @@ -1072,5 +1073,5 @@ set_cs_func(struct IsdnCardState *cs) cs->dbusytimer.function = (void *) hfc_dbusy_timer; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); - INIT_WORK(&cs->tqueue, (void *)(void *) hfcd_bh, cs); + INIT_WORK(&cs->tqueue, hfcd_bh); } diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 93f60b56351..5db0a85b827 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1506,8 +1506,10 @@ setstack_2b(struct PStack *st, struct BCState *bcs) /* handle L1 state changes */ /***************************/ static void -hfcpci_bh(struct IsdnCardState *cs) +hfcpci_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); u_long flags; // struct PStack *stptr; @@ -1722,7 +1724,7 @@ setup_hfcpci(struct IsdnCard *card) Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); /* At this point the needed PCI config is done */ /* fifos are still not enabled */ - INIT_WORK(&cs->tqueue, (void *)(void *) hfcpci_bh, cs); + INIT_WORK(&cs->tqueue, hfcpci_bh); cs->setstack_d = setstack_hfcpci; cs->BC_Send_Data = &hfcpci_send_data; cs->readisac = NULL; diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index 954d1536db1..4fd09d21a27 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -1251,8 +1251,10 @@ setstack_2b(struct PStack *st, struct BCState *bcs) /* handle L1 state changes */ /***************************/ static void -hfcsx_bh(struct IsdnCardState *cs) +hfcsx_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); u_long flags; if (!cs) @@ -1499,7 +1501,7 @@ setup_hfcsx(struct IsdnCard *card) cs->dbusytimer.function = (void *) hfcsx_dbusy_timer; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); - INIT_WORK(&cs->tqueue, (void *)(void *) hfcsx_bh, cs); + INIT_WORK(&cs->tqueue, hfcsx_bh); cs->readisac = NULL; cs->writeisac = NULL; cs->readisacfifo = NULL; diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index da706925d54..682cac32f25 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -77,8 +77,10 @@ icc_new_ph(struct IsdnCardState *cs) } static void -icc_bh(struct IsdnCardState *cs) +icc_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; if (!cs) @@ -674,7 +676,7 @@ clear_pending_icc_ints(struct IsdnCardState *cs) void __devinit setup_icc(struct IsdnCardState *cs) { - INIT_WORK(&cs->tqueue, (void *)(void *) icc_bh, cs); + INIT_WORK(&cs->tqueue, icc_bh); cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 282f349408b..4e9f23803da 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -81,8 +81,10 @@ isac_new_ph(struct IsdnCardState *cs) } static void -isac_bh(struct IsdnCardState *cs) +isac_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; if (!cs) @@ -674,7 +676,7 @@ clear_pending_isac_ints(struct IsdnCardState *cs) void __devinit setup_isac(struct IsdnCardState *cs) { - INIT_WORK(&cs->tqueue, (void *)(void *) isac_bh, cs); + INIT_WORK(&cs->tqueue, isac_bh); cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 674af673ff9..6f1a6583b17 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -437,8 +437,10 @@ extern void BChannel_bh(struct BCState *); #define B_LL_OK 10 static void -isar_bh(struct BCState *bcs) +isar_bh(struct work_struct *work) { + struct BCState *bcs = container_of(work, struct BCState, tqueue); + BChannel_bh(bcs); if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event)) ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR); @@ -1580,7 +1582,7 @@ isar_setup(struct IsdnCardState *cs) cs->bcs[i].mode = 0; cs->bcs[i].hw.isar.dpath = i + 1; modeisar(&cs->bcs[i], 0, 0); - INIT_WORK(&cs->bcs[i].tqueue, (void *)(void *) isar_bh, &cs->bcs[i]); + INIT_WORK(&cs->bcs[i].tqueue, isar_bh); } } diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index bab35688648..a14204ec88e 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -315,8 +315,10 @@ BChannel_proc_ack(struct BCState *bcs) } void -BChannel_bh(struct BCState *bcs) +BChannel_bh(struct work_struct *work) { + struct BCState *bcs = container_of(work, struct BCState, tqueue); + if (!bcs) return; if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event)) @@ -362,7 +364,7 @@ init_bcstate(struct IsdnCardState *cs, int bc) bcs->cs = cs; bcs->channel = bc; - INIT_WORK(&bcs->tqueue, (void *)(void *) BChannel_bh, bcs); + INIT_WORK(&bcs->tqueue, BChannel_bh); spin_lock_init(&bcs->aclock); bcs->BC_SetStack = NULL; bcs->BC_Close = NULL; diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index f9c14a2970b..46ed65334c5 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -233,20 +233,10 @@ static int sedlbauer_config(struct pcmcia_device *link) DEBUG(0, "sedlbauer_config(0x%p)\n", link); - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf)); diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index afcc2aeadb3..6b754f18379 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -232,23 +232,6 @@ static int teles_cs_config(struct pcmcia_device *link) DEBUG(0, "teles_config(0x%p)\n", link); dev = link->priv; - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = 255; - tuple.TupleOffset = 0; - tuple.Attributes = 0; - i = first_tuple(link, &tuple, &parse); - if (i != CS_SUCCESS) { - last_fn = ParseTuple; - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 1655341797a..3aeceaf9769 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -101,8 +101,10 @@ W6692_new_ph(struct IsdnCardState *cs) } static void -W6692_bh(struct IsdnCardState *cs) +W6692_bh(struct work_struct *work) { + struct IsdnCardState *cs = + container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; if (!cs) @@ -1070,7 +1072,7 @@ setup_w6692(struct IsdnCard *card) id_list[cs->subtyp].card_name, cs->irq, cs->hw.w6692.iobase); - INIT_WORK(&cs->tqueue, (void *)(void *) W6692_bh, cs); + INIT_WORK(&cs->tqueue, W6692_bh); cs->readW6692 = &ReadW6692; cs->writeW6692 = &WriteW6692; cs->readisacfifo = &ReadISACfifo; diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c index 82e42a80dc4..a1206498a1c 100644 --- a/drivers/isdn/hysdn/boardergo.c +++ b/drivers/isdn/hysdn/boardergo.c @@ -71,8 +71,9 @@ ergo_interrupt(int intno, void *dev_id) /* may be queued from everywhere (interrupts included). */ /******************************************************************************/ static void -ergo_irq_bh(hysdn_card * card) +ergo_irq_bh(struct work_struct *ugli_api) { + hysdn_card * card = container_of(ugli_api, hysdn_card, irq_queue); tErgDpram *dpr; int again; unsigned long flags; @@ -442,7 +443,7 @@ ergo_inithardware(hysdn_card * card) card->writebootseq = ergo_writebootseq; card->waitpofready = ergo_waitpofready; card->set_errlog_state = ergo_set_errlog_state; - INIT_WORK(&card->irq_queue, (void *) (void *) ergo_irq_bh, card); + INIT_WORK(&card->irq_queue, ergo_irq_bh); card->hysdn_lock = SPIN_LOCK_UNLOCKED; return (0); diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 1f8d6ae66b4..2e4daebfb7e 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -984,9 +984,9 @@ void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb) /* * called from tq_immediate */ -static void isdn_net_softint(void *private) +static void isdn_net_softint(struct work_struct *work) { - isdn_net_local *lp = private; + isdn_net_local *lp = container_of(work, isdn_net_local, tqueue); struct sk_buff *skb; spin_lock_bh(&lp->xmit_lock); @@ -2596,7 +2596,7 @@ isdn_net_new(char *name, struct net_device *master) netdev->local->netdev = netdev; netdev->local->next = netdev->local; - INIT_WORK(&netdev->local->tqueue, (void *)(void *) isdn_net_softint, netdev->local); + INIT_WORK(&netdev->local->tqueue, isdn_net_softint); spin_lock_init(&netdev->local->xmit_lock); netdev->local->isdn_device = -1; diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 6ead5e1508b..1966f3410a1 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -68,8 +68,6 @@ static void pcbit_set_msn(struct pcbit_dev *dev, char *list); static int pcbit_check_msn(struct pcbit_dev *dev, char *msn); -extern void pcbit_deliver(void * data); - int pcbit_init_dev(int board, int mem_base, int irq) { struct pcbit_dev *dev; @@ -129,7 +127,7 @@ int pcbit_init_dev(int board, int mem_base, int irq) memset(dev->b2, 0, sizeof(struct pcbit_chan)); dev->b2->id = 1; - INIT_WORK(&dev->qdelivery, pcbit_deliver, dev); + INIT_WORK(&dev->qdelivery, pcbit_deliver); /* * interrupts diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index 937fd212038..0c9f6df873f 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -67,7 +67,6 @@ extern void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg, * Prototypes */ -void pcbit_deliver(void *data); static void pcbit_transmit(struct pcbit_dev *dev); static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack); @@ -299,11 +298,12 @@ pcbit_transmit(struct pcbit_dev *dev) */ void -pcbit_deliver(void *data) +pcbit_deliver(struct work_struct *work) { struct frame_buf *frame; unsigned long flags, msg; - struct pcbit_dev *dev = (struct pcbit_dev *) data; + struct pcbit_dev *dev = + container_of(work, struct pcbit_dev, qdelivery); spin_lock_irqsave(&dev->lock, flags); diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h index 388bacefd23..19c18e88ff1 100644 --- a/drivers/isdn/pcbit/pcbit.h +++ b/drivers/isdn/pcbit/pcbit.h @@ -166,4 +166,6 @@ struct pcbit_ioctl { #define L2_RUNNING 5 #define L2_ERROR 6 +extern void pcbit_deliver(struct work_struct *work); + #endif diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index be0bd34ff6f..d43ea81d6df 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -267,12 +267,12 @@ adb_probe_task(void *x) } static void -__adb_probe_task(void *data) +__adb_probe_task(struct work_struct *bullshit) { adb_probe_task_pid = kernel_thread(adb_probe_task, NULL, SIGCHLD | CLONE_KERNEL); } -static DECLARE_WORK(adb_reset_work, __adb_probe_task, NULL); +static DECLARE_WORK(adb_reset_work, __adb_probe_task); int adb_reset_bus(void) diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index f1b6f563673..5ed41fe84e5 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -48,7 +48,8 @@ struct rackmeter_dma { } ____cacheline_aligned; struct rackmeter_cpu { - struct work_struct sniffer; + struct delayed_work sniffer; + struct rackmeter *rm; cputime64_t prev_wall; cputime64_t prev_idle; int zero; @@ -208,11 +209,12 @@ static void rackmeter_setup_dbdma(struct rackmeter *rm) rackmeter_do_pause(rm, 0); } -static void rackmeter_do_timer(void *data) +static void rackmeter_do_timer(struct work_struct *work) { - struct rackmeter *rm = data; + struct rackmeter_cpu *rcpu = + container_of(work, struct rackmeter_cpu, sniffer.work); + struct rackmeter *rm = rcpu->rm; unsigned int cpu = smp_processor_id(); - struct rackmeter_cpu *rcpu = &rm->cpu[cpu]; cputime64_t cur_jiffies, total_idle_ticks; unsigned int total_ticks, idle_ticks; int i, offset, load, cumm, pause; @@ -263,8 +265,10 @@ static void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm) * on those machines yet */ - INIT_WORK(&rm->cpu[0].sniffer, rackmeter_do_timer, rm); - INIT_WORK(&rm->cpu[1].sniffer, rackmeter_do_timer, rm); + rm->cpu[0].rm = rm; + INIT_DELAYED_WORK(&rm->cpu[0].sniffer, rackmeter_do_timer); + rm->cpu[1].rm = rm; + INIT_DELAYED_WORK(&rm->cpu[1].sniffer, rackmeter_do_timer); for_each_online_cpu(cpu) { struct rackmeter_cpu *rcpu; diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 4f724cdd2ef..6dde27ab79a 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -601,7 +601,7 @@ core_initcall(smu_late_init); * sysfs visibility */ -static void smu_expose_childs(void *unused) +static void smu_expose_childs(struct work_struct *unused) { struct device_node *np; @@ -611,7 +611,7 @@ static void smu_expose_childs(void *unused) &smu->of_dev->dev); } -static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs, NULL); +static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs); static int smu_platform_probe(struct of_device* dev, const struct of_device_id *match) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 08a40f4e4f6..ed2d4ef27fd 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -458,11 +458,11 @@ static void dec_pending(struct crypt_io *io, int error) * interrupt context. */ static struct workqueue_struct *_kcryptd_workqueue; -static void kcryptd_do_work(void *data); +static void kcryptd_do_work(struct work_struct *work); static void kcryptd_queue_io(struct crypt_io *io) { - INIT_WORK(&io->work, kcryptd_do_work, io); + INIT_WORK(&io->work, kcryptd_do_work); queue_work(_kcryptd_workqueue, &io->work); } @@ -618,9 +618,9 @@ static void process_read_endio(struct crypt_io *io) dec_pending(io, crypt_convert(cc, &ctx)); } -static void kcryptd_do_work(void *data) +static void kcryptd_do_work(struct work_struct *work) { - struct crypt_io *io = data; + struct crypt_io *io = container_of(work, struct crypt_io, work); if (io->post_process) process_read_endio(io); diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index d754e0bc6e9..e77ee6fd104 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -104,8 +104,8 @@ typedef int (*action_fn) (struct pgpath *pgpath); static kmem_cache_t *_mpio_cache; struct workqueue_struct *kmultipathd; -static void process_queued_ios(void *data); -static void trigger_event(void *data); +static void process_queued_ios(struct work_struct *work); +static void trigger_event(struct work_struct *work); /*----------------------------------------------- @@ -173,8 +173,8 @@ static struct multipath *alloc_multipath(struct dm_target *ti) INIT_LIST_HEAD(&m->priority_groups); spin_lock_init(&m->lock); m->queue_io = 1; - INIT_WORK(&m->process_queued_ios, process_queued_ios, m); - INIT_WORK(&m->trigger_event, trigger_event, m); + INIT_WORK(&m->process_queued_ios, process_queued_ios); + INIT_WORK(&m->trigger_event, trigger_event); m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache); if (!m->mpio_pool) { kfree(m); @@ -379,9 +379,10 @@ static void dispatch_queued_ios(struct multipath *m) } } -static void process_queued_ios(void *data) +static void process_queued_ios(struct work_struct *work) { - struct multipath *m = (struct multipath *) data; + struct multipath *m = + container_of(work, struct multipath, process_queued_ios); struct hw_handler *hwh = &m->hw_handler; struct pgpath *pgpath = NULL; unsigned init_required = 0, must_queue = 1; @@ -421,9 +422,10 @@ out: * An event is triggered whenever a path is taken out of use. * Includes path failure and PG bypass. */ -static void trigger_event(void *data) +static void trigger_event(struct work_struct *work) { - struct multipath *m = (struct multipath *) data; + struct multipath *m = + container_of(work, struct multipath, trigger_event); dm_table_event(m->ti->table); } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 48a653b3f51..fc8cbb168e3 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -883,7 +883,7 @@ static void do_mirror(struct mirror_set *ms) do_writes(ms, &writes); } -static void do_work(void *ignored) +static void do_work(struct work_struct *ignored) { struct mirror_set *ms; @@ -1269,7 +1269,7 @@ static int __init dm_mirror_init(void) dm_dirty_log_exit(); return r; } - INIT_WORK(&_kmirrord_work, do_work, NULL); + INIT_WORK(&_kmirrord_work, do_work); r = dm_register_target(&mirror_target); if (r < 0) { diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 5281e009407..91c7aa1fed0 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -40,7 +40,7 @@ #define SNAPSHOT_PAGES 256 struct workqueue_struct *ksnapd; -static void flush_queued_bios(void *data); +static void flush_queued_bios(struct work_struct *work); struct pending_exception { struct exception e; @@ -528,7 +528,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) } bio_list_init(&s->queued_bios); - INIT_WORK(&s->queued_bios_work, flush_queued_bios, s); + INIT_WORK(&s->queued_bios_work, flush_queued_bios); /* Add snapshot to the list of snapshots for this origin */ /* Exceptions aren't triggered till snapshot_resume() is called */ @@ -603,9 +603,10 @@ static void flush_bios(struct bio *bio) } } -static void flush_queued_bios(void *data) +static void flush_queued_bios(struct work_struct *work) { - struct dm_snapshot *s = (struct dm_snapshot *) data; + struct dm_snapshot *s = + container_of(work, struct dm_snapshot, queued_bios_work); struct bio *queued_bios; unsigned long flags; diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c index f1db6eff485..b3c01496c73 100644 --- a/drivers/md/kcopyd.c +++ b/drivers/md/kcopyd.c @@ -417,7 +417,7 @@ static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *)) /* * kcopyd does this every time it's woken up. */ -static void do_work(void *ignored) +static void do_work(struct work_struct *ignored) { /* * The order that these are called is *very* important. @@ -628,7 +628,7 @@ static int kcopyd_init(void) } kcopyd_clients++; - INIT_WORK(&_kcopyd_work, do_work, NULL); + INIT_WORK(&_kcopyd_work, do_work); mutex_unlock(&kcopyd_init_lock); return 0; } diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 06893243f3d..6e166801505 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -63,7 +63,7 @@ struct flexcop_pci { unsigned long last_irq; - struct work_struct irq_check_work; + struct delayed_work irq_check_work; struct flexcop_device *fc_dev; }; @@ -97,9 +97,10 @@ static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_regi return 0; } -static void flexcop_pci_irq_check_work(void *data) +static void flexcop_pci_irq_check_work(struct work_struct *work) { - struct flexcop_pci *fc_pci = data; + struct flexcop_pci *fc_pci = + container_of(work, struct flexcop_pci, irq_check_work.work); struct flexcop_device *fc = fc_pci->fc_dev; flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); @@ -371,7 +372,7 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) goto err_fc_exit; - INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci); + INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work); return ret; diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 8a7dd507cf6..206c13e47a0 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -128,7 +128,7 @@ struct cinergyt2 { struct dvbt_set_parameters_msg param; struct dvbt_get_status_msg status; - struct work_struct query_work; + struct delayed_work query_work; wait_queue_head_t poll_wq; int pending_fe_events; @@ -142,7 +142,7 @@ struct cinergyt2 { #ifdef ENABLE_RC struct input_dev *rc_input_dev; char phys[64]; - struct work_struct rc_query_work; + struct delayed_work rc_query_work; int rc_input_event; u32 rc_last_code; unsigned long last_event_jiffies; @@ -723,9 +723,10 @@ static struct dvb_device cinergyt2_fe_template = { #ifdef ENABLE_RC -static void cinergyt2_query_rc (void *data) +static void cinergyt2_query_rc (struct work_struct *work) { - struct cinergyt2 *cinergyt2 = data; + struct cinergyt2 *cinergyt2 = + container_of(work, struct cinergyt2, rc_query_work.work); char buf[1] = { CINERGYT2_EP1_GET_RC_EVENTS }; struct cinergyt2_rc_event rc_events[12]; int n, len, i; @@ -806,7 +807,7 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys)); cinergyt2->rc_input_event = KEY_MAX; cinergyt2->rc_last_code = ~0; - INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); + INIT_DELAYED_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc); input_dev->name = DRIVER_NAME " remote control"; input_dev->phys = cinergyt2->phys; @@ -847,9 +848,10 @@ static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { } #endif /* ENABLE_RC */ -static void cinergyt2_query (void *data) +static void cinergyt2_query (struct work_struct *work) { - struct cinergyt2 *cinergyt2 = (struct cinergyt2 *) data; + struct cinergyt2 *cinergyt2 = + container_of(work, struct cinergyt2, query_work.work); char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS }; struct dvbt_get_status_msg *s = &cinergyt2->status; uint8_t lock_bits; @@ -893,7 +895,7 @@ static int cinergyt2_probe (struct usb_interface *intf, mutex_init(&cinergyt2->sem); init_waitqueue_head (&cinergyt2->poll_wq); - INIT_WORK(&cinergyt2->query_work, cinergyt2_query, cinergyt2); + INIT_DELAYED_WORK(&cinergyt2->query_work, cinergyt2_query); cinergyt2->udev = interface_to_usbdev(intf); cinergyt2->param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 8859ab74f0f..ebf4dc5190f 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -127,6 +127,7 @@ struct dvb_net_priv { int in_use; struct net_device_stats stats; u16 pid; + struct net_device *net; struct dvb_net *host; struct dmx_demux *demux; struct dmx_section_feed *secfeed; @@ -1123,10 +1124,11 @@ static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) } -static void wq_set_multicast_list (void *data) +static void wq_set_multicast_list (struct work_struct *work) { - struct net_device *dev = data; - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = + container_of(work, struct dvb_net_priv, set_multicast_list_wq); + struct net_device *dev = priv->net; dvb_net_feed_stop(dev); priv->rx_mode = RX_MODE_UNI; @@ -1167,9 +1169,11 @@ static void dvb_net_set_multicast_list (struct net_device *dev) } -static void wq_restart_net_feed (void *data) +static void wq_restart_net_feed (struct work_struct *work) { - struct net_device *dev = data; + struct dvb_net_priv *priv = + container_of(work, struct dvb_net_priv, restart_net_feed_wq); + struct net_device *dev = priv->net; if (netif_running(dev)) { dvb_net_feed_stop(dev); @@ -1276,6 +1280,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) dvbnet->device[if_num] = net; priv = net->priv; + priv->net = net; priv->demux = dvbnet->demux; priv->pid = pid; priv->rx_mode = RX_MODE_UNI; @@ -1284,8 +1289,8 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) priv->feedtype = feedtype; reset_ule(priv); - INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net); - INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net); + INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list); + INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed); mutex_init(&priv->mutex); net->base_addr = pid; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index 0a3a0b6c235..794e4471561 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -13,9 +13,10 @@ * * TODO: Fix the repeat rate of the input device. */ -static void dvb_usb_read_remote_control(void *data) +static void dvb_usb_read_remote_control(struct work_struct *work) { - struct dvb_usb_device *d = data; + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, rc_query_work.work); u32 event; int state; @@ -128,7 +129,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) input_register_device(d->rc_input_dev); - INIT_WORK(&d->rc_query_work, dvb_usb_read_remote_control, d); + INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); info("schedule remote query interval to %d msecs.", d->props.rc_interval); schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval)); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 376c45a8e77..0d721731a52 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -369,7 +369,7 @@ struct dvb_usb_device { /* remote control */ struct input_dev *rc_input_dev; char rc_phys[64]; - struct work_struct rc_query_work; + struct delayed_work rc_query_work; u32 last_event; int last_state; diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c index 41f4b8d1755..b12cec94f4c 100644 --- a/drivers/media/video/cpia_pp.c +++ b/drivers/media/video/cpia_pp.c @@ -82,6 +82,8 @@ struct pp_cam_entry { struct pardevice *pdev; struct parport *port; struct work_struct cb_task; + void (*cb_func)(void *cbdata); + void *cb_data; int open_count; wait_queue_head_t wq_stream; /* image state flags */ @@ -130,6 +132,20 @@ static void cpia_parport_disable_irq( struct parport *port ) { #define PARPORT_CHUNK_SIZE PAGE_SIZE +static void cpia_pp_run_callback(struct work_struct *work) +{ + void (*cb_func)(void *cbdata); + void *cb_data; + struct pp_cam_entry *cam; + + cam = container_of(work, struct pp_cam_entry, cb_task); + cb_func = cam->cb_func; + cb_data = cam->cb_data; + work_release(work); + + cb_func(cb_data); +} + /**************************************************************************** * * CPiA-specific low-level parport functions for nibble uploads @@ -664,7 +680,9 @@ static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), vo int retval = 0; if(cam->port->irq != PARPORT_IRQ_NONE) { - INIT_WORK(&cam->cb_task, cb, cbdata); + cam->cb_func = cb; + cam->cb_data = cbdata; + INIT_WORK_NAR(&cam->cb_task, cpia_pp_run_callback); } else { retval = -1; } diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 57e1c024a54..e60a0a52e4b 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -145,9 +145,9 @@ static void ir_timer(unsigned long data) schedule_work(&ir->work); } -static void cx88_ir_work(void *data) +static void cx88_ir_work(struct work_struct *work) { - struct cx88_IR *ir = data; + struct cx88_IR *ir = container_of(work, struct cx88_IR, work); unsigned long timeout; cx88_ir_handle_key(ir); @@ -308,7 +308,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) core->ir = ir; if (ir->polling) { - INIT_WORK(&ir->work, cx88_ir_work, ir); + INIT_WORK(&ir->work, cx88_ir_work); init_timer(&ir->timer); ir->timer.function = ir_timer; ir->timer.data = (unsigned long)ir; diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 1457b160222..ab87e7bfe84 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -268,9 +268,9 @@ static void ir_timer(unsigned long data) schedule_work(&ir->work); } -static void ir_work(void *data) +static void ir_work(struct work_struct *work) { - struct IR_i2c *ir = data; + struct IR_i2c *ir = container_of(work, struct IR_i2c, work); ir_key_poll(ir); mod_timer(&ir->timer, jiffies+HZ/10); } @@ -400,7 +400,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir->input->name,ir->input->phys,adap->name); /* start polling via eventd */ - INIT_WORK(&ir->work, ir_work, ir); + INIT_WORK(&ir->work, ir_work); init_timer(&ir->timer); ir->timer.function = ir_timer; ir->timer.data = (unsigned long)ir; diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index f129f316d20..cf129746205 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -45,16 +45,21 @@ static void pvr2_context_trigger_poll(struct pvr2_context *mp) } -static void pvr2_context_poll(struct pvr2_context *mp) +static void pvr2_context_poll(struct work_struct *work) { + struct pvr2_context *mp = + container_of(work, struct pvr2_context, workpoll); pvr2_context_enter(mp); do { pvr2_hdw_poll(mp->hdw); } while (0); pvr2_context_exit(mp); } -static void pvr2_context_setup(struct pvr2_context *mp) +static void pvr2_context_setup(struct work_struct *work) { + struct pvr2_context *mp = + container_of(work, struct pvr2_context, workinit); + pvr2_context_enter(mp); do { if (!pvr2_hdw_dev_ok(mp->hdw)) break; pvr2_hdw_setup(mp->hdw); @@ -92,8 +97,8 @@ struct pvr2_context *pvr2_context_create( } mp->workqueue = create_singlethread_workqueue("pvrusb2"); - INIT_WORK(&mp->workinit,(void (*)(void*))pvr2_context_setup,mp); - INIT_WORK(&mp->workpoll,(void (*)(void*))pvr2_context_poll,mp); + INIT_WORK(&mp->workinit, pvr2_context_setup); + INIT_WORK(&mp->workpoll, pvr2_context_poll); queue_work(mp->workqueue,&mp->workinit); done: return mp; diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index 7b9859c3301..92eabf88a09 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c @@ -324,9 +324,9 @@ static void saa6588_timer(unsigned long data) schedule_work(&s->work); } -static void saa6588_work(void *data) +static void saa6588_work(struct work_struct *work) { - struct saa6588 *s = (struct saa6588 *)data; + struct saa6588 *s = container_of(work, struct saa6588, work); saa6588_i2c_poll(s); mod_timer(&s->timer, jiffies + msecs_to_jiffies(20)); @@ -419,7 +419,7 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind) saa6588_configure(s); /* start polling via eventd */ - INIT_WORK(&s->work, saa6588_work, s); + INIT_WORK(&s->work, saa6588_work); init_timer(&s->timer); s->timer.function = saa6588_timer; s->timer.data = (unsigned long)s; diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 65d044086ce..daaae870a2c 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -343,9 +343,10 @@ static struct video_device saa7134_empress_template = .minor = -1, }; -static void empress_signal_update(void* data) +static void empress_signal_update(struct work_struct *work) { - struct saa7134_dev* dev = (struct saa7134_dev*) data; + struct saa7134_dev* dev = + container_of(work, struct saa7134_dev, empress_workqueue); if (dev->nosignal) { dprintk("no video signal\n"); @@ -378,7 +379,7 @@ static int empress_init(struct saa7134_dev *dev) "%s empress (%s)", dev->name, saa7134_boards[dev->board].name); - INIT_WORK(&dev->empress_workqueue, empress_signal_update, (void*) dev); + INIT_WORK(&dev->empress_workqueue, empress_signal_update); err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, empress_nr[dev->nr]); @@ -399,7 +400,7 @@ static int empress_init(struct saa7134_dev *dev) sizeof(struct saa7134_buf), dev); - empress_signal_update(dev); + empress_signal_update(&dev->empress_workqueue); return 0; } diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 1dd49177315..ef2b55e1991 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -1018,9 +1018,10 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum) } static void -mptfc_setup_reset(void *arg) +mptfc_setup_reset(struct work_struct *work) { - MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fc_setup_reset_work); u64 pn; struct mptfc_rport_info *ri; @@ -1043,9 +1044,10 @@ mptfc_setup_reset(void *arg) } static void -mptfc_rescan_devices(void *arg) +mptfc_rescan_devices(struct work_struct *work) { - MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fc_rescan_work); int ii; u64 pn; struct mptfc_rport_info *ri; @@ -1154,8 +1156,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) } spin_lock_init(&ioc->fc_rescan_work_lock); - INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc); - INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset, (void *)ioc); + INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices); + INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset); spin_lock_irqsave(&ioc->FreeQlock, flags); diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 314c3a27585..b7c4407c5e3 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -111,7 +111,8 @@ struct mpt_lan_priv { u32 total_received; struct net_device_stats stats; /* Per device statistics */ - struct work_struct post_buckets_task; + struct delayed_work post_buckets_task; + struct net_device *dev; unsigned long post_buckets_active; }; @@ -132,7 +133,7 @@ static int lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, static int mpt_lan_open(struct net_device *dev); static int mpt_lan_reset(struct net_device *dev); static int mpt_lan_close(struct net_device *dev); -static void mpt_lan_post_receive_buckets(void *dev_id); +static void mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv); static void mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority); static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg); @@ -345,7 +346,7 @@ mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i; spin_unlock_irqrestore(&priv->rxfidx_lock, flags); } else { - mpt_lan_post_receive_buckets(dev); + mpt_lan_post_receive_buckets(priv); netif_wake_queue(dev); } @@ -441,7 +442,7 @@ mpt_lan_open(struct net_device *dev) dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n")); - mpt_lan_post_receive_buckets(dev); + mpt_lan_post_receive_buckets(priv); printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n", IOC_AND_NETDEV_NAMES_s_s(dev)); @@ -854,7 +855,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority) if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { if (priority) { - schedule_work(&priv->post_buckets_task); + schedule_delayed_work(&priv->post_buckets_task, 0); } else { schedule_delayed_work(&priv->post_buckets_task, 1); dioprintk((KERN_INFO MYNAM ": post_buckets queued on " @@ -1188,10 +1189,9 @@ mpt_lan_receive_post_reply(struct net_device *dev, /* Simple SGE's only at the moment */ static void -mpt_lan_post_receive_buckets(void *dev_id) +mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) { - struct net_device *dev = dev_id; - struct mpt_lan_priv *priv = dev->priv; + struct net_device *dev = priv->dev; MPT_ADAPTER *mpt_dev = priv->mpt_dev; MPT_FRAME_HDR *mf; LANReceivePostRequest_t *pRecvReq; @@ -1335,6 +1335,13 @@ out: clear_bit(0, &priv->post_buckets_active); } +static void +mpt_lan_post_receive_buckets_work(struct work_struct *work) +{ + mpt_lan_post_receive_buckets(container_of(work, struct mpt_lan_priv, + post_buckets_task.work)); +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static struct net_device * mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) @@ -1350,11 +1357,13 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) priv = netdev_priv(dev); + priv->dev = dev; priv->mpt_dev = mpt_dev; priv->pnum = pnum; - memset(&priv->post_buckets_task, 0, sizeof(struct work_struct)); - INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev); + memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task)); + INIT_DELAYED_WORK(&priv->post_buckets_task, + mpt_lan_post_receive_buckets_work); priv->post_buckets_active = 0; dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n", diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index b752a479f6d..4f0c530e47b 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -2006,9 +2006,10 @@ __mptsas_discovery_work(MPT_ADAPTER *ioc) *(Mutex LOCKED) */ static void -mptsas_discovery_work(void * arg) +mptsas_discovery_work(struct work_struct *work) { - struct mptsas_discovery_event *ev = arg; + struct mptsas_discovery_event *ev = + container_of(work, struct mptsas_discovery_event, work); MPT_ADAPTER *ioc = ev->ioc; mutex_lock(&ioc->sas_discovery_mutex); @@ -2068,9 +2069,9 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) * Work queue thread to clear the persitency table */ static void -mptsas_persist_clear_table(void * arg) +mptsas_persist_clear_table(struct work_struct *work) { - MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; + MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task); mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); } @@ -2093,9 +2094,10 @@ mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) * Work queue thread to handle SAS hotplug events */ static void -mptsas_hotplug_work(void *arg) +mptsas_hotplug_work(struct work_struct *work) { - struct mptsas_hotplug_event *ev = arg; + struct mptsas_hotplug_event *ev = + container_of(work, struct mptsas_hotplug_event, work); MPT_ADAPTER *ioc = ev->ioc; struct mptsas_phyinfo *phy_info; struct sas_rphy *rphy; @@ -2341,7 +2343,7 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc, break; } - INIT_WORK(&ev->work, mptsas_hotplug_work, ev); + INIT_WORK(&ev->work, mptsas_hotplug_work); ev->ioc = ioc; ev->handle = le16_to_cpu(sas_event_data->DevHandle); ev->parent_handle = @@ -2366,7 +2368,7 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc, * Persistent table is full. */ INIT_WORK(&ioc->sas_persist_task, - mptsas_persist_clear_table, (void *)ioc); + mptsas_persist_clear_table); schedule_work(&ioc->sas_persist_task); break; case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: @@ -2395,7 +2397,7 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc, return; } - INIT_WORK(&ev->work, mptsas_hotplug_work, ev); + INIT_WORK(&ev->work, mptsas_hotplug_work); ev->ioc = ioc; ev->id = raid_event_data->VolumeID; ev->event_type = MPTSAS_IGNORE_EVENT; @@ -2474,7 +2476,7 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc, ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) return; - INIT_WORK(&ev->work, mptsas_discovery_work, ev); + INIT_WORK(&ev->work, mptsas_discovery_work); ev->ioc = ioc; schedule_work(&ev->work); }; @@ -2511,8 +2513,7 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) break; case MPI_EVENT_PERSISTENT_TABLE_FULL: INIT_WORK(&ioc->sas_persist_task, - mptsas_persist_clear_table, - (void *)ioc); + mptsas_persist_clear_table); schedule_work(&ioc->sas_persist_task); break; case MPI_EVENT_SAS_DISCOVERY: diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index e4cc3dd5fc9..f422c0d0621 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -646,9 +646,10 @@ struct work_queue_wrapper { int disk; }; -static void mpt_work_wrapper(void *data) +static void mpt_work_wrapper(struct work_struct *work) { - struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct work_queue_wrapper *wqw = + container_of(work, struct work_queue_wrapper, work); struct _MPT_SCSI_HOST *hd = wqw->hd; struct Scsi_Host *shost = hd->ioc->sh; struct scsi_device *sdev; @@ -695,7 +696,7 @@ static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk) disk); return; } - INIT_WORK(&wqw->work, mpt_work_wrapper, wqw); + INIT_WORK(&wqw->work, mpt_work_wrapper); wqw->hd = hd; wqw->disk = disk; @@ -784,9 +785,10 @@ MODULE_DEVICE_TABLE(pci, mptspi_pci_table); * renegotiate for a given target */ static void -mptspi_dv_renegotiate_work(void *data) +mptspi_dv_renegotiate_work(struct work_struct *work) { - struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct work_queue_wrapper *wqw = + container_of(work, struct work_queue_wrapper, work); struct _MPT_SCSI_HOST *hd = wqw->hd; struct scsi_device *sdev; @@ -804,7 +806,7 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd) if (!wqw) return; - INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work, wqw); + INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work); wqw->hd = hd; schedule_work(&wqw->work); diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c index 64130227574..7fc7399bd2e 100644 --- a/drivers/message/i2o/driver.c +++ b/drivers/message/i2o/driver.c @@ -232,7 +232,7 @@ int i2o_driver_dispatch(struct i2o_controller *c, u32 m) break; } - INIT_WORK(&evt->work, (void (*)(void *))drv->event, evt); + INIT_WORK(&evt->work, drv->event); queue_work(drv->event_queue, &evt->work); return 1; } diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index a2350640384..9e529d8dd5c 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -371,8 +371,10 @@ static int i2o_exec_remove(struct device *dev) * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY * again, otherwise send LCT NOTIFY to get informed on next LCT change. */ -static void i2o_exec_lct_modified(struct i2o_exec_lct_notify_work *work) +static void i2o_exec_lct_modified(struct work_struct *_work) { + struct i2o_exec_lct_notify_work *work = + container_of(_work, struct i2o_exec_lct_notify_work, work); u32 change_ind = 0; struct i2o_controller *c = work->c; @@ -439,8 +441,7 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m, work->c = c; - INIT_WORK(&work->work, (void (*)(void *))i2o_exec_lct_modified, - work); + INIT_WORK(&work->work, i2o_exec_lct_modified); queue_work(i2o_exec_driver.event_queue, &work->work); return 1; } @@ -460,13 +461,15 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m, /** * i2o_exec_event - Event handling function - * @evt: Event which occurs + * @work: Work item in occurring event * * Handles events send by the Executive device. At the moment does not do * anything useful. */ -static void i2o_exec_event(struct i2o_event *evt) +static void i2o_exec_event(struct work_struct *work) { + struct i2o_event *evt = container_of(work, struct i2o_event, work); + if (likely(evt->i2o_dev)) osm_debug("Event received from device: %d\n", evt->i2o_dev->lct_data.tid); diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index eaba81bf2ec..70ae0025332 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -419,16 +419,18 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req) /** * i2o_block_delayed_request_fn - delayed request queue function - * delayed_request: the delayed request with the queue to start + * @work: the delayed request with the queue to start * * If the request queue is stopped for a disk, and there is no open * request, a new event is created, which calls this function to start * the queue after I2O_BLOCK_REQUEST_TIME. Otherwise the queue will never * be started again. */ -static void i2o_block_delayed_request_fn(void *delayed_request) +static void i2o_block_delayed_request_fn(struct work_struct *work) { - struct i2o_block_delayed_request *dreq = delayed_request; + struct i2o_block_delayed_request *dreq = + container_of(work, struct i2o_block_delayed_request, + work.work); struct request_queue *q = dreq->queue; unsigned long flags; @@ -538,8 +540,9 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m, return 1; }; -static void i2o_block_event(struct i2o_event *evt) +static void i2o_block_event(struct work_struct *work) { + struct i2o_event *evt = container_of(work, struct i2o_event, work); osm_debug("event received\n"); kfree(evt); }; @@ -938,8 +941,8 @@ static void i2o_block_request_fn(struct request_queue *q) continue; dreq->queue = q; - INIT_WORK(&dreq->work, i2o_block_delayed_request_fn, - dreq); + INIT_DELAYED_WORK(&dreq->work, + i2o_block_delayed_request_fn); if (!queue_delayed_work(i2o_block_driver.event_queue, &dreq->work, diff --git a/drivers/message/i2o/i2o_block.h b/drivers/message/i2o/i2o_block.h index 4fdaa5bda41..d9fdc95b440 100644 --- a/drivers/message/i2o/i2o_block.h +++ b/drivers/message/i2o/i2o_block.h @@ -96,7 +96,7 @@ struct i2o_block_request { /* I2O Block device delayed request */ struct i2o_block_delayed_request { - struct work_struct work; + struct delayed_work work; struct request_queue *queue; }; diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 1ba8754e938..2ab7add78f9 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -33,9 +33,10 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) spin_unlock_irqrestore(&fm->lock, flags); } -static void tifm_7xx1_remove_media(void *adapter) +static void tifm_7xx1_remove_media(struct work_struct *work) { - struct tifm_adapter *fm = adapter; + struct tifm_adapter *fm = + container_of(work, struct tifm_adapter, media_remover); unsigned long flags; int cnt; struct tifm_dev *sock; @@ -169,9 +170,10 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) return base_addr + ((sock_num + 1) << 10); } -static void tifm_7xx1_insert_media(void *adapter) +static void tifm_7xx1_insert_media(struct work_struct *work) { - struct tifm_adapter *fm = adapter; + struct tifm_adapter *fm = + container_of(work, struct tifm_adapter, media_inserter); unsigned long flags; tifm_media_id media_id; char *card_name = "xx"; @@ -261,7 +263,7 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) spin_unlock_irqrestore(&fm->lock, flags); flush_workqueue(fm->wq); - tifm_7xx1_remove_media(fm); + tifm_7xx1_remove_media(&fm->media_remover); pci_set_power_state(dev, PCI_D3hot); pci_disable_device(dev); @@ -328,8 +330,8 @@ static int tifm_7xx1_probe(struct pci_dev *dev, if (!fm->sockets) goto err_out_free; - INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media, fm); - INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media, fm); + INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media); + INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media); fm->eject = tifm_7xx1_eject; pci_set_drvdata(dev, fm); @@ -384,7 +386,7 @@ static void tifm_7xx1_remove(struct pci_dev *dev) flush_workqueue(fm->wq); - tifm_7xx1_remove_media(fm); + tifm_7xx1_remove_media(&fm->media_remover); writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); free_irq(dev->irq, fm); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 9d190022a49..6f2a282e2b9 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1419,18 +1419,16 @@ static void mmc_setup(struct mmc_host *host) */ void mmc_detect_change(struct mmc_host *host, unsigned long delay) { - if (delay) - mmc_schedule_delayed_work(&host->detect, delay); - else - mmc_schedule_work(&host->detect); + mmc_schedule_delayed_work(&host->detect, delay); } EXPORT_SYMBOL(mmc_detect_change); -static void mmc_rescan(void *data) +static void mmc_rescan(struct work_struct *work) { - struct mmc_host *host = data; + struct mmc_host *host = + container_of(work, struct mmc_host, detect.work); struct list_head *l, *n; unsigned char power_mode; @@ -1513,7 +1511,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_LIST_HEAD(&host->cards); - INIT_WORK(&host->detect, mmc_rescan, host); + INIT_DELAYED_WORK(&host->detect, mmc_rescan); /* * By default, hosts do not support SGIO or large requests. @@ -1611,7 +1609,7 @@ EXPORT_SYMBOL(mmc_suspend_host); */ int mmc_resume_host(struct mmc_host *host) { - mmc_rescan(host); + mmc_rescan(&host->detect.work); return 0; } diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h index cd5e0ab3d84..149affe0b68 100644 --- a/drivers/mmc/mmc.h +++ b/drivers/mmc/mmc.h @@ -20,6 +20,6 @@ void mmc_remove_host_sysfs(struct mmc_host *host); void mmc_free_host_sysfs(struct mmc_host *host); int mmc_schedule_work(struct work_struct *work); -int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay); +int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay); void mmc_flush_scheduled_work(void); #endif diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index ac532963604..e334acd045b 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -321,17 +321,9 @@ void mmc_free_host_sysfs(struct mmc_host *host) static struct workqueue_struct *workqueue; /* - * Internal function. Schedule work in the MMC work queue. - */ -int mmc_schedule_work(struct work_struct *work) -{ - return queue_work(workqueue, work); -} - -/* * Internal function. Schedule delayed work in the MMC work queue. */ -int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay) +int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay) { return queue_delayed_work(workqueue, work, delay); } diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index 0fdc55b08a6..e846499a004 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -99,7 +99,7 @@ struct tifm_sd { struct mmc_request *req; struct work_struct cmd_handler; - struct work_struct abort_handler; + struct delayed_work abort_handler; wait_queue_head_t can_eject; size_t written_blocks; @@ -496,9 +496,9 @@ err_out: mmc_request_done(mmc, mrq); } -static void tifm_sd_end_cmd(void *data) +static void tifm_sd_end_cmd(struct work_struct *work) { - struct tifm_sd *host = data; + struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); struct tifm_dev *sock = host->dev; struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_request *mrq; @@ -608,9 +608,9 @@ err_out: mmc_request_done(mmc, mrq); } -static void tifm_sd_end_cmd_nodma(void *data) +static void tifm_sd_end_cmd_nodma(struct work_struct *work) { - struct tifm_sd *host = (struct tifm_sd*)data; + struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); struct tifm_dev *sock = host->dev; struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_request *mrq; @@ -661,11 +661,14 @@ static void tifm_sd_end_cmd_nodma(void *data) mmc_request_done(mmc, mrq); } -static void tifm_sd_abort(void *data) +static void tifm_sd_abort(struct work_struct *work) { + struct tifm_sd *host = + container_of(work, struct tifm_sd, abort_handler.work); + printk(KERN_ERR DRIVER_NAME ": card failed to respond for a long period of time"); - tifm_eject(((struct tifm_sd*)data)->dev); + tifm_eject(host->dev); } static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -762,9 +765,9 @@ static struct mmc_host_ops tifm_sd_ops = { .get_ro = tifm_sd_ro }; -static void tifm_sd_register_host(void *data) +static void tifm_sd_register_host(struct work_struct *work) { - struct tifm_sd *host = (struct tifm_sd*)data; + struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); struct tifm_dev *sock = host->dev; struct mmc_host *mmc = tifm_get_drvdata(sock); unsigned long flags; @@ -772,8 +775,7 @@ static void tifm_sd_register_host(void *data) spin_lock_irqsave(&sock->lock, flags); host->flags |= HOST_REG; PREPARE_WORK(&host->cmd_handler, - no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd, - data); + no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd); spin_unlock_irqrestore(&sock->lock, flags); dev_dbg(&sock->dev, "adding host\n"); mmc_add_host(mmc); @@ -799,8 +801,8 @@ static int tifm_sd_probe(struct tifm_dev *sock) host->dev = sock; host->clk_div = 61; init_waitqueue_head(&host->can_eject); - INIT_WORK(&host->cmd_handler, tifm_sd_register_host, host); - INIT_WORK(&host->abort_handler, tifm_sd_abort, host); + INIT_WORK(&host->cmd_handler, tifm_sd_register_host); + INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort); tifm_set_drvdata(sock, mmc); sock->signal_irq = tifm_sd_signal_irq; diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 11d170afa9c..06e33786078 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -922,7 +922,7 @@ int __init init_module(void) * and then free up the resources we took when the card was found. */ -void cleanup_module(void) +void __exit cleanup_module(void) { struct net_device *dev = dev_3c501; unregister_netdev(dev); diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index a34b2206132..7e34c4f07b7 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -726,7 +726,7 @@ static void cleanup_card(struct net_device *dev) iounmap(ei_status.mem); } -void +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 458cb9cbe91..702bfb2a5e9 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1670,7 +1670,7 @@ int __init init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index aa43563610a..54e1d5aebed 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -940,7 +940,7 @@ int __init init_module(void) return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0; } -void +void __exit cleanup_module(void) { struct net_device *dev = dev_3c507; diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 91849469b4f..17d61eb0a7e 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -1302,7 +1302,7 @@ int __init init_module(void) } else return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { int this_dev; for (this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) { diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index f4aca5386ad..6c7437e60bd 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1659,7 +1659,7 @@ int __init init_module(void) * transmit operations are allowed to start scribbling into memory. */ -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(this_device); cleanup_card(this_device); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index d02ed51abfc..931028f672d 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -594,7 +594,7 @@ struct rtl8139_private { u32 rx_config; struct rtl_extra_stats xstats; - struct work_struct thread; + struct delayed_work thread; struct mii_if_info mii; unsigned int regs_len; @@ -636,8 +636,8 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); static void rtl8139_set_rx_mode (struct net_device *dev); static void __set_rx_mode (struct net_device *dev); static void rtl8139_hw_start (struct net_device *dev); -static void rtl8139_thread (void *_data); -static void rtl8139_tx_timeout_task(void *_data); +static void rtl8139_thread (struct work_struct *work); +static void rtl8139_tx_timeout_task(struct work_struct *work); static const struct ethtool_ops rtl8139_ethtool_ops; /* write MMIO register, with flush */ @@ -1010,7 +1010,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1)); spin_lock_init (&tp->lock); spin_lock_init (&tp->rx_lock); - INIT_WORK(&tp->thread, rtl8139_thread, dev); + INIT_DELAYED_WORK(&tp->thread, rtl8139_thread); tp->mii.dev = dev; tp->mii.mdio_read = mdio_read; tp->mii.mdio_write = mdio_write; @@ -1596,15 +1596,16 @@ static inline void rtl8139_thread_iter (struct net_device *dev, RTL_R8 (Config1)); } -static void rtl8139_thread (void *_data) +static void rtl8139_thread (struct work_struct *work) { - struct net_device *dev = _data; - struct rtl8139_private *tp = netdev_priv(dev); + struct rtl8139_private *tp = + container_of(work, struct rtl8139_private, thread.work); + struct net_device *dev = tp->mii.dev; unsigned long thr_delay = next_tick; if (tp->watchdog_fired) { tp->watchdog_fired = 0; - rtl8139_tx_timeout_task(_data); + rtl8139_tx_timeout_task(work); } else if (rtnl_trylock()) { rtl8139_thread_iter (dev, tp, tp->mmio_addr); rtnl_unlock (); @@ -1646,10 +1647,11 @@ static inline void rtl8139_tx_clear (struct rtl8139_private *tp) /* XXX account for unsent Tx packets in tp->stats.tx_dropped */ } -static void rtl8139_tx_timeout_task (void *_data) +static void rtl8139_tx_timeout_task (struct work_struct *work) { - struct net_device *dev = _data; - struct rtl8139_private *tp = netdev_priv(dev); + struct rtl8139_private *tp = + container_of(work, struct rtl8139_private, thread.work); + struct net_device *dev = tp->mii.dev; void __iomem *ioaddr = tp->mmio_addr; int i; u8 tmp8; @@ -1695,7 +1697,7 @@ static void rtl8139_tx_timeout (struct net_device *dev) struct rtl8139_private *tp = netdev_priv(dev); if (!tp->have_thread) { - INIT_WORK(&tp->thread, rtl8139_tx_timeout_task, dev); + INIT_DELAYED_WORK(&tp->thread, rtl8139_tx_timeout_task); schedule_delayed_work(&tp->thread, next_tick); } else tp->watchdog_fired = 1; diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 0dca8bb9d2c..c01f87f5bed 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -405,7 +405,7 @@ static void cleanup_card(struct net_device *dev) iounmap(ei_status.mem); } -void +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/apne.c b/drivers/net/apne.c index 9164d8cd670..d4e40816907 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -568,7 +568,7 @@ static irqreturn_t apne_interrupt(int irq, void *dev_id) #ifdef MODULE static struct net_device *apne_dev; -int init_module(void) +int __init init_module(void) { apne_dev = apne_probe(-1); if (IS_ERR(apne_dev)) @@ -576,7 +576,7 @@ int init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(apne_dev); diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index cc1a27ed197..dba5e516545 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -1041,7 +1041,7 @@ int __init init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(cops_dev); cleanup_card(cops_dev); diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index b54b857e357..fada15d959d 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -41,9 +41,6 @@ #define DRV_NAME "at91_ether" #define DRV_VERSION "1.0" -static struct net_device *at91_dev; - -static struct timer_list check_timer; #define LINK_POLL_INTERVAL (HZ) /* ..................................................................... */ @@ -146,7 +143,7 @@ static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int */ static void update_linkspeed(struct net_device *dev, int silent) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); unsigned int bmsr, bmcr, lpa, mac_cfg; unsigned int speed, duplex; @@ -199,7 +196,7 @@ static void update_linkspeed(struct net_device *dev, int silent) static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); unsigned int phy; /* @@ -242,7 +239,7 @@ done: */ static void enable_phyirq(struct net_device *dev) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); unsigned int dsintr, irq_number; int status; @@ -252,8 +249,7 @@ static void enable_phyirq(struct net_device *dev) * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L), * or board does not have it connected. */ - check_timer.expires = jiffies + LINK_POLL_INTERVAL; - add_timer(&check_timer); + mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL); return; } @@ -294,13 +290,13 @@ static void enable_phyirq(struct net_device *dev) */ static void disable_phyirq(struct net_device *dev) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); unsigned int dsintr; unsigned int irq_number; irq_number = lp->board_data.phy_irq_pin; if (!irq_number) { - del_timer_sync(&check_timer); + del_timer_sync(&lp->check_timer); return; } @@ -340,7 +336,7 @@ static void disable_phyirq(struct net_device *dev) #if 0 static void reset_phy(struct net_device *dev) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); unsigned int bmcr; spin_lock_irq(&lp->lock); @@ -362,13 +358,13 @@ static void reset_phy(struct net_device *dev) static void at91ether_check_link(unsigned long dev_id) { struct net_device *dev = (struct net_device *) dev_id; + struct at91_private *lp = netdev_priv(dev); enable_mdi(); update_linkspeed(dev, 1); disable_mdi(); - check_timer.expires = jiffies + LINK_POLL_INTERVAL; - add_timer(&check_timer); + mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL); } /* ......................... ADDRESS MANAGEMENT ........................ */ @@ -590,7 +586,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); int ret; spin_lock_irq(&lp->lock); @@ -611,7 +607,7 @@ static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cm static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); int ret; spin_lock_irq(&lp->lock); @@ -627,7 +623,7 @@ static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cm static int at91ether_nwayreset(struct net_device *dev) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); int ret; spin_lock_irq(&lp->lock); @@ -658,7 +654,7 @@ static const struct ethtool_ops at91ether_ethtool_ops = { static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); int res; if (!netif_running(dev)) @@ -680,7 +676,7 @@ static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) */ static void at91ether_start(struct net_device *dev) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); struct recv_desc_bufs *dlist, *dlist_phys; int i; unsigned long ctl; @@ -712,7 +708,7 @@ static void at91ether_start(struct net_device *dev) */ static int at91ether_open(struct net_device *dev) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); unsigned long ctl; if (!is_valid_ether_addr(dev->dev_addr)) @@ -752,7 +748,7 @@ static int at91ether_open(struct net_device *dev) */ static int at91ether_close(struct net_device *dev) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); unsigned long ctl; /* Disable Receiver and Transmitter */ @@ -779,7 +775,7 @@ static int at91ether_close(struct net_device *dev) */ static int at91ether_tx(struct sk_buff *skb, struct net_device *dev) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) { netif_stop_queue(dev); @@ -811,7 +807,7 @@ static int at91ether_tx(struct sk_buff *skb, struct net_device *dev) */ static struct net_device_stats *at91ether_stats(struct net_device *dev) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); int ale, lenerr, seqe, lcol, ecol; if (netif_running(dev)) { @@ -847,7 +843,7 @@ static struct net_device_stats *at91ether_stats(struct net_device *dev) */ static void at91ether_rx(struct net_device *dev) { - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); struct recv_desc_bufs *dlist; unsigned char *p_recv; struct sk_buff *skb; @@ -857,14 +853,13 @@ static void at91ether_rx(struct net_device *dev) while (dlist->descriptors[lp->rxBuffIndex].addr & EMAC_DESC_DONE) { p_recv = dlist->recv_buf[lp->rxBuffIndex]; pktlen = dlist->descriptors[lp->rxBuffIndex].size & 0x7ff; /* Length of frame including FCS */ - skb = alloc_skb(pktlen + 2, GFP_ATOMIC); + skb = dev_alloc_skb(pktlen + 2); if (skb != NULL) { skb_reserve(skb, 2); memcpy(skb_put(skb, pktlen), p_recv, pktlen); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); - skb->len = pktlen; dev->last_rx = jiffies; lp->stats.rx_bytes += pktlen; netif_rx(skb); @@ -891,7 +886,7 @@ static void at91ether_rx(struct net_device *dev) static irqreturn_t at91ether_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct at91_private *lp = (struct at91_private *) dev->priv; + struct at91_private *lp = netdev_priv(dev); unsigned long intstatus, ctl; /* MAC Interrupt Status register indicates what interrupts are pending. @@ -927,6 +922,17 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void at91ether_poll_controller(struct net_device *dev) +{ + unsigned long flags; + + local_irq_save(flags); + at91ether_interrupt(dev->irq, dev); + local_irq_restore(flags); +} +#endif + /* * Initialize the ethernet interface */ @@ -939,9 +945,6 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add unsigned int val; int res; - if (at91_dev) /* already initialized */ - return 0; - dev = alloc_etherdev(sizeof(struct at91_private)); if (!dev) return -ENOMEM; @@ -957,7 +960,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add } /* Allocate memory for DMA Receive descriptors */ - lp = (struct at91_private *)dev->priv; + lp = netdev_priv(dev); lp->dlist = (struct recv_desc_bufs *) dma_alloc_coherent(NULL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys, GFP_KERNEL); if (lp->dlist == NULL) { free_irq(dev->irq, dev); @@ -979,6 +982,9 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add dev->set_mac_address = set_mac_address; dev->ethtool_ops = &at91ether_ethtool_ops; dev->do_ioctl = at91ether_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = at91ether_poll_controller; +#endif SET_NETDEV_DEV(dev, &pdev->dev); @@ -1024,7 +1030,6 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys); return res; } - at91_dev = dev; /* Determine current link speed */ spin_lock_irq(&lp->lock); @@ -1036,9 +1041,9 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add /* If board has no PHY IRQ, use a timer to poll the PHY */ if (!lp->board_data.phy_irq_pin) { - init_timer(&check_timer); - check_timer.data = (unsigned long)dev; - check_timer.function = at91ether_check_link; + init_timer(&lp->check_timer); + lp->check_timer.data = (unsigned long)dev; + lp->check_timer.function = at91ether_check_link; } /* Display ethernet banner */ @@ -1115,15 +1120,16 @@ static int __init at91ether_probe(struct platform_device *pdev) static int __devexit at91ether_remove(struct platform_device *pdev) { - struct at91_private *lp = (struct at91_private *) at91_dev->priv; + struct net_device *dev = platform_get_drvdata(pdev); + struct at91_private *lp = netdev_priv(dev); - unregister_netdev(at91_dev); - free_irq(at91_dev->irq, at91_dev); + unregister_netdev(dev); + free_irq(dev->irq, dev); dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys); clk_put(lp->ether_clk); - free_netdev(at91_dev); - at91_dev = NULL; + platform_set_drvdata(pdev, NULL); + free_netdev(dev); return 0; } @@ -1131,8 +1137,8 @@ static int __devexit at91ether_remove(struct platform_device *pdev) static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg) { - struct at91_private *lp = (struct at91_private *) at91_dev->priv; struct net_device *net_dev = platform_get_drvdata(pdev); + struct at91_private *lp = netdev_priv(net_dev); int phy_irq = lp->board_data.phy_irq_pin; if (netif_running(net_dev)) { @@ -1149,8 +1155,8 @@ static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg) static int at91ether_resume(struct platform_device *pdev) { - struct at91_private *lp = (struct at91_private *) at91_dev->priv; struct net_device *net_dev = platform_get_drvdata(pdev); + struct at91_private *lp = netdev_priv(net_dev); int phy_irq = lp->board_data.phy_irq_pin; if (netif_running(net_dev)) { diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h index d1e72e02be3..b6b665de2ea 100644 --- a/drivers/net/arm/at91_ether.h +++ b/drivers/net/arm/at91_ether.h @@ -87,6 +87,7 @@ struct at91_private spinlock_t lock; /* lock for MDI interface */ short phy_media; /* media interface type */ unsigned short phy_address; /* 5-bit MDI address of PHY (0..31) */ + struct timer_list check_timer; /* Poll link status */ /* Transmit */ struct sk_buff *skb; /* holds skb until xmit interrupt completes */ diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index f3478a30e77..d6da3ce9ad7 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -254,7 +254,7 @@ ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsig } while (thislen); } -static int __init +static int __devinit ether1_ramtest(struct net_device *dev, unsigned char byte) { unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL); @@ -308,7 +308,7 @@ ether1_reset (struct net_device *dev) return BUS_16; } -static int __init +static int __devinit ether1_init_2(struct net_device *dev) { int i; @@ -986,7 +986,7 @@ ether1_setmulticastlist (struct net_device *dev) /* ------------------------------------------------------------------------- */ -static void __init ether1_banner(void) +static void __devinit ether1_banner(void) { static unsigned int version_printed = 0; diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 84686c8a5bc..4fc234785d5 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -198,7 +198,7 @@ static inline void ether3_ledon(struct net_device *dev) * Read the ethernet address string from the on board rom. * This is an ascii string!!! */ -static int __init +static int __devinit ether3_addr(char *addr, struct expansion_card *ec) { struct in_chunk_dir cd; @@ -223,7 +223,7 @@ ether3_addr(char *addr, struct expansion_card *ec) /* --------------------------------------------------------------------------- */ -static int __init +static int __devinit ether3_ramtest(struct net_device *dev, unsigned char byte) { unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL); @@ -272,7 +272,7 @@ ether3_ramtest(struct net_device *dev, unsigned char byte) /* ------------------------------------------------------------------------------- */ -static int __init ether3_init_2(struct net_device *dev) +static int __devinit ether3_init_2(struct net_device *dev) { int i; @@ -765,7 +765,7 @@ static void ether3_tx(struct net_device *dev) } } -static void __init ether3_banner(void) +static void __devinit ether3_banner(void) { static unsigned version_printed = 0; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 8620a5b470f..56ae8babd91 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -908,7 +908,7 @@ int __init init_module(void) return 0; } -void +void __exit cleanup_module(void) { unregister_netdev(dev_at1700); diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index d79489e4624..7e37ac86a69 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -1179,7 +1179,7 @@ static int lance_set_mac_address( struct net_device *dev, void *addr ) #ifdef MODULE static struct net_device *atarilance_dev; -int init_module(void) +int __init init_module(void) { atarilance_dev = atarilance_probe(-1); if (IS_ERR(atarilance_dev)) @@ -1187,7 +1187,7 @@ int init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(atarilance_dev); free_irq(atarilance_dev->irq, atarilance_dev); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index fc2f1d1c7ea..5bacb7587df 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -4411,9 +4411,9 @@ bnx2_open(struct net_device *dev) } static void -bnx2_reset_task(void *data) +bnx2_reset_task(struct work_struct *work) { - struct bnx2 *bp = data; + struct bnx2 *bp = container_of(work, struct bnx2, reset_task); if (!netif_running(bp->dev)) return; @@ -5702,7 +5702,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->pdev = pdev; spin_lock_init(&bp->phy_lock); - INIT_WORK(&bp->reset_task, bnx2_reset_task, bp); + INIT_WORK(&bp->reset_task, bnx2_reset_task); dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0); mem_len = MB_GET_CID_ADDR(TX_TSS_CID + 1); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 488d8ed9e74..6482aed4bb7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3684,7 +3684,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd mii->val_out = 0; read_lock_bh(&bond->lock); read_lock(&bond->curr_slave_lock); - if (bond->curr_active_slave) { + if (netif_carrier_ok(bond->dev)) { mii->val_out = BMSR_LSTATUS; } read_unlock(&bond->curr_slave_lock); diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index fd2cc13f7d9..c8126484c2b 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4066,9 +4066,9 @@ static int cas_alloc_rxds(struct cas *cp) return 0; } -static void cas_reset_task(void *data) +static void cas_reset_task(struct work_struct *work) { - struct cas *cp = (struct cas *) data; + struct cas *cp = container_of(work, struct cas, reset_task); #if 0 int pending = atomic_read(&cp->reset_task_pending); #else @@ -5006,7 +5006,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, atomic_set(&cp->reset_task_pending_spare, 0); atomic_set(&cp->reset_task_pending_mtu, 0); #endif - INIT_WORK(&cp->reset_task, cas_reset_task, cp); + INIT_WORK(&cp->reset_task, cas_reset_task); /* Default link parameters */ if (link_mode >= 0 && link_mode <= 6) diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index b265941e137..74758d2c7af 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -279,7 +279,7 @@ struct adapter { struct petp *tp; struct port_info port[MAX_NPORTS]; - struct work_struct stats_update_task; + struct delayed_work stats_update_task; struct timer_list stats_update_timer; spinlock_t tpi_lock; diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h index 60901f25014..cf914349988 100644 --- a/drivers/net/chelsio/cphy.h +++ b/drivers/net/chelsio/cphy.h @@ -91,7 +91,7 @@ struct cphy { int state; /* Link status state machine */ adapter_t *adapter; /* associated adapter */ - struct work_struct phy_update; + struct delayed_work phy_update; u16 bmsr; int count; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 53bec673981..de48eadddbc 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -953,10 +953,11 @@ static void t1_netpoll(struct net_device *dev) * Periodic accumulation of MAC statistics. This is used only if the MAC * does not have any other way to prevent stats counter overflow. */ -static void mac_stats_task(void *data) +static void mac_stats_task(struct work_struct *work) { int i; - struct adapter *adapter = data; + struct adapter *adapter = + container_of(work, struct adapter, stats_update_task.work); for_each_port(adapter, i) { struct port_info *p = &adapter->port[i]; @@ -977,9 +978,10 @@ static void mac_stats_task(void *data) /* * Processes elmer0 external interrupts in process context. */ -static void ext_intr_task(void *data) +static void ext_intr_task(struct work_struct *work) { - struct adapter *adapter = data; + struct adapter *adapter = + container_of(work, struct adapter, ext_intr_handler_task); t1_elmer0_ext_intr_handler(adapter); @@ -1113,9 +1115,9 @@ static int __devinit init_one(struct pci_dev *pdev, spin_lock_init(&adapter->mac_lock); INIT_WORK(&adapter->ext_intr_handler_task, - ext_intr_task, adapter); - INIT_WORK(&adapter->stats_update_task, mac_stats_task, - adapter); + ext_intr_task); + INIT_DELAYED_WORK(&adapter->stats_update_task, + mac_stats_task); pci_set_drvdata(pdev, netdev); } diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index 0b90014d5b3..c7731b6f9de 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c @@ -93,9 +93,11 @@ static int my3126_interrupt_handler(struct cphy *cphy) return cphy_cause_link_change; } -static void my3216_poll(void *arg) +static void my3216_poll(struct work_struct *work) { - my3126_interrupt_handler(arg); + struct cphy *cphy = container_of(work, struct cphy, phy_update.work); + + my3126_interrupt_handler(cphy); } static int my3126_set_loopback(struct cphy *cphy, int on) @@ -171,7 +173,7 @@ static struct cphy *my3126_phy_create(adapter_t *adapter, if (cphy) cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); - INIT_WORK(&cphy->phy_update, my3216_poll, cphy); + INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); cphy->bmsr = 0; return (cphy); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index dec70c2b374..4612f71a710 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1974,7 +1974,7 @@ out: return ret; } -void +void __exit cleanup_module(void) { unregister_netdev(dev_cs89x0); diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 00e2a8a134d..4ae0fed7122 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -40,6 +40,10 @@ * * v0.009: Module support fixes, multiple interfaces support, various * bits. macro + * + * v0.010: Fixes for the PMAD mapping of the LANCE buffer and for the + * PMAX requirement to only use halfword accesses to the + * buffer. macro */ #include <linux/crc32.h> @@ -54,6 +58,7 @@ #include <linux/spinlock.h> #include <linux/stddef.h> #include <linux/string.h> +#include <linux/types.h> #include <asm/addrspace.h> #include <asm/system.h> @@ -67,7 +72,7 @@ #include <asm/dec/tc.h> static char version[] __devinitdata = -"declance.c: v0.009 by Linux MIPS DECstation task force\n"; +"declance.c: v0.010 by Linux MIPS DECstation task force\n"; MODULE_AUTHOR("Linux MIPS DECstation task force"); MODULE_DESCRIPTION("DEC LANCE (DECstation onboard, PMAD-xx) driver"); @@ -110,24 +115,25 @@ MODULE_LICENSE("GPL"); #define LE_C3_BCON 0x1 /* Byte control */ /* Receive message descriptor 1 */ -#define LE_R1_OWN 0x80 /* Who owns the entry */ -#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ -#define LE_R1_FRA 0x20 /* FRA: Frame error */ -#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ -#define LE_R1_CRC 0x08 /* CRC error */ -#define LE_R1_BUF 0x04 /* BUF: Buffer error */ -#define LE_R1_SOP 0x02 /* Start of packet */ -#define LE_R1_EOP 0x01 /* End of packet */ -#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ - -#define LE_T1_OWN 0x80 /* Lance owns the packet */ -#define LE_T1_ERR 0x40 /* Error summary */ -#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ -#define LE_T1_EONE 0x08 /* Error: one retry needed */ -#define LE_T1_EDEF 0x04 /* Error: deferred */ -#define LE_T1_SOP 0x02 /* Start of packet */ -#define LE_T1_EOP 0x01 /* End of packet */ -#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ +#define LE_R1_OWN 0x8000 /* Who owns the entry */ +#define LE_R1_ERR 0x4000 /* Error: if FRA, OFL, CRC or BUF is set */ +#define LE_R1_FRA 0x2000 /* FRA: Frame error */ +#define LE_R1_OFL 0x1000 /* OFL: Frame overflow */ +#define LE_R1_CRC 0x0800 /* CRC error */ +#define LE_R1_BUF 0x0400 /* BUF: Buffer error */ +#define LE_R1_SOP 0x0200 /* Start of packet */ +#define LE_R1_EOP 0x0100 /* End of packet */ +#define LE_R1_POK 0x0300 /* Packet is complete: SOP + EOP */ + +/* Transmit message descriptor 1 */ +#define LE_T1_OWN 0x8000 /* Lance owns the packet */ +#define LE_T1_ERR 0x4000 /* Error summary */ +#define LE_T1_EMORE 0x1000 /* Error: more than one retry needed */ +#define LE_T1_EONE 0x0800 /* Error: one retry needed */ +#define LE_T1_EDEF 0x0400 /* Error: deferred */ +#define LE_T1_SOP 0x0200 /* Start of packet */ +#define LE_T1_EOP 0x0100 /* End of packet */ +#define LE_T1_POK 0x0300 /* Packet is complete: SOP + EOP */ #define LE_T3_BUF 0x8000 /* Buffer error */ #define LE_T3_UFL 0x4000 /* Error underflow */ @@ -156,69 +162,57 @@ MODULE_LICENSE("GPL"); #undef TEST_HITS #define ZERO 0 -/* The DS2000/3000 have a linear 64 KB buffer. - - * The PMAD-AA has 128 kb buffer on-board. +/* + * The DS2100/3100 have a linear 64 kB buffer which supports halfword + * accesses only. Each halfword of the buffer is word-aligned in the + * CPU address space. * - * The IOASIC LANCE devices use a shared memory region. This region as seen - * from the CPU is (max) 128 KB long and has to be on an 128 KB boundary. - * The LANCE sees this as a 64 KB long continuous memory region. + * The PMAD-AA has a 128 kB buffer on-board. * - * The LANCE's DMA address is used as an index in this buffer and DMA takes - * place in bursts of eight 16-Bit words which are packed into four 32-Bit words - * by the IOASIC. This leads to a strange padding: 16 bytes of valid data followed - * by a 16 byte gap :-(. + * The IOASIC LANCE devices use a shared memory region. This region + * as seen from the CPU is (max) 128 kB long and has to be on an 128 kB + * boundary. The LANCE sees this as a 64 kB long continuous memory + * region. + * + * The LANCE's DMA address is used as an index in this buffer and DMA + * takes place in bursts of eight 16-bit words which are packed into + * four 32-bit words by the IOASIC. This leads to a strange padding: + * 16 bytes of valid data followed by a 16 byte gap :-(. */ struct lance_rx_desc { unsigned short rmd0; /* low address of packet */ - short gap0; - unsigned char rmd1_hadr; /* high address of packet */ - unsigned char rmd1_bits; /* descriptor bits */ - short gap1; + unsigned short rmd1; /* high address of packet + and descriptor bits */ short length; /* 2s complement (negative!) of buffer length */ - short gap2; unsigned short mblength; /* actual number of bytes received */ - short gap3; }; struct lance_tx_desc { unsigned short tmd0; /* low address of packet */ - short gap0; - unsigned char tmd1_hadr; /* high address of packet */ - unsigned char tmd1_bits; /* descriptor bits */ - short gap1; + unsigned short tmd1; /* high address of packet + and descriptor bits */ short length; /* 2s complement (negative!) of buffer length */ - short gap2; unsigned short misc; - short gap3; }; /* First part of the LANCE initialization block, described in databook. */ struct lance_init_block { unsigned short mode; /* pre-set mode (reg. 15) */ - short gap0; - unsigned char phys_addr[12]; /* physical ethernet address - only 0, 1, 4, 5, 8, 9 are valid - 2, 3, 6, 7, 10, 11 are gaps */ - unsigned short filter[8]; /* multicast filter - only 0, 2, 4, 6 are valid - 1, 3, 5, 7 are gaps */ + unsigned short phys_addr[3]; /* physical ethernet address */ + unsigned short filter[4]; /* multicast filter */ /* Receive and transmit ring base, along with extra bits. */ unsigned short rx_ptr; /* receive descriptor addr */ - short gap1; unsigned short rx_len; /* receive len and high addr */ - short gap2; unsigned short tx_ptr; /* transmit descriptor addr */ - short gap3; unsigned short tx_len; /* transmit len and high addr */ - short gap4; - short gap5[8]; + + short gap[4]; /* The buffer descriptors */ struct lance_rx_desc brx_ring[RX_RING_SIZE]; @@ -226,15 +220,28 @@ struct lance_init_block { }; #define BUF_OFFSET_CPU sizeof(struct lance_init_block) -#define BUF_OFFSET_LNC (sizeof(struct lance_init_block)>>1) +#define BUF_OFFSET_LNC sizeof(struct lance_init_block) -#define libdesc_offset(rt, elem) \ -((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem]))))) +#define shift_off(off, type) \ + (type == ASIC_LANCE || type == PMAX_LANCE ? off << 1 : off) -/* - * This works *only* for the ring descriptors - */ -#define LANCE_ADDR(x) (CPHYSADDR(x) >> 1) +#define lib_off(rt, type) \ + shift_off(offsetof(struct lance_init_block, rt), type) + +#define lib_ptr(ib, rt, type) \ + ((volatile u16 *)((u8 *)(ib) + lib_off(rt, type))) + +#define rds_off(rt, type) \ + shift_off(offsetof(struct lance_rx_desc, rt), type) + +#define rds_ptr(rd, rt, type) \ + ((volatile u16 *)((u8 *)(rd) + rds_off(rt, type))) + +#define tds_off(rt, type) \ + shift_off(offsetof(struct lance_tx_desc, rt), type) + +#define tds_ptr(td, rt, type) \ + ((volatile u16 *)((u8 *)(td) + tds_off(rt, type))) struct lance_private { struct net_device *next; @@ -242,7 +249,6 @@ struct lance_private { int slot; int dma_irq; volatile struct lance_regs *ll; - volatile struct lance_init_block *init_block; spinlock_t lock; @@ -260,8 +266,8 @@ struct lance_private { char *tx_buf_ptr_cpu[TX_RING_SIZE]; /* Pointers to the ring buffers as seen from the LANCE */ - char *rx_buf_ptr_lnc[RX_RING_SIZE]; - char *tx_buf_ptr_lnc[TX_RING_SIZE]; + uint rx_buf_ptr_lnc[RX_RING_SIZE]; + uint tx_buf_ptr_lnc[TX_RING_SIZE]; }; #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ @@ -294,7 +300,7 @@ static inline void writereg(volatile unsigned short *regptr, short value) static void load_csrs(struct lance_private *lp) { volatile struct lance_regs *ll = lp->ll; - int leptr; + uint leptr; /* The address space as seen from the LANCE * begins at address 0. HK @@ -316,12 +322,14 @@ static void load_csrs(struct lance_private *lp) * Our specialized copy routines * */ -void cp_to_buf(const int type, void *to, const void *from, int len) +static void cp_to_buf(const int type, void *to, const void *from, int len) { unsigned short *tp, *fp, clen; unsigned char *rtp, *rfp; - if (type == PMAX_LANCE) { + if (type == PMAD_LANCE) { + memcpy(to, from, len); + } else if (type == PMAX_LANCE) { clen = len >> 1; tp = (unsigned short *) to; fp = (unsigned short *) from; @@ -370,12 +378,14 @@ void cp_to_buf(const int type, void *to, const void *from, int len) iob(); } -void cp_from_buf(const int type, void *to, const void *from, int len) +static void cp_from_buf(const int type, void *to, const void *from, int len) { unsigned short *tp, *fp, clen; unsigned char *rtp, *rfp; - if (type == PMAX_LANCE) { + if (type == PMAD_LANCE) { + memcpy(to, from, len); + } else if (type == PMAX_LANCE) { clen = len >> 1; tp = (unsigned short *) to; fp = (unsigned short *) from; @@ -431,12 +441,10 @@ void cp_from_buf(const int type, void *to, const void *from, int len) static void lance_init_ring(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib; - int leptr; + volatile u16 *ib = (volatile u16 *)dev->mem_start; + uint leptr; int i; - ib = (struct lance_init_block *) (dev->mem_start); - /* Lock out other processes while setting up hardware */ netif_stop_queue(dev); lp->rx_new = lp->tx_new = 0; @@ -445,55 +453,64 @@ static void lance_init_ring(struct net_device *dev) /* Copy the ethernet address to the lance init block. * XXX bit 0 of the physical address registers has to be zero */ - ib->phys_addr[0] = dev->dev_addr[0]; - ib->phys_addr[1] = dev->dev_addr[1]; - ib->phys_addr[4] = dev->dev_addr[2]; - ib->phys_addr[5] = dev->dev_addr[3]; - ib->phys_addr[8] = dev->dev_addr[4]; - ib->phys_addr[9] = dev->dev_addr[5]; + *lib_ptr(ib, phys_addr[0], lp->type) = (dev->dev_addr[1] << 8) | + dev->dev_addr[0]; + *lib_ptr(ib, phys_addr[1], lp->type) = (dev->dev_addr[3] << 8) | + dev->dev_addr[2]; + *lib_ptr(ib, phys_addr[2], lp->type) = (dev->dev_addr[5] << 8) | + dev->dev_addr[4]; /* Setup the initialization block */ /* Setup rx descriptor pointer */ - leptr = LANCE_ADDR(libdesc_offset(brx_ring, 0)); - ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16); - ib->rx_ptr = leptr; + leptr = offsetof(struct lance_init_block, brx_ring); + *lib_ptr(ib, rx_len, lp->type) = (LANCE_LOG_RX_BUFFERS << 13) | + (leptr >> 16); + *lib_ptr(ib, rx_ptr, lp->type) = leptr; if (ZERO) - printk("RX ptr: %8.8x(%8.8x)\n", leptr, libdesc_offset(brx_ring, 0)); + printk("RX ptr: %8.8x(%8.8x)\n", + leptr, lib_off(brx_ring, lp->type)); /* Setup tx descriptor pointer */ - leptr = LANCE_ADDR(libdesc_offset(btx_ring, 0)); - ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16); - ib->tx_ptr = leptr; + leptr = offsetof(struct lance_init_block, btx_ring); + *lib_ptr(ib, tx_len, lp->type) = (LANCE_LOG_TX_BUFFERS << 13) | + (leptr >> 16); + *lib_ptr(ib, tx_ptr, lp->type) = leptr; if (ZERO) - printk("TX ptr: %8.8x(%8.8x)\n", leptr, libdesc_offset(btx_ring, 0)); + printk("TX ptr: %8.8x(%8.8x)\n", + leptr, lib_off(btx_ring, lp->type)); if (ZERO) printk("TX rings:\n"); /* Setup the Tx ring entries */ for (i = 0; i < TX_RING_SIZE; i++) { - leptr = (int) lp->tx_buf_ptr_lnc[i]; - ib->btx_ring[i].tmd0 = leptr; - ib->btx_ring[i].tmd1_hadr = leptr >> 16; - ib->btx_ring[i].tmd1_bits = 0; - ib->btx_ring[i].length = 0xf000; /* The ones required by tmd2 */ - ib->btx_ring[i].misc = 0; + leptr = lp->tx_buf_ptr_lnc[i]; + *lib_ptr(ib, btx_ring[i].tmd0, lp->type) = leptr; + *lib_ptr(ib, btx_ring[i].tmd1, lp->type) = (leptr >> 16) & + 0xff; + *lib_ptr(ib, btx_ring[i].length, lp->type) = 0xf000; + /* The ones required by tmd2 */ + *lib_ptr(ib, btx_ring[i].misc, lp->type) = 0; if (i < 3 && ZERO) - printk("%d: 0x%8.8x(0x%8.8x)\n", i, leptr, (int) lp->tx_buf_ptr_cpu[i]); + printk("%d: 0x%8.8x(0x%8.8x)\n", + i, leptr, (uint)lp->tx_buf_ptr_cpu[i]); } /* Setup the Rx ring entries */ if (ZERO) printk("RX rings:\n"); for (i = 0; i < RX_RING_SIZE; i++) { - leptr = (int) lp->rx_buf_ptr_lnc[i]; - ib->brx_ring[i].rmd0 = leptr; - ib->brx_ring[i].rmd1_hadr = leptr >> 16; - ib->brx_ring[i].rmd1_bits = LE_R1_OWN; - ib->brx_ring[i].length = -RX_BUFF_SIZE | 0xf000; - ib->brx_ring[i].mblength = 0; + leptr = lp->rx_buf_ptr_lnc[i]; + *lib_ptr(ib, brx_ring[i].rmd0, lp->type) = leptr; + *lib_ptr(ib, brx_ring[i].rmd1, lp->type) = ((leptr >> 16) & + 0xff) | + LE_R1_OWN; + *lib_ptr(ib, brx_ring[i].length, lp->type) = -RX_BUFF_SIZE | + 0xf000; + *lib_ptr(ib, brx_ring[i].mblength, lp->type) = 0; if (i < 3 && ZERO) - printk("%d: 0x%8.8x(0x%8.8x)\n", i, leptr, (int) lp->rx_buf_ptr_cpu[i]); + printk("%d: 0x%8.8x(0x%8.8x)\n", + i, leptr, (uint)lp->rx_buf_ptr_cpu[i]); } iob(); } @@ -511,11 +528,13 @@ static int init_restart_lance(struct lance_private *lp) udelay(10); } if ((i == 100) || (ll->rdp & LE_C0_ERR)) { - printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp); + printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", + i, ll->rdp); return -1; } if ((ll->rdp & LE_C0_ERR)) { - printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp); + printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", + i, ll->rdp); return -1; } writereg(&ll->rdp, LE_C0_IDON); @@ -528,12 +547,11 @@ static int init_restart_lance(struct lance_private *lp) static int lance_rx(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib; - volatile struct lance_rx_desc *rd = 0; - unsigned char bits; - int len = 0; - struct sk_buff *skb = 0; - ib = (struct lance_init_block *) (dev->mem_start); + volatile u16 *ib = (volatile u16 *)dev->mem_start; + volatile u16 *rd; + unsigned short bits; + int entry, len; + struct sk_buff *skb; #ifdef TEST_HITS { @@ -542,19 +560,22 @@ static int lance_rx(struct net_device *dev) printk("["); for (i = 0; i < RX_RING_SIZE; i++) { if (i == lp->rx_new) - printk("%s", ib->brx_ring[i].rmd1_bits & + printk("%s", *lib_ptr(ib, brx_ring[i].rmd1, + lp->type) & LE_R1_OWN ? "_" : "X"); else - printk("%s", ib->brx_ring[i].rmd1_bits & + printk("%s", *lib_ptr(ib, brx_ring[i].rmd1, + lp->type) & LE_R1_OWN ? "." : "1"); } printk("]"); } #endif - for (rd = &ib->brx_ring[lp->rx_new]; - !((bits = rd->rmd1_bits) & LE_R1_OWN); - rd = &ib->brx_ring[lp->rx_new]) { + for (rd = lib_ptr(ib, brx_ring[lp->rx_new], lp->type); + !((bits = *rds_ptr(rd, rmd1, lp->type)) & LE_R1_OWN); + rd = lib_ptr(ib, brx_ring[lp->rx_new], lp->type)) { + entry = lp->rx_new; /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { @@ -575,16 +596,18 @@ static int lance_rx(struct net_device *dev) if (bits & LE_R1_EOP) lp->stats.rx_errors++; } else { - len = (rd->mblength & 0xfff) - 4; + len = (*rds_ptr(rd, mblength, lp->type) & 0xfff) - 4; skb = dev_alloc_skb(len + 2); if (skb == 0) { printk("%s: Memory squeeze, deferring packet.\n", dev->name); lp->stats.rx_dropped++; - rd->mblength = 0; - rd->rmd1_bits = LE_R1_OWN; - lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; + *rds_ptr(rd, mblength, lp->type) = 0; + *rds_ptr(rd, rmd1, lp->type) = + ((lp->rx_buf_ptr_lnc[entry] >> 16) & + 0xff) | LE_R1_OWN; + lp->rx_new = (entry + 1) & RX_RING_MOD_MASK; return 0; } lp->stats.rx_bytes += len; @@ -594,8 +617,7 @@ static int lance_rx(struct net_device *dev) skb_put(skb, len); /* make room */ cp_from_buf(lp->type, skb->data, - (char *)lp->rx_buf_ptr_cpu[lp->rx_new], - len); + (char *)lp->rx_buf_ptr_cpu[entry], len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); @@ -604,10 +626,11 @@ static int lance_rx(struct net_device *dev) } /* Return the packet to the pool */ - rd->mblength = 0; - rd->length = -RX_BUFF_SIZE | 0xf000; - rd->rmd1_bits = LE_R1_OWN; - lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; + *rds_ptr(rd, mblength, lp->type) = 0; + *rds_ptr(rd, length, lp->type) = -RX_BUFF_SIZE | 0xf000; + *rds_ptr(rd, rmd1, lp->type) = + ((lp->rx_buf_ptr_lnc[entry] >> 16) & 0xff) | LE_R1_OWN; + lp->rx_new = (entry + 1) & RX_RING_MOD_MASK; } return 0; } @@ -615,24 +638,24 @@ static int lance_rx(struct net_device *dev) static void lance_tx(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib; + volatile u16 *ib = (volatile u16 *)dev->mem_start; volatile struct lance_regs *ll = lp->ll; - volatile struct lance_tx_desc *td; + volatile u16 *td; int i, j; int status; - ib = (struct lance_init_block *) (dev->mem_start); + j = lp->tx_old; spin_lock(&lp->lock); for (i = j; i != lp->tx_new; i = j) { - td = &ib->btx_ring[i]; + td = lib_ptr(ib, btx_ring[i], lp->type); /* If we hit a packet not owned by us, stop */ - if (td->tmd1_bits & LE_T1_OWN) + if (*tds_ptr(td, tmd1, lp->type) & LE_T1_OWN) break; - if (td->tmd1_bits & LE_T1_ERR) { - status = td->misc; + if (*tds_ptr(td, tmd1, lp->type) & LE_T1_ERR) { + status = *tds_ptr(td, misc, lp->type); lp->stats.tx_errors++; if (status & LE_T3_RTY) @@ -667,18 +690,19 @@ static void lance_tx(struct net_device *dev) init_restart_lance(lp); goto out; } - } else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) { + } else if ((*tds_ptr(td, tmd1, lp->type) & LE_T1_POK) == + LE_T1_POK) { /* * So we don't count the packet more than once. */ - td->tmd1_bits &= ~(LE_T1_POK); + *tds_ptr(td, tmd1, lp->type) &= ~(LE_T1_POK); /* One collision before packet was sent. */ - if (td->tmd1_bits & LE_T1_EONE) + if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EONE) lp->stats.collisions++; /* More than one collision, be optimistic. */ - if (td->tmd1_bits & LE_T1_EMORE) + if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EMORE) lp->stats.collisions += 2; lp->stats.tx_packets++; @@ -752,7 +776,7 @@ struct net_device *last_dev = 0; static int lance_open(struct net_device *dev) { - volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start); + volatile u16 *ib = (volatile u16 *)dev->mem_start; struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int status = 0; @@ -769,11 +793,11 @@ static int lance_open(struct net_device *dev) * * BTW it is common bug in all lance drivers! --ANK */ - ib->mode = 0; - ib->filter [0] = 0; - ib->filter [2] = 0; - ib->filter [4] = 0; - ib->filter [6] = 0; + *lib_ptr(ib, mode, lp->type) = 0; + *lib_ptr(ib, filter[0], lp->type) = 0; + *lib_ptr(ib, filter[1], lp->type) = 0; + *lib_ptr(ib, filter[2], lp->type) = 0; + *lib_ptr(ib, filter[3], lp->type) = 0; lance_init_ring(dev); load_csrs(lp); @@ -874,12 +898,10 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; - volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start); - int entry, skblen, len; + volatile u16 *ib = (volatile u16 *)dev->mem_start; + int entry, len; - skblen = skb->len; - - len = skblen; + len = skb->len; if (len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) @@ -889,23 +911,17 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->stats.tx_bytes += len; - entry = lp->tx_new & TX_RING_MOD_MASK; - ib->btx_ring[entry].length = (-len); - ib->btx_ring[entry].misc = 0; - - cp_to_buf(lp->type, (char *)lp->tx_buf_ptr_cpu[entry], skb->data, - skblen); + entry = lp->tx_new; + *lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len); + *lib_ptr(ib, btx_ring[entry].misc, lp->type) = 0; - /* Clear the slack of the packet, do I need this? */ - /* For a firewall it's a good idea - AC */ -/* - if (len != skblen) - memset ((char *) &ib->tx_buf [entry][skblen], 0, (len - skblen) << 1); - */ + cp_to_buf(lp->type, (char *)lp->tx_buf_ptr_cpu[entry], skb->data, len); /* Now, give the packet to the lance */ - ib->btx_ring[entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN); - lp->tx_new = (lp->tx_new + 1) & TX_RING_MOD_MASK; + *lib_ptr(ib, btx_ring[entry].tmd1, lp->type) = + ((lp->tx_buf_ptr_lnc[entry] >> 16) & 0xff) | + (LE_T1_POK | LE_T1_OWN); + lp->tx_new = (entry + 1) & TX_RING_MOD_MASK; if (TX_BUFFS_AVAIL <= 0) netif_stop_queue(dev); @@ -930,8 +946,8 @@ static struct net_device_stats *lance_get_stats(struct net_device *dev) static void lance_load_multicast(struct net_device *dev) { - volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start); - volatile u16 *mcast_table = (u16 *) & ib->filter; + struct lance_private *lp = netdev_priv(dev); + volatile u16 *ib = (volatile u16 *)dev->mem_start; struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i; @@ -939,17 +955,17 @@ static void lance_load_multicast(struct net_device *dev) /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI) { - ib->filter[0] = 0xffff; - ib->filter[2] = 0xffff; - ib->filter[4] = 0xffff; - ib->filter[6] = 0xffff; + *lib_ptr(ib, filter[0], lp->type) = 0xffff; + *lib_ptr(ib, filter[1], lp->type) = 0xffff; + *lib_ptr(ib, filter[2], lp->type) = 0xffff; + *lib_ptr(ib, filter[3], lp->type) = 0xffff; return; } /* clear the multicast filter */ - ib->filter[0] = 0; - ib->filter[2] = 0; - ib->filter[4] = 0; - ib->filter[6] = 0; + *lib_ptr(ib, filter[0], lp->type) = 0; + *lib_ptr(ib, filter[1], lp->type) = 0; + *lib_ptr(ib, filter[2], lp->type) = 0; + *lib_ptr(ib, filter[3], lp->type) = 0; /* Add addresses */ for (i = 0; i < dev->mc_count; i++) { @@ -962,7 +978,7 @@ static void lance_load_multicast(struct net_device *dev) crc = ether_crc_le(ETH_ALEN, addrs); crc = crc >> 26; - mcast_table[2 * (crc >> 4)] |= 1 << (crc & 0xf); + *lib_ptr(ib, filter[crc >> 4], lp->type) |= 1 << (crc & 0xf); } return; } @@ -970,11 +986,9 @@ static void lance_load_multicast(struct net_device *dev) static void lance_set_multicast(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - volatile struct lance_init_block *ib; + volatile u16 *ib = (volatile u16 *)dev->mem_start; volatile struct lance_regs *ll = lp->ll; - ib = (struct lance_init_block *) (dev->mem_start); - if (!netif_running(dev)) return; @@ -992,9 +1006,9 @@ static void lance_set_multicast(struct net_device *dev) lance_init_ring(dev); if (dev->flags & IFF_PROMISC) { - ib->mode |= LE_MO_PROM; + *lib_ptr(ib, mode, lp->type) |= LE_MO_PROM; } else { - ib->mode &= ~LE_MO_PROM; + *lib_ptr(ib, mode, lp->type) &= ~LE_MO_PROM; lance_load_multicast(dev); } load_csrs(lp); @@ -1051,7 +1065,6 @@ static int __init dec_lance_init(const int type, const int slot) lp->type = type; lp->slot = slot; switch (type) { -#ifdef CONFIG_TC case ASIC_LANCE: dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE); @@ -1073,20 +1086,20 @@ static int __init dec_lance_init(const int type, const int slot) */ for (i = 0; i < RX_RING_SIZE; i++) { lp->rx_buf_ptr_cpu[i] = - (char *)(dev->mem_start + BUF_OFFSET_CPU + + (char *)(dev->mem_start + 2 * BUF_OFFSET_CPU + 2 * i * RX_BUFF_SIZE); lp->rx_buf_ptr_lnc[i] = - (char *)(BUF_OFFSET_LNC + i * RX_BUFF_SIZE); + (BUF_OFFSET_LNC + i * RX_BUFF_SIZE); } for (i = 0; i < TX_RING_SIZE; i++) { lp->tx_buf_ptr_cpu[i] = - (char *)(dev->mem_start + BUF_OFFSET_CPU + + (char *)(dev->mem_start + 2 * BUF_OFFSET_CPU + 2 * RX_RING_SIZE * RX_BUFF_SIZE + 2 * i * TX_BUFF_SIZE); lp->tx_buf_ptr_lnc[i] = - (char *)(BUF_OFFSET_LNC + - RX_RING_SIZE * RX_BUFF_SIZE + - i * TX_BUFF_SIZE); + (BUF_OFFSET_LNC + + RX_RING_SIZE * RX_BUFF_SIZE + + i * TX_BUFF_SIZE); } /* Setup I/O ASIC LANCE DMA. */ @@ -1095,11 +1108,12 @@ static int __init dec_lance_init(const int type, const int slot) CPHYSADDR(dev->mem_start) << 3); break; - +#ifdef CONFIG_TC case PMAD_LANCE: claim_tc_card(slot); dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot)); + dev->mem_end = dev->mem_start + 0x100000; dev->base_addr = dev->mem_start + 0x100000; dev->irq = get_tc_irq_nr(slot); esar_base = dev->mem_start + 0x1c0002; @@ -1110,7 +1124,7 @@ static int __init dec_lance_init(const int type, const int slot) (char *)(dev->mem_start + BUF_OFFSET_CPU + i * RX_BUFF_SIZE); lp->rx_buf_ptr_lnc[i] = - (char *)(BUF_OFFSET_LNC + i * RX_BUFF_SIZE); + (BUF_OFFSET_LNC + i * RX_BUFF_SIZE); } for (i = 0; i < TX_RING_SIZE; i++) { lp->tx_buf_ptr_cpu[i] = @@ -1118,18 +1132,18 @@ static int __init dec_lance_init(const int type, const int slot) RX_RING_SIZE * RX_BUFF_SIZE + i * TX_BUFF_SIZE); lp->tx_buf_ptr_lnc[i] = - (char *)(BUF_OFFSET_LNC + - RX_RING_SIZE * RX_BUFF_SIZE + - i * TX_BUFF_SIZE); + (BUF_OFFSET_LNC + + RX_RING_SIZE * RX_BUFF_SIZE + + i * TX_BUFF_SIZE); } break; #endif - case PMAX_LANCE: dev->irq = dec_interrupt[DEC_IRQ_LANCE]; dev->base_addr = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE); dev->mem_start = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE_MEM); + dev->mem_end = dev->mem_start + KN01_SLOT_SIZE; esar_base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_ESAR + 1); lp->dma_irq = -1; @@ -1138,20 +1152,20 @@ static int __init dec_lance_init(const int type, const int slot) */ for (i = 0; i < RX_RING_SIZE; i++) { lp->rx_buf_ptr_cpu[i] = - (char *)(dev->mem_start + BUF_OFFSET_CPU + + (char *)(dev->mem_start + 2 * BUF_OFFSET_CPU + 2 * i * RX_BUFF_SIZE); lp->rx_buf_ptr_lnc[i] = - (char *)(BUF_OFFSET_LNC + i * RX_BUFF_SIZE); + (BUF_OFFSET_LNC + i * RX_BUFF_SIZE); } for (i = 0; i < TX_RING_SIZE; i++) { lp->tx_buf_ptr_cpu[i] = - (char *)(dev->mem_start + BUF_OFFSET_CPU + + (char *)(dev->mem_start + 2 * BUF_OFFSET_CPU + 2 * RX_RING_SIZE * RX_BUFF_SIZE + 2 * i * TX_BUFF_SIZE); lp->tx_buf_ptr_lnc[i] = - (char *)(BUF_OFFSET_LNC + - RX_RING_SIZE * RX_BUFF_SIZE + - i * TX_BUFF_SIZE); + (BUF_OFFSET_LNC + + RX_RING_SIZE * RX_BUFF_SIZE + + i * TX_BUFF_SIZE); } break; @@ -1279,10 +1293,8 @@ static int __init dec_lance_probe(void) /* Then handle onboard devices. */ if (dec_interrupt[DEC_IRQ_LANCE] >= 0) { if (dec_interrupt[DEC_IRQ_LANCE_MERR] >= 0) { -#ifdef CONFIG_TC if (dec_lance_init(ASIC_LANCE, -1) >= 0) count++; -#endif } else if (!TURBOCHANNEL) { if (dec_lance_init(PMAX_LANCE, -1) >= 0) count++; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 3a8df479cbd..03bf164f9e8 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2102,9 +2102,10 @@ static void e100_tx_timeout(struct net_device *netdev) schedule_work(&nic->tx_timeout_task); } -static void e100_tx_timeout_task(struct net_device *netdev) +static void e100_tx_timeout_task(struct work_struct *work) { - struct nic *nic = netdev_priv(netdev); + struct nic *nic = container_of(work, struct nic, tx_timeout_task); + struct net_device *netdev = nic->netdev; DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", readb(&nic->csr->scb.status)); @@ -2637,8 +2638,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, nic->blink_timer.function = e100_blink_led; nic->blink_timer.data = (unsigned long)nic; - INIT_WORK(&nic->tx_timeout_task, - (void (*)(void *))e100_tx_timeout_task, netdev); + INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task); if((err = e100_alloc(nic))) { DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n"); diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 32dde0adb68..73f3a85fd23 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -190,7 +190,7 @@ void e1000_set_ethtool_ops(struct net_device *netdev); static void e1000_enter_82542_rst(struct e1000_adapter *adapter); static void e1000_leave_82542_rst(struct e1000_adapter *adapter); static void e1000_tx_timeout(struct net_device *dev); -static void e1000_reset_task(struct net_device *dev); +static void e1000_reset_task(struct work_struct *work); static void e1000_smartspeed(struct e1000_adapter *adapter); static int e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb); @@ -914,8 +914,7 @@ e1000_probe(struct pci_dev *pdev, adapter->phy_info_timer.function = &e1000_update_phy_info; adapter->phy_info_timer.data = (unsigned long) adapter; - INIT_WORK(&adapter->reset_task, - (void (*)(void *))e1000_reset_task, netdev); + INIT_WORK(&adapter->reset_task, e1000_reset_task); e1000_check_options(adapter); @@ -3306,9 +3305,10 @@ e1000_tx_timeout(struct net_device *netdev) } static void -e1000_reset_task(struct net_device *netdev) +e1000_reset_task(struct work_struct *work) { - struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_adapter *adapter = + container_of(work, struct e1000_adapter, reset_task); e1000_reinit_locked(adapter); } diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index d39e8480ca5..c62d9c6363c 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -463,7 +463,7 @@ static void cleanup_card(struct net_device *dev) release_region(dev->base_addr, E21_IO_EXTENT); } -void +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index a4eb0dc99ec..b4463094c93 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1827,7 +1827,7 @@ int __init init_module(void) return n_eepro ? 0 : -ENODEV; } -void +void __exit cleanup_module(void) { int i; diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index e14be020e56..4a50fcb5ad6 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -1719,7 +1719,7 @@ int __init init_module(void) return -ENXIO; } -void cleanup_module(void) +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 6ad69610141..83fa32f7239 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2224,11 +2224,12 @@ static int ehea_stop(struct net_device *dev) return ret; } -static void ehea_reset_port(void *data) +static void ehea_reset_port(struct work_struct *work) { int ret; - struct net_device *dev = data; - struct ehea_port *port = netdev_priv(dev); + struct ehea_port *port = + container_of(work, struct ehea_port, reset_task); + struct net_device *dev = port->netdev; port->resets++; down(&port->port_lock); @@ -2379,7 +2380,7 @@ static int ehea_setup_single_port(struct ehea_port *port, dev->tx_timeout = &ehea_tx_watchdog; dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT; - INIT_WORK(&port->reset_task, ehea_reset_port, dev); + INIT_WORK(&port->reset_task, ehea_reset_port); ehea_set_ethtool_ops(dev); diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index fd7b32a24ea..2d2ea94a00b 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -455,7 +455,7 @@ static void cleanup_card(struct net_device *dev) iounmap(ei_status.mem); } -void +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index b7b8bc2a630..93283e386f3 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1475,7 +1475,7 @@ int __init init_module(void) return -ENXIO; } -void cleanup_module(void) +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 1ed9cccd3c1..3c33d6f6a6a 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -168,8 +168,9 @@ struct baycom_state { int magic; struct pardevice *pdev; + struct net_device *dev; unsigned int work_running; - struct work_struct run_work; + struct delayed_work run_work; unsigned int modem; unsigned int bitrate; unsigned char stat; @@ -659,16 +660,18 @@ static int receive(struct net_device *dev, int cnt) #define GETTICK(x) #endif /* __i386__ */ -static void epp_bh(struct net_device *dev) +static void epp_bh(struct work_struct *work) { + struct net_device *dev; struct baycom_state *bc; struct parport *pp; unsigned char stat; unsigned char tmp[2]; unsigned int time1 = 0, time2 = 0, time3 = 0; int cnt, cnt2; - - bc = netdev_priv(dev); + + bc = container_of(work, struct baycom_state, run_work.work); + dev = bc->dev; if (!bc->work_running) return; baycom_int_freq(bc); @@ -889,7 +892,7 @@ static int epp_open(struct net_device *dev) return -EBUSY; } dev->irq = /*pp->irq*/ 0; - INIT_WORK(&bc->run_work, (void *)(void *)epp_bh, dev); + INIT_DELAYED_WORK(&bc->run_work, epp_bh); bc->work_running = 1; bc->modem = EPP_CONVENTIONAL; if (eppconfig(bc)) @@ -1213,6 +1216,7 @@ static void __init baycom_epp_dev_setup(struct net_device *dev) /* * initialize part of the baycom_state struct */ + bc->dev = dev; bc->magic = BAYCOM_MAGIC; bc->cfg.fclk = 19666600; bc->cfg.bps = 9600; diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 0f8b9afd55b..e6e721aff6f 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -252,7 +252,7 @@ static inline void z8530_isr(struct scc_info *info); static irqreturn_t scc_isr(int irq, void *dev_id); static void rx_isr(struct scc_priv *priv); static void special_condition(struct scc_priv *priv, int rc); -static void rx_bh(void *arg); +static void rx_bh(struct work_struct *); static void tx_isr(struct scc_priv *priv); static void es_isr(struct scc_priv *priv); static void tm_isr(struct scc_priv *priv); @@ -579,7 +579,7 @@ static int __init setup_adapter(int card_base, int type, int n) priv->param.clocks = TCTRxCP | RCRTxCP; priv->param.persist = 256; priv->param.dma = -1; - INIT_WORK(&priv->rx_work, rx_bh, priv); + INIT_WORK(&priv->rx_work, rx_bh); dev->priv = priv; sprintf(dev->name, "dmascc%i", 2 * n + i); dev->base_addr = card_base; @@ -1272,9 +1272,9 @@ static void special_condition(struct scc_priv *priv, int rc) } -static void rx_bh(void *arg) +static void rx_bh(struct work_struct *ugli_api) { - struct scc_priv *priv = arg; + struct scc_priv *priv = container_of(ugli_api, struct scc_priv, rx_work); int i = priv->rx_tail; int cb; unsigned long flags; diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 6abcfd2a4b2..99a36cc3f8d 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -482,7 +482,7 @@ static void cleanup_card(struct net_device *dev) release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); } -void +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/hp.c b/drivers/net/hp.c index 29470970aa2..635b13c2e2a 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -444,7 +444,7 @@ static void cleanup_card(struct net_device *dev) release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); } -void +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index b32c52ed19d..f0c61f3b2a8 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -560,9 +560,9 @@ static inline int mcs_find_endpoints(struct mcs_cb *mcs, return ret; } -static void mcs_speed_work(void *arg) +static void mcs_speed_work(struct work_struct *work) { - struct mcs_cb *mcs = arg; + struct mcs_cb *mcs = container_of(work, struct mcs_cb, work); struct net_device *netdev = mcs->netdev; mcs_speed_change(mcs); @@ -927,7 +927,7 @@ static int mcs_probe(struct usb_interface *intf, irda_qos_bits_to_value(&mcs->qos); /* Speed change work initialisation*/ - INIT_WORK(&mcs->work, mcs_speed_work, mcs); + INIT_WORK(&mcs->work, mcs_speed_work); /* Override the network functions we need to use */ ndev->hard_start_xmit = mcs_hard_xmit; diff --git a/drivers/net/irda/sir-dev.h b/drivers/net/irda/sir-dev.h index 9fa294a546d..2a57bc67ce3 100644 --- a/drivers/net/irda/sir-dev.h +++ b/drivers/net/irda/sir-dev.h @@ -22,7 +22,7 @@ struct sir_fsm { struct semaphore sem; - struct work_struct work; + struct delayed_work work; unsigned state, substate; int param; int result; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 3b5854d10c1..17b0c3ab620 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -100,9 +100,9 @@ static int sirdev_tx_complete_fsm(struct sir_dev *dev) * Both must be unlocked/restarted on completion - but only on final exit. */ -static void sirdev_config_fsm(void *data) +static void sirdev_config_fsm(struct work_struct *work) { - struct sir_dev *dev = data; + struct sir_dev *dev = container_of(work, struct sir_dev, fsm.work.work); struct sir_fsm *fsm = &dev->fsm; int next_state; int ret = -1; @@ -309,8 +309,8 @@ int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned par fsm->param = param; fsm->result = 0; - INIT_WORK(&fsm->work, sirdev_config_fsm, dev); - queue_work(irda_sir_wq, &fsm->work); + INIT_DELAYED_WORK(&fsm->work, sirdev_config_fsm); + queue_delayed_work(irda_sir_wq, &fsm->work, 0); return 0; } diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 2284e2ce169..d6f4f185bf3 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -166,7 +166,7 @@ struct veth_msg { struct veth_lpar_connection { HvLpIndex remote_lp; - struct work_struct statemachine_wq; + struct delayed_work statemachine_wq; struct veth_msg *msgs; int num_events; struct veth_cap_data local_caps; @@ -456,7 +456,7 @@ static struct kobj_type veth_port_ktype = { static inline void veth_kick_statemachine(struct veth_lpar_connection *cnx) { - schedule_work(&cnx->statemachine_wq); + schedule_delayed_work(&cnx->statemachine_wq, 0); } static void veth_take_cap(struct veth_lpar_connection *cnx, @@ -638,9 +638,11 @@ static int veth_process_caps(struct veth_lpar_connection *cnx) } /* FIXME: The gotos here are a bit dubious */ -static void veth_statemachine(void *p) +static void veth_statemachine(struct work_struct *work) { - struct veth_lpar_connection *cnx = (struct veth_lpar_connection *)p; + struct veth_lpar_connection *cnx = + container_of(work, struct veth_lpar_connection, + statemachine_wq.work); int rlp = cnx->remote_lp; int rc; @@ -827,7 +829,7 @@ static int veth_init_connection(u8 rlp) cnx->remote_lp = rlp; spin_lock_init(&cnx->lock); - INIT_WORK(&cnx->statemachine_wq, veth_statemachine, cnx); + INIT_DELAYED_WORK(&cnx->statemachine_wq, veth_statemachine); init_timer(&cnx->ack_timer); cnx->ack_timer.function = veth_timed_ack; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 7b127212e62..e628126c9c4 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -106,7 +106,7 @@ static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter); static void ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter); void ixgb_set_ethtool_ops(struct net_device *netdev); static void ixgb_tx_timeout(struct net_device *dev); -static void ixgb_tx_timeout_task(struct net_device *dev); +static void ixgb_tx_timeout_task(struct work_struct *work); static void ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); static void ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); @@ -489,8 +489,7 @@ ixgb_probe(struct pci_dev *pdev, adapter->watchdog_timer.function = &ixgb_watchdog; adapter->watchdog_timer.data = (unsigned long)adapter; - INIT_WORK(&adapter->tx_timeout_task, - (void (*)(void *))ixgb_tx_timeout_task, netdev); + INIT_WORK(&adapter->tx_timeout_task, ixgb_tx_timeout_task); strcpy(netdev->name, "eth%d"); if((err = register_netdev(netdev))) @@ -1493,9 +1492,10 @@ ixgb_tx_timeout(struct net_device *netdev) } static void -ixgb_tx_timeout_task(struct net_device *netdev) +ixgb_tx_timeout_task(struct work_struct *work) { - struct ixgb_adapter *adapter = netdev_priv(netdev); + struct ixgb_adapter *adapter = + container_of(work, struct ixgb_adapter, tx_timeout_task); adapter->tx_timeout_count++; ixgb_down(adapter, TRUE); diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 4256c13c73c..a3843320dbe 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -368,7 +368,7 @@ static void cleanup_card(struct net_device *dev) kfree(lp); } -void cleanup_module(void) +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 5795ee11620..0a08d0c4e7b 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -440,7 +440,7 @@ static void cleanup_card(struct net_device *dev) iounmap(ei_status.mem); } -void cleanup_module(void) +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 9997081c6da..c41ae4286ee 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -277,9 +277,11 @@ static void mv643xx_eth_tx_timeout(struct net_device *dev) * * Actual routine to reset the adapter when a timeout on Tx has occurred */ -static void mv643xx_eth_tx_timeout_task(struct net_device *dev) +static void mv643xx_eth_tx_timeout_task(struct work_struct *ugly) { - struct mv643xx_private *mp = netdev_priv(dev); + struct mv643xx_private *mp = container_of(ugly, struct mv643xx_private, + tx_timeout_task); + struct net_device *dev = mp->mii.dev; /* yuck */ if (!netif_running(dev)) return; @@ -1098,7 +1100,7 @@ static void eth_tx_fill_frag_descs(struct mv643xx_private *mp, ETH_TX_ENABLE_INTERRUPT; mp->tx_skb[tx_index] = skb; } else - mp->tx_skb[tx_index] = 0; + mp->tx_skb[tx_index] = NULL; desc = &mp->p_tx_desc_area[tx_index]; desc->l4i_chk = 0; @@ -1134,7 +1136,7 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, eth_tx_fill_frag_descs(mp, skb); length = skb_headlen(skb); - mp->tx_skb[tx_index] = 0; + mp->tx_skb[tx_index] = NULL; } else { cmd_sts |= ETH_ZERO_PADDING | ETH_TX_LAST_DESC | @@ -1360,8 +1362,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) #endif /* Configure the timeout task */ - INIT_WORK(&mp->tx_timeout_task, - (void (*)(void *))mv643xx_eth_tx_timeout_task, dev); + INIT_WORK(&mp->tx_timeout_task, mv643xx_eth_tx_timeout_task); spin_lock_init(&mp->lock); diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 56a82d8ee8f..e246d00bba6 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -184,7 +184,7 @@ static int m147lance_close(struct net_device *dev) MODULE_LICENSE("GPL"); static struct net_device *dev_mvme147_lance; -int init_module(void) +int __init init_module(void) { dev_mvme147_lance = mvme147lance_probe(-1); if (IS_ERR(dev_mvme147_lance)) @@ -192,7 +192,7 @@ int init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { struct m147lance_private *lp = dev_mvme147_lance->priv; unregister_netdev(dev_mvme147_lance); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 36350e6db1c..81f127a78af 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -89,7 +89,7 @@ MODULE_LICENSE("Dual BSD/GPL"); #define MYRI10GE_EEPROM_STRINGS_SIZE 256 #define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2) -#define MYRI10GE_NO_CONFIRM_DATA 0xffffffff +#define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff) #define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff struct myri10ge_rx_buffer_state { @@ -156,8 +156,8 @@ struct myri10ge_priv { int sram_size; unsigned long board_span; unsigned long iomem_base; - u32 __iomem *irq_claim; - u32 __iomem *irq_deassert; + __be32 __iomem *irq_claim; + __be32 __iomem *irq_deassert; char *mac_addr_string; struct mcp_cmd_response *cmd; dma_addr_t cmd_bus; @@ -165,10 +165,10 @@ struct myri10ge_priv { dma_addr_t fw_stats_bus; struct pci_dev *pdev; int msi_enabled; - unsigned int link_state; + __be32 link_state; unsigned int rdma_tags_available; int intr_coal_delay; - u32 __iomem *intr_coal_delay_ptr; + __be32 __iomem *intr_coal_delay_ptr; int mtrr; int wake_queue; int stop_queue; @@ -273,6 +273,11 @@ MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)"); #define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8) +static inline void put_be32(__be32 val, __be32 __iomem *p) +{ + __raw_writel((__force __u32)val, (__force void __iomem *)p); +} + static int myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, struct myri10ge_cmd *data, int atomic) @@ -296,7 +301,7 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, buf->response_addr.low = htonl(dma_low); buf->response_addr.high = htonl(dma_high); - response->result = MYRI10GE_NO_RESPONSE_RESULT; + response->result = htonl(MYRI10GE_NO_RESPONSE_RESULT); mb(); myri10ge_pio_copy(cmd_addr, buf, sizeof(*buf)); @@ -311,14 +316,14 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, * (1ms will be enough for those commands) */ for (sleep_total = 0; sleep_total < 1000 - && response->result == MYRI10GE_NO_RESPONSE_RESULT; + && response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT); sleep_total += 10) udelay(10); } else { /* use msleep for most command */ for (sleep_total = 0; sleep_total < 15 - && response->result == MYRI10GE_NO_RESPONSE_RESULT; + && response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT); sleep_total++) msleep(1); } @@ -393,7 +398,7 @@ abort: static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable) { char __iomem *submit; - u32 buf[16]; + __be32 buf[16]; u32 dma_low, dma_high; int i; @@ -410,7 +415,7 @@ static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable) buf[0] = htonl(dma_high); /* confirm addr MSW */ buf[1] = htonl(dma_low); /* confirm addr LSW */ - buf[2] = htonl(MYRI10GE_NO_CONFIRM_DATA); /* confirm data */ + buf[2] = MYRI10GE_NO_CONFIRM_DATA; /* confirm data */ buf[3] = htonl(dma_high); /* dummy addr MSW */ buf[4] = htonl(dma_low); /* dummy addr LSW */ buf[5] = htonl(enable); /* enable? */ @@ -479,7 +484,7 @@ static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size) } /* check id */ - hdr_offset = ntohl(*(u32 *) (fw->data + MCP_HEADER_PTR_OFFSET)); + hdr_offset = ntohl(*(__be32 *) (fw->data + MCP_HEADER_PTR_OFFSET)); if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->size) { dev_err(dev, "Bad firmware file\n"); status = -EINVAL; @@ -550,7 +555,7 @@ static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp) static int myri10ge_load_firmware(struct myri10ge_priv *mgp) { char __iomem *submit; - u32 buf[16]; + __be32 buf[16]; u32 dma_low, dma_high, size; int status, i; @@ -600,7 +605,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp) buf[0] = htonl(dma_high); /* confirm addr MSW */ buf[1] = htonl(dma_low); /* confirm addr LSW */ - buf[2] = htonl(MYRI10GE_NO_CONFIRM_DATA); /* confirm data */ + buf[2] = MYRI10GE_NO_CONFIRM_DATA; /* confirm data */ /* FIX: All newest firmware should un-protect the bottom of * the sram before handoff. However, the very first interfaces @@ -705,21 +710,21 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0); - mgp->irq_claim = (__iomem u32 *) (mgp->sram + cmd.data0); + mgp->irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0); if (!mgp->msi_enabled) { status |= myri10ge_send_cmd (mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd, 0); - mgp->irq_deassert = (__iomem u32 *) (mgp->sram + cmd.data0); + mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0); } status |= myri10ge_send_cmd (mgp, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd, 0); - mgp->intr_coal_delay_ptr = (__iomem u32 *) (mgp->sram + cmd.data0); + mgp->intr_coal_delay_ptr = (__iomem __be32 *) (mgp->sram + cmd.data0); if (status != 0) { dev_err(&mgp->pdev->dev, "failed set interrupt parameters\n"); return status; } - __raw_writel(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); + put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); /* Run a small DMA test. * The magic multipliers to the length tell the firmware @@ -786,14 +791,16 @@ static inline void myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst, struct mcp_kreq_ether_recv *src) { - u32 low; + __be32 low; low = src->addr_low; - src->addr_low = DMA_32BIT_MASK; - myri10ge_pio_copy(dst, src, 8 * sizeof(*src)); + src->addr_low = htonl(DMA_32BIT_MASK); + myri10ge_pio_copy(dst, src, 4 * sizeof(*src)); + mb(); + myri10ge_pio_copy(dst + 4, src + 4, 4 * sizeof(*src)); mb(); src->addr_low = low; - __raw_writel(low, &dst->addr_low); + put_be32(low, &dst->addr_low); mb(); } @@ -939,11 +946,11 @@ done: return retval; } -static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, u16 hw_csum) +static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, __wsum hw_csum) { struct vlan_hdr *vh = (struct vlan_hdr *)(skb->data); - if ((skb->protocol == ntohs(ETH_P_8021Q)) && + if ((skb->protocol == htons(ETH_P_8021Q)) && (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) || vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) { skb->csum = hw_csum; @@ -953,7 +960,7 @@ static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, u16 hw_csum) static inline unsigned long myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, - int bytes, int len, int csum) + int bytes, int len, __wsum csum) { dma_addr_t bus; struct sk_buff *skb; @@ -986,12 +993,12 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, skb->protocol = eth_type_trans(skb, mgp->dev); if (mgp->csum_flag) { - if ((skb->protocol == ntohs(ETH_P_IP)) || - (skb->protocol == ntohs(ETH_P_IPV6))) { - skb->csum = ntohs((u16) csum); + if ((skb->protocol == htons(ETH_P_IP)) || + (skb->protocol == htons(ETH_P_IPV6))) { + skb->csum = csum; skb->ip_summed = CHECKSUM_COMPLETE; } else - myri10ge_vlan_ip_csum(skb, ntohs((u16) csum)); + myri10ge_vlan_ip_csum(skb, csum); } netif_receive_skb(skb); @@ -1060,12 +1067,12 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit) int idx = rx_done->idx; int cnt = rx_done->cnt; u16 length; - u16 checksum; + __wsum checksum; while (rx_done->entry[idx].length != 0 && *limit != 0) { length = ntohs(rx_done->entry[idx].length); rx_done->entry[idx].length = 0; - checksum = ntohs(rx_done->entry[idx].checksum); + checksum = csum_unfold(rx_done->entry[idx].checksum); if (length <= mgp->small_bytes) rx_ok = myri10ge_rx_done(mgp, &mgp->rx_small, mgp->small_bytes, @@ -1142,7 +1149,7 @@ static int myri10ge_poll(struct net_device *netdev, int *budget) if (rx_done->entry[rx_done->idx].length == 0 || !netif_running(netdev)) { netif_rx_complete(netdev); - __raw_writel(htonl(3), mgp->irq_claim); + put_be32(htonl(3), mgp->irq_claim); return 0; } return 1; @@ -1166,7 +1173,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) netif_rx_schedule(mgp->dev); if (!mgp->msi_enabled) { - __raw_writel(0, mgp->irq_deassert); + put_be32(0, mgp->irq_deassert); if (!myri10ge_deassert_wait) stats->valid = 0; mb(); @@ -1195,7 +1202,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) myri10ge_check_statblock(mgp); - __raw_writel(htonl(3), mgp->irq_claim + 1); + put_be32(htonl(3), mgp->irq_claim + 1); return (IRQ_HANDLED); } @@ -1233,7 +1240,7 @@ myri10ge_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal) struct myri10ge_priv *mgp = netdev_priv(netdev); mgp->intr_coal_delay = coal->rx_coalesce_usecs; - __raw_writel(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); + put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); return 0; } @@ -1748,7 +1755,7 @@ static int myri10ge_open(struct net_device *dev) goto abort_with_rings; } - mgp->link_state = -1; + mgp->link_state = htonl(~0U); mgp->rdma_tags_available = 15; netif_poll_enable(mgp->dev); /* must happen prior to any irq */ @@ -1876,7 +1883,7 @@ myri10ge_submit_req(struct myri10ge_tx_buf *tx, struct mcp_kreq_ether_send *src, /* re-write the last 32-bits with the valid flags */ src->flags = last_flags; - __raw_writel(*((u32 *) src + 3), (u32 __iomem *) dst + 3); + put_be32(*((__be32 *) src + 3), (__be32 __iomem *) dst + 3); tx->req += cnt; mb(); } @@ -1919,7 +1926,8 @@ static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev) struct myri10ge_tx_buf *tx = &mgp->tx; struct skb_frag_struct *frag; dma_addr_t bus; - u32 low, high_swapped; + u32 low; + __be32 high_swapped; unsigned int len; int idx, last_idx, avail, frag_cnt, frag_idx, count, mss, max_segments; u16 pseudo_hdr_offset, cksum_offset; @@ -1964,7 +1972,6 @@ again: cksum_offset = 0; pseudo_hdr_offset = 0; } else { - pseudo_hdr_offset = htons(pseudo_hdr_offset); odd_flag = MXGEFW_FLAGS_ALIGN_ODD; flags |= MXGEFW_FLAGS_CKSUM; } @@ -1986,7 +1993,7 @@ again: /* for TSO, pseudo_hdr_offset holds mss. * The firmware figures out where to put * the checksum by parsing the header. */ - pseudo_hdr_offset = htons(mss); + pseudo_hdr_offset = mss; } else #endif /*NETIF_F_TSO */ /* Mark small packets, and pad out tiny packets */ @@ -2086,7 +2093,7 @@ again: #endif /* NETIF_F_TSO */ req->addr_high = high_swapped; req->addr_low = htonl(low); - req->pseudo_hdr_offset = pseudo_hdr_offset; + req->pseudo_hdr_offset = htons(pseudo_hdr_offset); req->pad = 0; /* complete solid 16-byte block; does this matter? */ req->rdma_count = 1; req->length = htons(seglen); @@ -2199,6 +2206,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev) struct myri10ge_cmd cmd; struct myri10ge_priv *mgp; struct dev_mc_list *mc_list; + __be32 data[2] = {0, 0}; int err; mgp = netdev_priv(dev); @@ -2237,10 +2245,9 @@ static void myri10ge_set_multicast_list(struct net_device *dev) /* Walk the multicast list, and add each address */ for (mc_list = dev->mc_list; mc_list != NULL; mc_list = mc_list->next) { - memcpy(&cmd.data0, &mc_list->dmi_addr, 4); - memcpy(&cmd.data1, ((char *)&mc_list->dmi_addr) + 4, 2); - cmd.data0 = htonl(cmd.data0); - cmd.data1 = htonl(cmd.data1); + memcpy(data, &mc_list->dmi_addr, 6); + cmd.data0 = ntohl(data[0]); + cmd.data1 = ntohl(data[1]); err = myri10ge_send_cmd(mgp, MXGEFW_JOIN_MULTICAST_GROUP, &cmd, 1); @@ -2615,9 +2622,10 @@ static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp) * This watchdog is used to check whether the board has suffered * from a parity error and needs to be recovered. */ -static void myri10ge_watchdog(void *arg) +static void myri10ge_watchdog(struct work_struct *work) { - struct myri10ge_priv *mgp = arg; + struct myri10ge_priv *mgp = + container_of(work, struct myri10ge_priv, watchdog_work); u32 reboot; int status; u16 cmd, vendor; @@ -2887,7 +2895,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) (unsigned long)mgp); SET_ETHTOOL_OPS(netdev, &myri10ge_ethtool_ops); - INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog, mgp); + INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog); status = register_netdev(netdev); if (status != 0) { dev_err(&pdev->dev, "register_netdev failed: %d\n", status); diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h index 9519ae7cd5e..29463b301a8 100644 --- a/drivers/net/myri10ge/myri10ge_mcp.h +++ b/drivers/net/myri10ge/myri10ge_mcp.h @@ -6,23 +6,23 @@ /* 8 Bytes */ struct mcp_dma_addr { - u32 high; - u32 low; + __be32 high; + __be32 low; }; /* 4 Bytes */ struct mcp_slot { - u16 checksum; - u16 length; + __sum16 checksum; + __be16 length; }; /* 64 Bytes */ struct mcp_cmd { - u32 cmd; - u32 data0; /* will be low portion if data > 32 bits */ + __be32 cmd; + __be32 data0; /* will be low portion if data > 32 bits */ /* 8 */ - u32 data1; /* will be high portion if data > 32 bits */ - u32 data2; /* currently unused.. */ + __be32 data1; /* will be high portion if data > 32 bits */ + __be32 data2; /* currently unused.. */ /* 16 */ struct mcp_dma_addr response_addr; /* 24 */ @@ -31,8 +31,8 @@ struct mcp_cmd { /* 8 Bytes */ struct mcp_cmd_response { - u32 data; - u32 result; + __be32 data; + __be32 result; }; /* @@ -73,10 +73,10 @@ union mcp_pso_or_cumlen { /* 16 Bytes */ struct mcp_kreq_ether_send { - u32 addr_high; - u32 addr_low; - u16 pseudo_hdr_offset; - u16 length; + __be32 addr_high; + __be32 addr_low; + __be16 pseudo_hdr_offset; + __be16 length; u8 pad; u8 rdma_count; u8 cksum_offset; /* where to start computing cksum */ @@ -85,8 +85,8 @@ struct mcp_kreq_ether_send { /* 8 Bytes */ struct mcp_kreq_ether_recv { - u32 addr_high; - u32 addr_low; + __be32 addr_high; + __be32 addr_low; }; /* Commands */ @@ -219,19 +219,19 @@ enum myri10ge_mcp_cmd_status { struct mcp_irq_data { /* add new counters at the beginning */ - u32 future_use[5]; - u32 dropped_multicast_filtered; + __be32 future_use[5]; + __be32 dropped_multicast_filtered; /* 40 Bytes */ - u32 send_done_count; - - u32 link_up; - u32 dropped_link_overflow; - u32 dropped_link_error_or_filtered; - u32 dropped_runt; - u32 dropped_overrun; - u32 dropped_no_small_buffer; - u32 dropped_no_big_buffer; - u32 rdma_tags_available; + __be32 send_done_count; + + __be32 link_up; + __be32 dropped_link_overflow; + __be32 dropped_link_error_or_filtered; + __be32 dropped_runt; + __be32 dropped_overrun; + __be32 dropped_no_small_buffer; + __be32 dropped_no_big_buffer; + __be32 rdma_tags_available; u8 tx_stopped; u8 link_down; diff --git a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h index 487f7792fd4..16a810dd6d5 100644 --- a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h +++ b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h @@ -36,7 +36,7 @@ struct mcp_gen_header { /* the first 4 fields are filled at compile time */ unsigned header_length; - unsigned mcp_type; + __be32 mcp_type; char version[128]; unsigned mcp_globals; /* pointer to mcp-type specific structure */ diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 787aa422152..a5c4199e275 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -867,7 +867,7 @@ static void cleanup_card(struct net_device *dev) release_region(dev->base_addr, NE_IO_EXTENT); } -void cleanup_module(void) +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index 5fccfea66d8..089b5bb702f 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -813,7 +813,7 @@ static void cleanup_card(struct net_device *dev) release_region(dev->base_addr, NE_IO_EXTENT); } -void cleanup_module(void) +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d925053fe59..b5410bee5f2 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1,25 +1,25 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, @@ -63,40 +63,68 @@ #include "netxen_nic_hw.h" -#define NETXEN_NIC_BUILD_NO "5" -#define _NETXEN_NIC_LINUX_MAJOR 2 +#define NETXEN_NIC_BUILD_NO "1" +#define _NETXEN_NIC_LINUX_MAJOR 3 #define _NETXEN_NIC_LINUX_MINOR 3 -#define _NETXEN_NIC_LINUX_SUBVERSION 59 -#define NETXEN_NIC_LINUX_VERSIONID "2.3.59" "-" NETXEN_NIC_BUILD_NO -#define NETXEN_NIC_FW_VERSIONID "2.3.59" +#define _NETXEN_NIC_LINUX_SUBVERSION 2 +#define NETXEN_NIC_LINUX_VERSIONID "3.3.2" "-" NETXEN_NIC_BUILD_NO +#define NETXEN_NIC_FW_VERSIONID "3.3.2" #define RCV_DESC_RINGSIZE \ (sizeof(struct rcv_desc) * adapter->max_rx_desc_count) #define STATUS_DESC_RINGSIZE \ (sizeof(struct status_desc)* adapter->max_rx_desc_count) +#define LRO_DESC_RINGSIZE \ + (sizeof(rcvDesc_t) * adapter->max_lro_rx_desc_count) #define TX_RINGSIZE \ (sizeof(struct netxen_cmd_buffer) * adapter->max_tx_desc_count) #define RCV_BUFFSIZE \ (sizeof(struct netxen_rx_buffer) * rcv_desc->max_rx_desc_count) #define find_diff_among(a,b,range) ((a)<(b)?((b)-(a)):((b)+(range)-(a))) -#define NETXEN_NETDEV_STATUS 0x1 +#define NETXEN_NETDEV_STATUS 0x1 +#define NETXEN_RCV_PRODUCER_OFFSET 0 +#define NETXEN_RCV_PEG_DB_ID 2 +#define NETXEN_HOST_DUMMY_DMA_SIZE 1024 #define ADDR_IN_WINDOW1(off) \ ((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0 +/* + * In netxen_nic_down(), we must wait for any pending callback requests into + * netxen_watchdog_task() to complete; eg otherwise the watchdog_timer could be + * reenabled right after it is deleted in netxen_nic_down(). FLUSH_SCHEDULED_WORK() + * does this synchronization. + * + * Normally, schedule_work()/flush_scheduled_work() could have worked, but + * netxen_nic_close() is invoked with kernel rtnl lock held. netif_carrier_off() + * call in netxen_nic_close() triggers a schedule_work(&linkwatch_work), and a + * subsequent call to flush_scheduled_work() in netxen_nic_down() would cause + * linkwatch_event() to be executed which also attempts to acquire the rtnl + * lock thus causing a deadlock. + */ + +#define SCHEDULE_WORK(tp) queue_work(netxen_workq, tp) +#define FLUSH_SCHEDULED_WORK() flush_workqueue(netxen_workq) +extern struct workqueue_struct *netxen_workq; /* * normalize a 64MB crb address to 32MB PCI window * To use NETXEN_CRB_NORMALIZE, window _must_ be set to 1 */ -#define NETXEN_CRB_NORMAL(reg) \ - (reg) - NETXEN_CRB_PCIX_HOST2 + NETXEN_CRB_PCIX_HOST +#define NETXEN_CRB_NORMAL(reg) \ + ((reg) - NETXEN_CRB_PCIX_HOST2 + NETXEN_CRB_PCIX_HOST) #define NETXEN_CRB_NORMALIZE(adapter, reg) \ pci_base_offset(adapter, NETXEN_CRB_NORMAL(reg)) +#define DB_NORMALIZE(adapter, off) \ + (adapter->ahw.db_base + (off)) + +#define NX_P2_C0 0x24 +#define NX_P2_C1 0x25 + #define FIRST_PAGE_GROUP_START 0 -#define FIRST_PAGE_GROUP_END 0x400000 +#define FIRST_PAGE_GROUP_END 0x100000 #define SECOND_PAGE_GROUP_START 0x4000000 #define SECOND_PAGE_GROUP_END 0x66BC000 @@ -108,11 +136,13 @@ #define SECOND_PAGE_GROUP_SIZE SECOND_PAGE_GROUP_END - SECOND_PAGE_GROUP_START #define THIRD_PAGE_GROUP_SIZE THIRD_PAGE_GROUP_END - THIRD_PAGE_GROUP_START -#define MAX_RX_BUFFER_LENGTH 2000 +#define MAX_RX_BUFFER_LENGTH 1760 #define MAX_RX_JUMBO_BUFFER_LENGTH 9046 -#define RX_DMA_MAP_LEN (MAX_RX_BUFFER_LENGTH - NET_IP_ALIGN) +#define MAX_RX_LRO_BUFFER_LENGTH ((48*1024)-512) +#define RX_DMA_MAP_LEN (MAX_RX_BUFFER_LENGTH - 2) #define RX_JUMBO_DMA_MAP_LEN \ - (MAX_RX_JUMBO_BUFFER_LENGTH - NET_IP_ALIGN) + (MAX_RX_JUMBO_BUFFER_LENGTH - 2) +#define RX_LRO_DMA_MAP_LEN (MAX_RX_LRO_BUFFER_LENGTH - 2) #define NETXEN_ROM_ROUNDUP 0x80000000ULL /* @@ -151,30 +181,38 @@ enum { /* Host writes the following to notify that it has done the init-handshake */ #define PHAN_INITIALIZE_ACK 0xf00f -#define NUM_RCV_DESC_RINGS 2 /* No of Rcv Descriptor contexts */ +#define NUM_RCV_DESC_RINGS 3 /* No of Rcv Descriptor contexts */ /* descriptor types */ #define RCV_DESC_NORMAL 0x01 #define RCV_DESC_JUMBO 0x02 +#define RCV_DESC_LRO 0x04 #define RCV_DESC_NORMAL_CTXID 0 #define RCV_DESC_JUMBO_CTXID 1 +#define RCV_DESC_LRO_CTXID 2 #define RCV_DESC_TYPE(ID) \ - ((ID == RCV_DESC_JUMBO_CTXID) ? RCV_DESC_JUMBO : RCV_DESC_NORMAL) + ((ID == RCV_DESC_JUMBO_CTXID) \ + ? RCV_DESC_JUMBO \ + : ((ID == RCV_DESC_LRO_CTXID) \ + ? RCV_DESC_LRO : \ + (RCV_DESC_NORMAL))) #define MAX_CMD_DESCRIPTORS 1024 #define MAX_RCV_DESCRIPTORS 32768 -#define MAX_JUMBO_RCV_DESCRIPTORS 1024 +#define MAX_JUMBO_RCV_DESCRIPTORS 4096 +#define MAX_LRO_RCV_DESCRIPTORS 2048 #define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS #define MAX_JUMBO_RCV_DESC MAX_JUMBO_RCV_DESCRIPTORS #define MAX_RCV_DESC MAX_RCV_DESCRIPTORS #define MAX_RCVSTATUS_DESC MAX_RCV_DESCRIPTORS -#define NUM_RCV_DESC (MAX_RCV_DESC + MAX_JUMBO_RCV_DESCRIPTORS) #define MAX_EPG_DESCRIPTORS (MAX_CMD_DESCRIPTORS * 8) - +#define NUM_RCV_DESC (MAX_RCV_DESC + MAX_JUMBO_RCV_DESCRIPTORS + \ + MAX_LRO_RCV_DESCRIPTORS) #define MIN_TX_COUNT 4096 #define MIN_RX_COUNT 4096 - +#define NETXEN_CTX_SIGNATURE 0xdee0 +#define NETXEN_RCV_PRODUCER(ringid) (ringid) #define MAX_FRAME_SIZE 0x10000 /* 64K MAX size for LSO */ #define PHAN_PEG_RCV_INITIALIZED 0xff01 @@ -186,6 +224,67 @@ enum { #define get_index_range(index,length,count) \ (((index) + (count)) & ((length) - 1)) +#define MPORT_SINGLE_FUNCTION_MODE 0x1111 + +extern unsigned long long netxen_dma_mask; + +/* + * NetXen host-peg signal message structure + * + * Bit 0-1 : peg_id => 0x2 for tx and 01 for rx + * Bit 2 : priv_id => must be 1 + * Bit 3-17 : count => for doorbell + * Bit 18-27 : ctx_id => Context id + * Bit 28-31 : opcode + */ + +typedef u32 netxen_ctx_msg; + +#define _netxen_set_bits(config_word, start, bits, val) {\ + unsigned long long mask = (((1ULL << (bits)) - 1) << (start)); \ + unsigned long long value = (val); \ + (config_word) &= ~mask; \ + (config_word) |= (((value) << (start)) & mask); \ +} + +#define netxen_set_msg_peg_id(config_word, val) \ + _netxen_set_bits(config_word, 0, 2, val) +#define netxen_set_msg_privid(config_word) \ + set_bit(2, (unsigned long*)&config_word) +#define netxen_set_msg_count(config_word, val) \ + _netxen_set_bits(config_word, 3, 15, val) +#define netxen_set_msg_ctxid(config_word, val) \ + _netxen_set_bits(config_word, 18, 10, val) +#define netxen_set_msg_opcode(config_word, val) \ + _netxen_set_bits(config_word, 28, 4, val) + +struct netxen_rcv_context { + u32 rcv_ring_addr_lo; + u32 rcv_ring_addr_hi; + u32 rcv_ring_size; + u32 rsrvd; +}; + +struct netxen_ring_ctx { + + /* one command ring */ + u64 cmd_consumer_offset; + u32 cmd_ring_addr_lo; + u32 cmd_ring_addr_hi; + u32 cmd_ring_size; + u32 rsrvd; + + /* three receive rings */ + struct netxen_rcv_context rcv_ctx[3]; + + /* one status ring */ + u32 sts_ring_addr_lo; + u32 sts_ring_addr_hi; + u32 sts_ring_size; + + u32 ctx_id; +} __attribute__ ((aligned(64))); + /* * Following data structures describe the descriptors that will be used. * Added fileds of tcpHdrSize and ipHdrSize, The driver needs to do it only when @@ -203,22 +302,32 @@ enum { #define FLAGS_IPSEC_SA_DELETE 0x08 #define FLAGS_VLAN_TAGGED 0x10 -#define CMD_DESC_TOTAL_LENGTH(cmd_desc) \ - ((cmd_desc)->length_tcp_hdr & 0x00FFFFFF) -#define CMD_DESC_TCP_HDR_OFFSET(cmd_desc) \ - (((cmd_desc)->length_tcp_hdr >> 24) & 0x0FF) -#define CMD_DESC_PORT(cmd_desc) ((cmd_desc)->port_ctxid & 0x0F) -#define CMD_DESC_CTX_ID(cmd_desc) (((cmd_desc)->port_ctxid >> 4) & 0x0F) +#define netxen_set_cmd_desc_port(cmd_desc, var) \ + ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) -#define CMD_DESC_TOTAL_LENGTH_WRT(cmd_desc, var) \ - ((cmd_desc)->length_tcp_hdr |= ((var) & 0x00FFFFFF)) -#define CMD_DESC_TCP_HDR_OFFSET_WRT(cmd_desc, var) \ - ((cmd_desc)->length_tcp_hdr |= (((var) << 24) & 0xFF000000)) -#define CMD_DESC_PORT_WRT(cmd_desc, var) \ - ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) +#define netxen_set_cmd_desc_flags(cmd_desc, val) \ + _netxen_set_bits((cmd_desc)->flags_opcode, 0, 7, val) +#define netxen_set_cmd_desc_opcode(cmd_desc, val) \ + _netxen_set_bits((cmd_desc)->flags_opcode, 7, 6, val) + +#define netxen_set_cmd_desc_num_of_buff(cmd_desc, val) \ + _netxen_set_bits((cmd_desc)->num_of_buffers_total_length, 0, 8, val); +#define netxen_set_cmd_desc_totallength(cmd_desc, val) \ + _netxen_set_bits((cmd_desc)->num_of_buffers_total_length, 8, 24, val); + +#define netxen_get_cmd_desc_opcode(cmd_desc) \ + (((cmd_desc)->flags_opcode >> 7) & 0x003F) +#define netxen_get_cmd_desc_totallength(cmd_desc) \ + (((cmd_desc)->num_of_buffers_total_length >> 8) & 0x0FFFFFF) struct cmd_desc_type0 { - u64 netxen_next; /* for fragments handled by Phantom */ + u8 tcp_hdr_offset; /* For LSO only */ + u8 ip_hdr_offset; /* For LSO only */ + /* Bit pattern: 0-6 flags, 7-12 opcode, 13-15 unused */ + u16 flags_opcode; + /* Bit pattern: 0-7 total number of segments, + 8-31 Total size of the packet */ + u32 num_of_buffers_total_length; union { struct { u32 addr_low_part2; @@ -227,13 +336,6 @@ struct cmd_desc_type0 { u64 addr_buffer2; }; - /* Bit pattern: 0-23 total length, 24-32 tcp header offset */ - u32 length_tcp_hdr; - u8 ip_hdr_offset; /* For LSO only */ - u8 num_of_buffers; /* total number of segments */ - u8 flags; /* as defined above */ - u8 opcode; - u16 reference_handle; /* changed to u16 to add mss */ u16 mss; /* passed by NDIS_PACKET for LSO */ /* Bit pattern 0-3 port, 0-3 ctx id */ @@ -248,7 +350,6 @@ struct cmd_desc_type0 { }; u64 addr_buffer3; }; - union { struct { u32 addr_low_part1; @@ -270,6 +371,8 @@ struct cmd_desc_type0 { u64 addr_buffer4; }; + u64 unused; + } __attribute__ ((aligned(64))); /* Note: sizeof(rcv_desc) should always be a mutliple of 2 */ @@ -296,22 +399,49 @@ struct rcv_desc { #define NETXEN_PROT_UNKNOWN (0) /* Note: sizeof(status_desc) should always be a mutliple of 2 */ -#define STATUS_DESC_PORT(status_desc) \ - ((status_desc)->port_status_type_op & 0x0F) -#define STATUS_DESC_STATUS(status_desc) \ - (((status_desc)->port_status_type_op >> 4) & 0x0F) -#define STATUS_DESC_TYPE(status_desc) \ - (((status_desc)->port_status_type_op >> 8) & 0x0F) -#define STATUS_DESC_OPCODE(status_desc) \ - (((status_desc)->port_status_type_op >> 12) & 0x0F) + +#define netxen_get_sts_desc_lro_cnt(status_desc) \ + ((status_desc)->lro & 0x7F) +#define netxen_get_sts_desc_lro_last_frag(status_desc) \ + (((status_desc)->lro & 0x80) >> 7) + +#define netxen_get_sts_port(status_desc) \ + ((status_desc)->status_desc_data & 0x0F) +#define netxen_get_sts_status(status_desc) \ + (((status_desc)->status_desc_data >> 4) & 0x0F) +#define netxen_get_sts_type(status_desc) \ + (((status_desc)->status_desc_data >> 8) & 0x0F) +#define netxen_get_sts_totallength(status_desc) \ + (((status_desc)->status_desc_data >> 12) & 0xFFFF) +#define netxen_get_sts_refhandle(status_desc) \ + (((status_desc)->status_desc_data >> 28) & 0xFFFF) +#define netxen_get_sts_prot(status_desc) \ + (((status_desc)->status_desc_data >> 44) & 0x0F) +#define netxen_get_sts_owner(status_desc) \ + (((status_desc)->status_desc_data >> 56) & 0x03) +#define netxen_get_sts_opcode(status_desc) \ + (((status_desc)->status_desc_data >> 58) & 0x03F) + +#define netxen_clear_sts_owner(status_desc) \ + ((status_desc)->status_desc_data &= \ + ~(((unsigned long long)3) << 56 )) +#define netxen_set_sts_owner(status_desc, val) \ + ((status_desc)->status_desc_data |= \ + (((unsigned long long)((val) & 0x3)) << 56 )) struct status_desc { - /* Bit pattern: 0-3 port, 4-7 status, 8-11 type, 12-15 opcode */ - u16 port_status_type_op; - u16 total_length; /* NIC mode */ - u16 reference_handle; /* handle for the associated packet */ - /* Bit pattern: 0-1 owner, 2-5 protocol */ - u16 owner; /* Owner of the descriptor */ + /* Bit pattern: 0-3 port, 4-7 status, 8-11 type, 12-27 total_length + 28-43 reference_handle, 44-47 protocol, 48-52 unused + 53-55 desc_cnt, 56-57 owner, 58-63 opcode + */ + u64 status_desc_data; + u32 hash_value; + u8 hash_type; + u8 msg_type; + u8 unused; + /* Bit pattern: 0-6 lro_count indicates frag sequence, + 7 last_frag indicates last frag */ + u8 lro; } __attribute__ ((aligned(8))); enum { @@ -559,11 +689,12 @@ typedef enum { #define PRIMARY_START (BOOTLD_START) #define FLASH_CRBINIT_SIZE (0x4000) #define FLASH_BRDCFG_SIZE (sizeof(struct netxen_board_info)) -#define FLASH_USER_SIZE (sizeof(netxen_user_info)/sizeof(u32)) +#define FLASH_USER_SIZE (sizeof(struct netxen_user_info)/sizeof(u32)) #define FLASH_SECONDARY_SIZE (USER_START-SECONDARY_START) #define NUM_PRIMARY_SECTORS (0x20) #define NUM_CONFIG_SECTORS (1) -#define PFX "netxen: " +#define PFX "NetXen: " +extern char netxen_nic_driver_name[]; /* Note: Make sure to not call this before adapter->port is valid */ #if !defined(NETXEN_DEBUG) @@ -572,7 +703,7 @@ typedef enum { #else #define DPRINTK(klevel, fmt, args...) do { \ printk(KERN_##klevel PFX "%s: %s: " fmt, __FUNCTION__,\ - (adapter != NULL && adapter->port != NULL && \ + (adapter != NULL && \ adapter->port[0] != NULL && \ adapter->port[0]->netdev != NULL) ? \ adapter->port[0]->netdev->name : NULL, \ @@ -609,7 +740,6 @@ struct netxen_cmd_buffer { u8 frag_count; unsigned long time_stamp; u32 state; - u32 no_of_descriptors; }; /* In rx_buffer, we do not need multiple fragments as is a single buffer */ @@ -618,6 +748,9 @@ struct netxen_rx_buffer { u64 dma; u16 ref_handle; u16 state; + u32 lro_expected_frags; + u32 lro_current_frags; + u32 lro_length; }; /* Board types */ @@ -633,6 +766,8 @@ struct netxen_hardware_context { void __iomem *pci_base0; void __iomem *pci_base1; void __iomem *pci_base2; + void __iomem *db_base; + unsigned long db_len; u8 revision_id; u16 board_type; @@ -642,14 +777,13 @@ struct netxen_hardware_context { u32 qg_linksup; /* Address of cmd ring in Phantom */ struct cmd_desc_type0 *cmd_desc_head; - char *pauseaddr; struct pci_dev *cmd_desc_pdev; dma_addr_t cmd_desc_phys_addr; - dma_addr_t pause_physaddr; - struct pci_dev *pause_pdev; struct netxen_adapter *adapter; }; +#define RCV_RING_LRO RCV_DESC_LRO + #define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */ #define ETHERNET_FCS_SIZE 4 @@ -702,8 +836,13 @@ struct netxen_recv_context { }; #define NETXEN_NIC_MSI_ENABLED 0x02 +#define NETXEN_DMA_MASK 0xfffffffe +#define NETXEN_DB_MAPSIZE_BYTES 0x1000 -struct netxen_drvops; +struct netxen_dummy_dma { + void *addr; + dma_addr_t phys_addr; +}; struct netxen_adapter { struct netxen_hardware_context ahw; @@ -714,17 +853,19 @@ struct netxen_adapter { spinlock_t lock; struct work_struct watchdog_task; struct work_struct tx_timeout_task; + struct net_device *netdev; struct timer_list watchdog_timer; u32 curr_window; u32 cmd_producer; - u32 cmd_consumer; + u32 *cmd_consumer; u32 last_cmd_consumer; u32 max_tx_desc_count; u32 max_rx_desc_count; u32 max_jumbo_rx_desc_count; + u32 max_lro_rx_desc_count; /* Num of instances active on cmd buffer ring */ u32 proc_cmd_buf_counter; @@ -746,8 +887,27 @@ struct netxen_adapter { struct netxen_recv_context recv_ctx[MAX_RCV_CTX]; int is_up; - int work_done; - struct netxen_drvops *ops; + int number; + struct netxen_dummy_dma dummy_dma; + + /* Context interface shared between card and host */ + struct netxen_ring_ctx *ctx_desc; + struct pci_dev *ctx_desc_pdev; + dma_addr_t ctx_desc_phys_addr; + int (*enable_phy_interrupts) (struct netxen_adapter *, int); + int (*disable_phy_interrupts) (struct netxen_adapter *, int); + void (*handle_phy_intr) (struct netxen_adapter *); + int (*macaddr_set) (struct netxen_port *, netxen_ethernet_macaddr_t); + int (*set_mtu) (struct netxen_port *, int); + int (*set_promisc) (struct netxen_adapter *, int, + netxen_niu_prom_mode_t); + int (*unset_promisc) (struct netxen_adapter *, int, + netxen_niu_prom_mode_t); + int (*phy_read) (struct netxen_adapter *, long phy, long reg, u32 *); + int (*phy_write) (struct netxen_adapter *, long phy, long reg, u32 val); + int (*init_port) (struct netxen_adapter *, int); + void (*init_niu) (struct netxen_adapter *); + int (*stop_port) (struct netxen_adapter *, int); }; /* netxen_adapter structure */ /* Max number of xmit producer threads that can run simultaneously */ @@ -829,25 +989,6 @@ static inline void __iomem *pci_base(struct netxen_adapter *adapter, return NULL; } -struct netxen_drvops { - int (*enable_phy_interrupts) (struct netxen_adapter *, int); - int (*disable_phy_interrupts) (struct netxen_adapter *, int); - void (*handle_phy_intr) (struct netxen_adapter *); - int (*macaddr_set) (struct netxen_port *, netxen_ethernet_macaddr_t); - int (*set_mtu) (struct netxen_port *, int); - int (*set_promisc) (struct netxen_adapter *, int, - netxen_niu_prom_mode_t); - int (*unset_promisc) (struct netxen_adapter *, int, - netxen_niu_prom_mode_t); - int (*phy_read) (struct netxen_adapter *, long phy, long reg, u32 *); - int (*phy_write) (struct netxen_adapter *, long phy, long reg, u32 val); - int (*init_port) (struct netxen_adapter *, int); - void (*init_niu) (struct netxen_adapter *); - int (*stop_port) (struct netxen_adapter *, int); -}; - -extern char netxen_nic_driver_name[]; - int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter, int port); int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter, @@ -886,10 +1027,20 @@ int netxen_nic_hw_read_wx(struct netxen_adapter *adapter, u64 off, void *data, int len); int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data, int len); +int netxen_nic_hw_read_ioctl(struct netxen_adapter *adapter, u64 off, + void *data, int len); +int netxen_nic_hw_write_ioctl(struct netxen_adapter *adapter, u64 off, + void *data, int len); +int netxen_nic_pci_mem_write_ioctl(struct netxen_adapter *adapter, + u64 off, void *data, int size); +int netxen_nic_pci_mem_read_ioctl(struct netxen_adapter *adapter, + u64 off, void *data, int size); void netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off, int data); /* Functions from netxen_nic_init.c */ +void netxen_free_adapter_offload(struct netxen_adapter *adapter); +int netxen_initialize_adapter_offload(struct netxen_adapter *adapter); void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val); void netxen_load_firmware(struct netxen_adapter *adapter); int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose); @@ -921,10 +1072,12 @@ netxen_nic_do_ioctl(struct netxen_adapter *adapter, void *u_data, struct netxen_port *port); int netxen_nic_rx_has_work(struct netxen_adapter *adapter); int netxen_nic_tx_has_work(struct netxen_adapter *adapter); -void netxen_watchdog_task(unsigned long v); +void netxen_watchdog_task(struct work_struct *work); void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid); -void netxen_process_cmd_ring(unsigned long data); +void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, u32 ctx, + u32 ringid); +int netxen_process_cmd_ring(unsigned long data); u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctx, int max); void netxen_nic_set_multi(struct net_device *netdev); int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu); @@ -1018,7 +1171,6 @@ static inline void get_brd_name_by_type(u32 type, char *name) int netxen_is_flash_supported(struct netxen_adapter *adapter); int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 mac[]); - extern void netxen_change_ringparam(struct netxen_adapter *adapter); extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 9a914aeba5b..2ab4885cc95 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -1,25 +1,25 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, @@ -118,7 +118,7 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) u32 fw_minor = 0; u32 fw_build = 0; - strncpy(drvinfo->driver, "netxen_nic", 32); + strncpy(drvinfo->driver, netxen_nic_driver_name, 32); strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32); fw_major = readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_MAJOR)); @@ -210,7 +210,6 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) printk(KERN_ERR "netxen-nic: Unsupported board model %d\n", (netxen_brdtype_t) boardinfo->board_type); return -EIO; - } return 0; @@ -226,18 +225,18 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) /* read which mode */ if (adapter->ahw.board_type == NETXEN_NIC_GBE) { /* autonegotiation */ - if (adapter->ops->phy_write - && adapter->ops->phy_write(adapter, port->portnum, - NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, - (__le32) ecmd->autoneg) != 0) + if (adapter->phy_write + && adapter->phy_write(adapter, port->portnum, + NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, + (__le32) ecmd->autoneg) != 0) return -EIO; else port->link_autoneg = ecmd->autoneg; - if (adapter->ops->phy_read - && adapter->ops->phy_read(adapter, port->portnum, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - &status) != 0) + if (adapter->phy_read + && adapter->phy_read(adapter, port->portnum, + NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + &status) != 0) return -EIO; /* speed */ @@ -257,10 +256,10 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) netxen_clear_phy_duplex(status); if (ecmd->duplex == DUPLEX_FULL) netxen_set_phy_duplex(status); - if (adapter->ops->phy_write - && adapter->ops->phy_write(adapter, port->portnum, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - *((int *)&status)) != 0) + if (adapter->phy_write + && adapter->phy_write(adapter, port->portnum, + NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + *((int *)&status)) != 0) return -EIO; else { port->link_speed = ecmd->speed; @@ -422,10 +421,10 @@ static u32 netxen_nic_get_link(struct net_device *dev) /* read which mode */ if (adapter->ahw.board_type == NETXEN_NIC_GBE) { - if (adapter->ops->phy_read - && adapter->ops->phy_read(adapter, port->portnum, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - &status) != 0) + if (adapter->phy_read + && adapter->phy_read(adapter, port->portnum, + NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + &status) != 0) return -EIO; else return (netxen_get_phy_link(status)); @@ -460,20 +459,22 @@ netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) { struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; - int i, j; + int i; ring->rx_pending = 0; + ring->rx_jumbo_pending = 0; for (i = 0; i < MAX_RCV_CTX; ++i) { - for (j = 0; j < NUM_RCV_DESC_RINGS; j++) - ring->rx_pending += - adapter->recv_ctx[i].rcv_desc[j].rcv_pending; + ring->rx_pending += adapter->recv_ctx[i]. + rcv_desc[RCV_DESC_NORMAL_CTXID].rcv_pending; + ring->rx_jumbo_pending += adapter->recv_ctx[i]. + rcv_desc[RCV_DESC_JUMBO_CTXID].rcv_pending; } ring->rx_max_pending = adapter->max_rx_desc_count; ring->tx_max_pending = adapter->max_tx_desc_count; + ring->rx_jumbo_max_pending = adapter->max_jumbo_rx_desc_count; ring->rx_mini_max_pending = 0; ring->rx_mini_pending = 0; - ring->rx_jumbo_max_pending = 0; ring->rx_jumbo_pending = 0; } @@ -526,10 +527,10 @@ netxen_nic_set_pauseparam(struct net_device *dev, *(u32 *) (&val)); /* set autoneg */ autoneg = pause->autoneg; - if (adapter->ops->phy_write - && adapter->ops->phy_write(adapter, port->portnum, - NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, - (__le32) autoneg) != 0) + if (adapter->phy_write + && adapter->phy_write(adapter, port->portnum, + NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, + (__le32) autoneg) != 0) return -EIO; else { port->link_autoneg = pause->autoneg; diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 72c6ec4ee2a..fe8b675f9e7 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -16,10 +16,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 105c24f0ad4..9147b6048df 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -16,10 +16,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, @@ -42,7 +42,7 @@ #define NETXEN_FLASH_BASE (BOOTLD_START) #define NETXEN_PHANTOM_MEM_BASE (NETXEN_FLASH_BASE) -#define NETXEN_MAX_MTU 8000 +#define NETXEN_MAX_MTU 8000 + NETXEN_ENET_HEADER_SIZE + NETXEN_ETH_FCS_SIZE #define NETXEN_MIN_MTU 64 #define NETXEN_ETH_FCS_SIZE 4 #define NETXEN_ENET_HEADER_SIZE 14 @@ -81,8 +81,8 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p) DPRINTK(INFO, "valid ether addr\n"); memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - if (adapter->ops->macaddr_set) - adapter->ops->macaddr_set(port, addr->sa_data); + if (adapter->macaddr_set) + adapter->macaddr_set(port, addr->sa_data); return 0; } @@ -99,17 +99,17 @@ void netxen_nic_set_multi(struct net_device *netdev) mc_ptr = netdev->mc_list; if (netdev->flags & IFF_PROMISC) { - if (adapter->ops->set_promisc) - adapter->ops->set_promisc(adapter, - port->portnum, - NETXEN_NIU_PROMISC_MODE); + if (adapter->set_promisc) + adapter->set_promisc(adapter, + port->portnum, + NETXEN_NIU_PROMISC_MODE); } else { - if (adapter->ops->unset_promisc && + if (adapter->unset_promisc && adapter->ahw.boardcfg.board_type != NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) - adapter->ops->unset_promisc(adapter, - port->portnum, - NETXEN_NIU_NON_PROMISC_MODE); + adapter->unset_promisc(adapter, + port->portnum, + NETXEN_NIU_NON_PROMISC_MODE); } if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x03); @@ -160,8 +160,8 @@ int netxen_nic_change_mtu(struct net_device *netdev, int mtu) return -EINVAL; } - if (adapter->ops->set_mtu) - adapter->ops->set_mtu(port, mtu); + if (adapter->set_mtu) + adapter->set_mtu(port, mtu); netdev->mtu = mtu; return 0; @@ -176,22 +176,18 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) struct netxen_hardware_context *hw = &adapter->ahw; u32 state = 0; void *addr; - void *pause_addr; int loops = 0, err = 0; int ctx, ring; u32 card_cmdring = 0; - struct netxen_rcv_desc_crb *rcv_desc_crb = NULL; struct netxen_recv_context *recv_ctx; struct netxen_rcv_desc_ctx *rcv_desc; - DPRINTK(INFO, "crb_base: %lx %lx", NETXEN_PCI_CRBSPACE, + DPRINTK(INFO, "crb_base: %lx %x", NETXEN_PCI_CRBSPACE, PCI_OFFSET_SECOND_RANGE(adapter, NETXEN_PCI_CRBSPACE)); - DPRINTK(INFO, "cam base: %lx %lx", NETXEN_CRB_CAM, + DPRINTK(INFO, "cam base: %lx %x", NETXEN_CRB_CAM, pci_base_offset(adapter, NETXEN_CRB_CAM)); - DPRINTK(INFO, "cam RAM: %lx %lx", NETXEN_CAM_RAM_BASE, + DPRINTK(INFO, "cam RAM: %lx %x", NETXEN_CAM_RAM_BASE, pci_base_offset(adapter, NETXEN_CAM_RAM_BASE)); - DPRINTK(INFO, "NIC base:%lx %lx\n", NIC_CRB_BASE_PORT1, - pci_base_offset(adapter, NIC_CRB_BASE_PORT1)); /* Window 1 call */ card_cmdring = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_CMDRING)); @@ -226,33 +222,42 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) DPRINTK(INFO, "Recieve Peg ready too. starting stuff\n"); addr = netxen_alloc(adapter->ahw.pdev, - sizeof(struct cmd_desc_type0) * - adapter->max_tx_desc_count, - &hw->cmd_desc_phys_addr, &hw->cmd_desc_pdev); + sizeof(struct netxen_ring_ctx) + + sizeof(uint32_t), + (dma_addr_t *) & adapter->ctx_desc_phys_addr, + &adapter->ctx_desc_pdev); + printk("ctx_desc_phys_addr: 0x%llx\n", + (u64) adapter->ctx_desc_phys_addr); if (addr == NULL) { DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); - return -ENOMEM; + err = -ENOMEM; + return err; } + memset(addr, 0, sizeof(struct netxen_ring_ctx)); + adapter->ctx_desc = (struct netxen_ring_ctx *)addr; + adapter->ctx_desc->cmd_consumer_offset = adapter->ctx_desc_phys_addr + + sizeof(struct netxen_ring_ctx); + adapter->cmd_consumer = (uint32_t *) (((char *)addr) + + sizeof(struct netxen_ring_ctx)); + + addr = pci_alloc_consistent(adapter->ahw.pdev, + sizeof(struct cmd_desc_type0) * + adapter->max_tx_desc_count, + (dma_addr_t *) & hw->cmd_desc_phys_addr); + printk("cmd_desc_phys_addr: 0x%llx\n", (u64) hw->cmd_desc_phys_addr); - pause_addr = netxen_alloc(adapter->ahw.pdev, 512, - (dma_addr_t *) & hw->pause_physaddr, - &hw->pause_pdev); - if (pause_addr == NULL) { - DPRINTK(1, ERR, "bad return from pci_alloc_consistent\n"); + if (addr == NULL) { + DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); + netxen_free_hw_resources(adapter); return -ENOMEM; } - hw->pauseaddr = (char *)pause_addr; - { - u64 *ptr = (u64 *) pause_addr; - *ptr++ = NETXEN_NIC_ZERO_PAUSE_ADDR; - *ptr++ = NETXEN_NIC_ZERO_PAUSE_ADDR; - *ptr++ = NETXEN_NIC_UNIT_PAUSE_ADDR; - *ptr++ = NETXEN_NIC_ZERO_PAUSE_ADDR; - *ptr++ = NETXEN_NIC_EPG_PAUSE_ADDR1; - *ptr++ = NETXEN_NIC_EPG_PAUSE_ADDR2; - } + adapter->ctx_desc->cmd_ring_addr_lo = + hw->cmd_desc_phys_addr & 0xffffffffUL; + adapter->ctx_desc->cmd_ring_addr_hi = + ((u64) hw->cmd_desc_phys_addr >> 32); + adapter->ctx_desc->cmd_ring_size = adapter->max_tx_desc_count; hw->cmd_desc_head = (struct cmd_desc_type0 *)addr; @@ -273,6 +278,12 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) return err; } rcv_desc->desc_head = (struct rcv_desc *)addr; + adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr_lo = + rcv_desc->phys_addr & 0xffffffffUL; + adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr_hi = + ((u64) rcv_desc->phys_addr >> 32); + adapter->ctx_desc->rcv_ctx[ring].rcv_ring_size = + rcv_desc->max_rx_desc_count; } addr = netxen_alloc(adapter->ahw.pdev, STATUS_DESC_RINGSIZE, @@ -286,47 +297,21 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) return err; } recv_ctx->rcv_status_desc_head = (struct status_desc *)addr; - for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { - rcv_desc = &recv_ctx->rcv_desc[ring]; - rcv_desc_crb = - &recv_crb_registers[ctx].rcv_desc_crb[ring]; - DPRINTK(INFO, "ring #%d crb global ring reg 0x%x\n", - ring, rcv_desc_crb->crb_globalrcv_ring); - /* Window = 1 */ - writel(lower32(rcv_desc->phys_addr), - NETXEN_CRB_NORMALIZE(adapter, - rcv_desc_crb-> - crb_globalrcv_ring)); - DPRINTK(INFO, "GLOBAL_RCV_RING ctx %d, addr 0x%x" - " val 0x%llx," - " virt %p\n", ctx, - rcv_desc_crb->crb_globalrcv_ring, - (unsigned long long)rcv_desc->phys_addr, - +rcv_desc->desc_head); - } + adapter->ctx_desc->sts_ring_addr_lo = + recv_ctx->rcv_status_desc_phys_addr & 0xffffffffUL; + adapter->ctx_desc->sts_ring_addr_hi = + ((u64) recv_ctx->rcv_status_desc_phys_addr >> 32); + adapter->ctx_desc->sts_ring_size = adapter->max_rx_desc_count; - /* Window = 1 */ - writel(lower32(recv_ctx->rcv_status_desc_phys_addr), - NETXEN_CRB_NORMALIZE(adapter, - recv_crb_registers[ctx]. - crb_rcvstatus_ring)); - DPRINTK(INFO, "RCVSTATUS_RING, ctx %d, addr 0x%x," - " val 0x%x,virt%p\n", - ctx, - recv_crb_registers[ctx].crb_rcvstatus_ring, - (unsigned long long)recv_ctx->rcv_status_desc_phys_addr, - recv_ctx->rcv_status_desc_head); } /* Window = 1 */ - writel(lower32(hw->pause_physaddr), - NETXEN_CRB_NORMALIZE(adapter, CRB_PAUSE_ADDR_LO)); - writel(upper32(hw->pause_physaddr), - NETXEN_CRB_NORMALIZE(adapter, CRB_PAUSE_ADDR_HI)); - - writel(lower32(hw->cmd_desc_phys_addr), - NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO)); - writel(upper32(hw->cmd_desc_phys_addr), - NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_HI)); + + writel(lower32(adapter->ctx_desc_phys_addr), + NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO)); + writel(upper32(adapter->ctx_desc_phys_addr), + NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI)); + writel(NETXEN_CTX_SIGNATURE, + NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG)); return err; } @@ -336,6 +321,15 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) struct netxen_rcv_desc_ctx *rcv_desc; int ctx, ring; + if (adapter->ctx_desc != NULL) { + pci_free_consistent(adapter->ctx_desc_pdev, + sizeof(struct netxen_ring_ctx) + + sizeof(uint32_t), + adapter->ctx_desc, + adapter->ctx_desc_phys_addr); + adapter->ctx_desc = NULL; + } + if (adapter->ahw.cmd_desc_head != NULL) { pci_free_consistent(adapter->ahw.cmd_desc_pdev, sizeof(struct cmd_desc_type0) * @@ -344,11 +338,9 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) adapter->ahw.cmd_desc_phys_addr); adapter->ahw.cmd_desc_head = NULL; } - if (adapter->ahw.pauseaddr != NULL) { - pci_free_consistent(adapter->ahw.pause_pdev, 512, - adapter->ahw.pauseaddr, - adapter->ahw.pause_physaddr); - adapter->ahw.pauseaddr = NULL; + /* Special handling: there are 2 ports on this board */ + if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) { + adapter->ahw.max_ports = 2; } for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { @@ -383,19 +375,22 @@ void netxen_tso_check(struct netxen_adapter *adapter, desc->total_hdr_length = sizeof(struct ethhdr) + ((skb->nh.iph)->ihl * sizeof(u32)) + ((skb->h.th)->doff * sizeof(u32)); - desc->opcode = TX_TCP_LSO; + netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO); } else if (skb->ip_summed == CHECKSUM_COMPLETE) { if (skb->nh.iph->protocol == IPPROTO_TCP) { - desc->opcode = TX_TCP_PKT; + netxen_set_cmd_desc_opcode(desc, TX_TCP_PKT); } else if (skb->nh.iph->protocol == IPPROTO_UDP) { - desc->opcode = TX_UDP_PKT; + netxen_set_cmd_desc_opcode(desc, TX_UDP_PKT); } else { return; } } adapter->stats.xmitcsummed++; - CMD_DESC_TCP_HDR_OFFSET_WRT(desc, skb->h.raw - skb->data); - desc->length_tcp_hdr = cpu_to_le32(desc->length_tcp_hdr); + desc->tcp_hdr_offset = skb->h.raw - skb->data; + netxen_set_cmd_desc_totallength(desc, + cpu_to_le32 + (netxen_get_cmd_desc_totallength + (desc))); desc->ip_hdr_offset = skb->nh.raw - skb->data; } @@ -648,7 +643,7 @@ void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val) addr = NETXEN_CRB_NORMALIZE(adapter, off); DPRINTK(INFO, "writing to base %lx offset %llx addr %p data %x\n", - pci_base(adapter, off), off, addr); + pci_base(adapter, off), off, addr, val); writel(val, addr); } @@ -660,7 +655,7 @@ int netxen_nic_reg_read(struct netxen_adapter *adapter, u64 off) addr = NETXEN_CRB_NORMALIZE(adapter, off); DPRINTK(INFO, "reading from base %lx offset %llx addr %p\n", - adapter->ahw.pci_base, off, addr); + pci_base(adapter, off), off, addr); val = readl(addr); writel(val, addr); @@ -848,8 +843,8 @@ void netxen_nic_stop_all_ports(struct netxen_adapter *adapter) for (port_nr = 0; port_nr < adapter->ahw.max_ports; port_nr++) { port = adapter->port[port_nr]; - if (adapter->ops->stop_port) - adapter->ops->stop_port(adapter, port->portnum); + if (adapter->stop_port) + adapter->stop_port(adapter, port->portnum); } } @@ -873,13 +868,13 @@ void netxen_nic_set_link_parameters(struct netxen_port *port) { struct netxen_adapter *adapter = port->adapter; __le32 status; - u16 autoneg; + __le32 autoneg; __le32 mode; netxen_nic_read_w0(adapter, NETXEN_NIU_MODE, &mode); if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */ - if (adapter->ops->phy_read - && adapter->ops-> + if (adapter->phy_read + && adapter-> phy_read(adapter, port->portnum, NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status) == 0) { @@ -909,11 +904,11 @@ void netxen_nic_set_link_parameters(struct netxen_port *port) port->link_duplex = -1; break; } - if (adapter->ops->phy_read - && adapter->ops-> + if (adapter->phy_read + && adapter-> phy_read(adapter, port->portnum, NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, - (__le32 *) & autoneg) != 0) + &autoneg) != 0) port->link_autoneg = autoneg; } else goto link_down; @@ -1008,3 +1003,291 @@ int netxen_crb_read_val(struct netxen_adapter *adapter, unsigned long off) netxen_nic_hw_read_wx(adapter, off, &data, 4); return data; } + +int netxen_nic_hw_write_ioctl(struct netxen_adapter *adapter, u64 off, + void *data, int len) +{ + void *addr; + u64 offset = off; + u8 *mem_ptr = NULL; + unsigned long mem_base; + unsigned long mem_page; + + if (ADDR_IN_WINDOW1(off)) { + addr = NETXEN_CRB_NORMALIZE(adapter, off); + if (!addr) { + mem_base = pci_resource_start(adapter->ahw.pdev, 0); + offset = NETXEN_CRB_NORMAL(off); + mem_page = offset & PAGE_MASK; + if (mem_page != ((offset + len - 1) & PAGE_MASK)) + mem_ptr = + ioremap(mem_base + mem_page, PAGE_SIZE * 2); + else + mem_ptr = + ioremap(mem_base + mem_page, PAGE_SIZE); + if (mem_ptr == 0UL) { + return 1; + } + addr = mem_ptr; + addr += offset & (PAGE_SIZE - 1); + } + } else { + addr = pci_base_offset(adapter, off); + if (!addr) { + mem_base = pci_resource_start(adapter->ahw.pdev, 0); + mem_page = off & PAGE_MASK; + if (mem_page != ((off + len - 1) & PAGE_MASK)) + mem_ptr = + ioremap(mem_base + mem_page, PAGE_SIZE * 2); + else + mem_ptr = + ioremap(mem_base + mem_page, PAGE_SIZE); + if (mem_ptr == 0UL) { + return 1; + } + addr = mem_ptr; + addr += off & (PAGE_SIZE - 1); + } + netxen_nic_pci_change_crbwindow(adapter, 0); + } + switch (len) { + case 1: + writeb(*(u8 *) data, addr); + break; + case 2: + writew(*(u16 *) data, addr); + break; + case 4: + writel(*(u32 *) data, addr); + break; + case 8: + writeq(*(u64 *) data, addr); + break; + default: + DPRINTK(INFO, + "writing data %lx to offset %llx, num words=%d\n", + *(unsigned long *)data, off, (len >> 3)); + + netxen_nic_hw_block_write64((u64 __iomem *) data, addr, + (len >> 3)); + break; + } + + if (!ADDR_IN_WINDOW1(off)) + netxen_nic_pci_change_crbwindow(adapter, 1); + if (mem_ptr) + iounmap(mem_ptr); + return 0; +} + +int netxen_nic_hw_read_ioctl(struct netxen_adapter *adapter, u64 off, + void *data, int len) +{ + void *addr; + u64 offset; + u8 *mem_ptr = NULL; + unsigned long mem_base; + unsigned long mem_page; + + if (ADDR_IN_WINDOW1(off)) { + addr = NETXEN_CRB_NORMALIZE(adapter, off); + if (!addr) { + mem_base = pci_resource_start(adapter->ahw.pdev, 0); + offset = NETXEN_CRB_NORMAL(off); + mem_page = offset & PAGE_MASK; + if (mem_page != ((offset + len - 1) & PAGE_MASK)) + mem_ptr = + ioremap(mem_base + mem_page, PAGE_SIZE * 2); + else + mem_ptr = + ioremap(mem_base + mem_page, PAGE_SIZE); + if (mem_ptr == 0UL) { + *(u8 *) data = 0; + return 1; + } + addr = mem_ptr; + addr += offset & (PAGE_SIZE - 1); + } + } else { + addr = pci_base_offset(adapter, off); + if (!addr) { + mem_base = pci_resource_start(adapter->ahw.pdev, 0); + mem_page = off & PAGE_MASK; + if (mem_page != ((off + len - 1) & PAGE_MASK)) + mem_ptr = + ioremap(mem_base + mem_page, PAGE_SIZE * 2); + else + mem_ptr = + ioremap(mem_base + mem_page, PAGE_SIZE); + if (mem_ptr == 0UL) + return 1; + addr = mem_ptr; + addr += off & (PAGE_SIZE - 1); + } + netxen_nic_pci_change_crbwindow(adapter, 0); + } + switch (len) { + case 1: + *(u8 *) data = readb(addr); + break; + case 2: + *(u16 *) data = readw(addr); + break; + case 4: + *(u32 *) data = readl(addr); + break; + case 8: + *(u64 *) data = readq(addr); + break; + default: + netxen_nic_hw_block_read64((u64 __iomem *) data, addr, + (len >> 3)); + break; + } + if (!ADDR_IN_WINDOW1(off)) + netxen_nic_pci_change_crbwindow(adapter, 1); + if (mem_ptr) + iounmap(mem_ptr); + return 0; +} + +int netxen_nic_pci_mem_write_ioctl(struct netxen_adapter *adapter, u64 off, + void *data, int size) +{ + void *addr; + int ret = 0; + u8 *mem_ptr = NULL; + unsigned long mem_base; + unsigned long mem_page; + + if (data == NULL || off > (128 * 1024 * 1024)) { + printk(KERN_ERR "%s: data: %p off:%llx\n", + netxen_nic_driver_name, data, off); + return 1; + } + off = netxen_nic_pci_set_window(adapter, off); + /* Corner case : Malicious user tried to break the driver by reading + last few bytes in ranges and tries to read further addresses. + */ + if (!pci_base(adapter, off + size - 1) && pci_base(adapter, off)) { + printk(KERN_ERR "%s: Invalid access to memory address range" + " 0x%llx - 0x%llx\n", netxen_nic_driver_name, off, + off + size); + return 1; + } + addr = pci_base_offset(adapter, off); + DPRINTK(INFO, "writing data %llx to offset %llx\n", + *(unsigned long long *)data, off); + if (!addr) { + mem_base = pci_resource_start(adapter->ahw.pdev, 0); + mem_page = off & PAGE_MASK; + /* Map two pages whenever user tries to access addresses in two + consecutive pages. + */ + if (mem_page != ((off + size - 1) & PAGE_MASK)) + mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); + else + mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); + if (mem_ptr == 0UL) { + return 1; + } + addr = mem_ptr; + addr += off & (PAGE_SIZE - 1); + } + switch (size) { + case 1: + writeb(*(u8 *) data, addr); + break; + case 2: + writew(*(u16 *) data, addr); + break; + case 4: + writel(*(u32 *) data, addr); + break; + case 8: + writeq(*(u64 *) data, addr); + break; + default: + DPRINTK(INFO, + "writing data %lx to offset %llx, num words=%d\n", + *(unsigned long *)data, off, (size >> 3)); + + netxen_nic_hw_block_write64((u64 __iomem *) data, addr, + (size >> 3)); + break; + } + + if (mem_ptr) + iounmap(mem_ptr); + DPRINTK(INFO, "wrote %llx\n", *(unsigned long long *)data); + + return ret; +} + +int netxen_nic_pci_mem_read_ioctl(struct netxen_adapter *adapter, + u64 off, void *data, int size) +{ + void *addr; + int ret = 0; + u8 *mem_ptr = NULL; + unsigned long mem_base; + unsigned long mem_page; + + if (data == NULL || off > (128 * 1024 * 1024)) { + printk(KERN_ERR "%s: data: %p off:%llx\n", + netxen_nic_driver_name, data, off); + return 1; + } + off = netxen_nic_pci_set_window(adapter, off); + /* Corner case : Malicious user tried to break the driver by reading + last few bytes in ranges and tries to read further addresses. + */ + if (!pci_base(adapter, off + size - 1) && pci_base(adapter, off)) { + printk(KERN_ERR "%s: Invalid access to memory address range" + " 0x%llx - 0x%llx\n", netxen_nic_driver_name, off, + off + size); + return 1; + } + addr = pci_base_offset(adapter, off); + if (!addr) { + mem_base = pci_resource_start(adapter->ahw.pdev, 0); + mem_page = off & PAGE_MASK; + /* Map two pages whenever user tries to access addresses in two + consecutive pages. + */ + if (mem_page != ((off + size - 1) & PAGE_MASK)) + mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); + else + mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); + if (mem_ptr == 0UL) { + *(u8 *) data = 0; + return 1; + } + addr = mem_ptr; + addr += off & (PAGE_SIZE - 1); + } + switch (size) { + case 1: + *(u8 *) data = readb(addr); + break; + case 2: + *(u16 *) data = readw(addr); + break; + case 4: + *(u32 *) data = readl(addr); + break; + case 8: + *(u64 *) data = readq(addr); + break; + default: + netxen_nic_hw_block_read64((u64 __iomem *) data, addr, + (size >> 3)); + break; + } + + if (mem_ptr) + iounmap(mem_ptr); + DPRINTK(INFO, "read %llx\n", *(unsigned long long *)data); + + return ret; +} diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index 201a636b7ab..0685633a9c1 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -16,10 +16,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, @@ -83,8 +83,8 @@ struct netxen_adapter; #define NETXEN_PCI_MAPSIZE_BYTES (NETXEN_PCI_MAPSIZE << 20) #define NETXEN_NIC_LOCKED_READ_REG(X, Y) \ - addr = pci_base_offset(adapter, (X)); \ - *(u32 *)Y = readl(addr); + addr = pci_base_offset(adapter, X); \ + *(u32 *)Y = readl((void __iomem*) addr); struct netxen_port; void netxen_nic_set_link_parameters(struct netxen_port *port); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 0dca029bc3e..290145ec08e 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1,25 +1,25 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, @@ -137,6 +137,8 @@ int netxen_init_firmware(struct netxen_adapter *adapter) return err; } /* Window 1 call */ + writel(MPORT_SINGLE_FUNCTION_MODE, + NETXEN_CRB_NORMALIZE(adapter, CRB_MPORT_MODE)); writel(PHAN_INITIALIZE_ACK, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); @@ -184,15 +186,12 @@ void netxen_initialize_adapter_sw(struct netxen_adapter *adapter) for (i = 0; i < num_rx_bufs; i++) { rx_buf->ref_handle = i; rx_buf->state = NETXEN_BUFFER_FREE; - DPRINTK(INFO, "Rx buf:ctx%d i(%d) rx_buf:" "%p\n", ctxid, i, rx_buf); rx_buf++; } } } - DPRINTK(INFO, "initialized buffers for %s and %s\n", - "adapter->free_cmd_buf_list", "adapter->free_rxbuf"); } void netxen_initialize_adapter_hw(struct netxen_adapter *adapter) @@ -212,37 +211,36 @@ void netxen_initialize_adapter_hw(struct netxen_adapter *adapter) void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) { - struct netxen_drvops *ops = adapter->ops; switch (adapter->ahw.board_type) { case NETXEN_NIC_GBE: - ops->enable_phy_interrupts = + adapter->enable_phy_interrupts = netxen_niu_gbe_enable_phy_interrupts; - ops->disable_phy_interrupts = + adapter->disable_phy_interrupts = netxen_niu_gbe_disable_phy_interrupts; - ops->handle_phy_intr = netxen_nic_gbe_handle_phy_intr; - ops->macaddr_set = netxen_niu_macaddr_set; - ops->set_mtu = netxen_nic_set_mtu_gb; - ops->set_promisc = netxen_niu_set_promiscuous_mode; - ops->unset_promisc = netxen_niu_set_promiscuous_mode; - ops->phy_read = netxen_niu_gbe_phy_read; - ops->phy_write = netxen_niu_gbe_phy_write; - ops->init_port = netxen_niu_gbe_init_port; - ops->init_niu = netxen_nic_init_niu_gb; - ops->stop_port = netxen_niu_disable_gbe_port; + adapter->handle_phy_intr = netxen_nic_gbe_handle_phy_intr; + adapter->macaddr_set = netxen_niu_macaddr_set; + adapter->set_mtu = netxen_nic_set_mtu_gb; + adapter->set_promisc = netxen_niu_set_promiscuous_mode; + adapter->unset_promisc = netxen_niu_set_promiscuous_mode; + adapter->phy_read = netxen_niu_gbe_phy_read; + adapter->phy_write = netxen_niu_gbe_phy_write; + adapter->init_port = netxen_niu_gbe_init_port; + adapter->init_niu = netxen_nic_init_niu_gb; + adapter->stop_port = netxen_niu_disable_gbe_port; break; case NETXEN_NIC_XGBE: - ops->enable_phy_interrupts = + adapter->enable_phy_interrupts = netxen_niu_xgbe_enable_phy_interrupts; - ops->disable_phy_interrupts = + adapter->disable_phy_interrupts = netxen_niu_xgbe_disable_phy_interrupts; - ops->handle_phy_intr = netxen_nic_xgbe_handle_phy_intr; - ops->macaddr_set = netxen_niu_xg_macaddr_set; - ops->set_mtu = netxen_nic_set_mtu_xgb; - ops->init_port = netxen_niu_xg_init_port; - ops->set_promisc = netxen_niu_xg_set_promiscuous_mode; - ops->unset_promisc = netxen_niu_xg_set_promiscuous_mode; - ops->stop_port = netxen_niu_disable_xg_port; + adapter->handle_phy_intr = netxen_nic_xgbe_handle_phy_intr; + adapter->macaddr_set = netxen_niu_xg_macaddr_set; + adapter->set_mtu = netxen_nic_set_mtu_xgb; + adapter->init_port = netxen_niu_xg_init_port; + adapter->set_promisc = netxen_niu_xg_set_promiscuous_mode; + adapter->unset_promisc = netxen_niu_xg_set_promiscuous_mode; + adapter->stop_port = netxen_niu_disable_xg_port; break; default: @@ -383,8 +381,8 @@ int netxen_rom_wip_poll(struct netxen_adapter *adapter) return 0; } -static inline int do_rom_fast_write(struct netxen_adapter *adapter, - int addr, int data) +static inline int do_rom_fast_write(struct netxen_adapter *adapter, int addr, + int data) { if (netxen_rom_wren(adapter)) { return -1; @@ -622,6 +620,43 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) return 0; } +int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) +{ + uint64_t addr; + uint32_t hi; + uint32_t lo; + + adapter->dummy_dma.addr = + pci_alloc_consistent(adapter->ahw.pdev, + NETXEN_HOST_DUMMY_DMA_SIZE, + &adapter->dummy_dma.phys_addr); + if (adapter->dummy_dma.addr == NULL) { + printk("%s: ERROR: Could not allocate dummy DMA memory\n", + __FUNCTION__); + return -ENOMEM; + } + + addr = (uint64_t) adapter->dummy_dma.phys_addr; + hi = (addr >> 32) & 0xffffffff; + lo = addr & 0xffffffff; + + writel(hi, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI)); + writel(lo, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO)); + + return 0; +} + +void netxen_free_adapter_offload(struct netxen_adapter *adapter) +{ + if (adapter->dummy_dma.addr) { + pci_free_consistent(adapter->ahw.pdev, + NETXEN_HOST_DUMMY_DMA_SIZE, + adapter->dummy_dma.addr, + adapter->dummy_dma.phys_addr); + adapter->dummy_dma.addr = NULL; + } +} + void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) { u32 val = 0; @@ -656,7 +691,8 @@ int netxen_nic_rx_has_work(struct netxen_adapter *adapter) desc_head = recv_ctx->rcv_status_desc_head; desc = &desc_head[consumer]; - if (((le16_to_cpu(desc->owner)) & STATUS_OWNER_HOST)) + if (((le16_to_cpu(netxen_get_sts_owner(desc))) + & STATUS_OWNER_HOST)) return 1; } @@ -710,12 +746,13 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter) return rv; } -void netxen_watchdog_task(unsigned long v) +void netxen_watchdog_task(struct work_struct *work) { int port_num; struct netxen_port *port; struct net_device *netdev; - struct netxen_adapter *adapter = (struct netxen_adapter *)v; + struct netxen_adapter *adapter = + container_of(work, struct netxen_adapter, watchdog_task); if (netxen_nic_check_temp(adapter)) return; @@ -734,8 +771,8 @@ void netxen_watchdog_task(unsigned long v) netif_wake_queue(netdev); } - if (adapter->ops->handle_phy_intr) - adapter->ops->handle_phy_intr(adapter); + if (adapter->handle_phy_intr) + adapter->handle_phy_intr(adapter); mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); } @@ -748,19 +785,19 @@ void netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, struct status_desc *desc) { - struct netxen_port *port = adapter->port[STATUS_DESC_PORT(desc)]; + struct netxen_port *port = adapter->port[netxen_get_sts_port(desc)]; struct pci_dev *pdev = port->pdev; struct net_device *netdev = port->netdev; - int index = le16_to_cpu(desc->reference_handle); + int index = le16_to_cpu(netxen_get_sts_refhandle(desc)); struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]); struct netxen_rx_buffer *buffer; struct sk_buff *skb; - u32 length = le16_to_cpu(desc->total_length); + u32 length = le16_to_cpu(netxen_get_sts_totallength(desc)); u32 desc_ctx; struct netxen_rcv_desc_ctx *rcv_desc; int ret; - desc_ctx = STATUS_DESC_TYPE(desc); + desc_ctx = netxen_get_sts_type(desc); if (unlikely(desc_ctx >= NUM_RCV_DESC_RINGS)) { printk("%s: %s Bad Rcv descriptor ring\n", netxen_nic_driver_name, netdev->name); @@ -768,20 +805,49 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, } rcv_desc = &recv_ctx->rcv_desc[desc_ctx]; + if (unlikely(index > rcv_desc->max_rx_desc_count)) { + DPRINTK(ERR, "Got a buffer index:%x Max is %x\n", + index, rcv_desc->max_rx_desc_count); + return; + } buffer = &rcv_desc->rx_buf_arr[index]; + if (desc_ctx == RCV_DESC_LRO_CTXID) { + buffer->lro_current_frags++; + if (netxen_get_sts_desc_lro_last_frag(desc)) { + buffer->lro_expected_frags = + netxen_get_sts_desc_lro_cnt(desc); + buffer->lro_length = length; + } + if (buffer->lro_current_frags != buffer->lro_expected_frags) { + if (buffer->lro_expected_frags != 0) { + printk("LRO: (refhandle:%x) recv frag." + "wait for last. flags: %x expected:%d" + "have:%d\n", index, + netxen_get_sts_desc_lro_last_frag(desc), + buffer->lro_expected_frags, + buffer->lro_current_frags); + } + return; + } + } pci_unmap_single(pdev, buffer->dma, rcv_desc->dma_size, PCI_DMA_FROMDEVICE); skb = (struct sk_buff *)buffer->skb; - if (likely(STATUS_DESC_STATUS(desc) == STATUS_CKSUM_OK)) { + if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) { port->stats.csummed++; skb->ip_summed = CHECKSUM_UNNECESSARY; - } else - skb->ip_summed = CHECKSUM_NONE; + } skb->dev = netdev; - skb_put(skb, length); + if (desc_ctx == RCV_DESC_LRO_CTXID) { + /* True length was only available on the last pkt */ + skb_put(skb, buffer->lro_length); + } else { + skb_put(skb, length); + } + skb->protocol = eth_type_trans(skb, netdev); ret = netif_receive_skb(skb); @@ -827,6 +893,8 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, adapter->stats.post_called++; buffer->skb = NULL; buffer->state = NETXEN_BUFFER_FREE; + buffer->lro_current_frags = 0; + buffer->lro_expected_frags = 0; port->stats.no_rcv++; port->stats.rxbytes += length; @@ -839,6 +907,7 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) struct status_desc *desc_head = recv_ctx->rcv_status_desc_head; struct status_desc *desc; /* used to read status desc here */ u32 consumer = recv_ctx->status_rx_consumer; + u32 producer = 0; int count = 0, ring; DPRINTK(INFO, "procesing receive\n"); @@ -850,18 +919,22 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) */ while (count < max) { desc = &desc_head[consumer]; - if (!((le16_to_cpu(desc->owner)) & STATUS_OWNER_HOST)) { - DPRINTK(ERR, "desc %p ownedby %x\n", desc, desc->owner); + if (! + (le16_to_cpu(netxen_get_sts_owner(desc)) & + STATUS_OWNER_HOST)) { + DPRINTK(ERR, "desc %p ownedby %x\n", desc, + netxen_get_sts_owner(desc)); break; } netxen_process_rcv(adapter, ctxid, desc); - desc->owner = STATUS_OWNER_PHANTOM; + netxen_clear_sts_owner(desc); + netxen_set_sts_owner(desc, STATUS_OWNER_PHANTOM); consumer = (consumer + 1) & (adapter->max_rx_desc_count - 1); count++; } if (count) { for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { - netxen_post_rx_buffers(adapter, ctxid, ring); + netxen_post_rx_buffers_nodb(adapter, ctxid, ring); } } @@ -869,6 +942,7 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) if (count) { adapter->stats.process_rcv++; recv_ctx->status_rx_consumer = consumer; + recv_ctx->status_rx_producer = producer; /* Window = 1 */ writel(consumer, @@ -881,12 +955,13 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) } /* Process Command status ring */ -void netxen_process_cmd_ring(unsigned long data) +int netxen_process_cmd_ring(unsigned long data) { u32 last_consumer; u32 consumer; struct netxen_adapter *adapter = (struct netxen_adapter *)data; - int count = 0; + int count1 = 0; + int count2 = 0; struct netxen_cmd_buffer *buffer; struct netxen_port *port; /* port #1 */ struct netxen_port *nport; @@ -895,6 +970,7 @@ void netxen_process_cmd_ring(unsigned long data) u32 i; struct sk_buff *skb = NULL; int p; + int done; spin_lock(&adapter->tx_lock); last_consumer = adapter->last_cmd_consumer; @@ -904,14 +980,13 @@ void netxen_process_cmd_ring(unsigned long data) * number as part of the descriptor. This way we will be able to get * the netdev which is associated with that device. */ - consumer = - readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_CONSUMER_OFFSET)); + consumer = *(adapter->cmd_consumer); if (last_consumer == consumer) { /* Ring is empty */ DPRINTK(INFO, "last_consumer %d == consumer %d\n", last_consumer, consumer); spin_unlock(&adapter->tx_lock); - return; + return 1; } adapter->proc_cmd_buf_counter++; @@ -922,7 +997,7 @@ void netxen_process_cmd_ring(unsigned long data) */ spin_unlock(&adapter->tx_lock); - while ((last_consumer != consumer) && (count < MAX_STATUS_HANDLE)) { + while ((last_consumer != consumer) && (count1 < MAX_STATUS_HANDLE)) { buffer = &adapter->cmd_buf_arr[last_consumer]; port = adapter->port[buffer->port]; pdev = port->pdev; @@ -948,24 +1023,25 @@ void netxen_process_cmd_ring(unsigned long data) && netif_carrier_ok(port->netdev)) && ((jiffies - port->netdev->trans_start) > port->netdev->watchdog_timeo)) { - schedule_work(&port->adapter->tx_timeout_task); + SCHEDULE_WORK(port->adapter->tx_timeout_task + + port->portnum); } last_consumer = get_next_index(last_consumer, adapter->max_tx_desc_count); - count++; + count1++; } - adapter->stats.noxmitdone += count; + adapter->stats.noxmitdone += count1; - count = 0; + count2 = 0; spin_lock(&adapter->tx_lock); if ((--adapter->proc_cmd_buf_counter) == 0) { adapter->last_cmd_consumer = last_consumer; while ((adapter->last_cmd_consumer != consumer) - && (count < MAX_STATUS_HANDLE)) { + && (count2 < MAX_STATUS_HANDLE)) { buffer = &adapter->cmd_buf_arr[adapter->last_cmd_consumer]; - count++; + count2++; if (buffer->skb) break; else @@ -974,7 +1050,7 @@ void netxen_process_cmd_ring(unsigned long data) adapter->max_tx_desc_count); } } - if (count) { + if (count1 || count2) { for (p = 0; p < adapter->ahw.max_ports; p++) { nport = adapter->port[p]; if (netif_queue_stopped(nport->netdev) @@ -984,10 +1060,30 @@ void netxen_process_cmd_ring(unsigned long data) } } } + /* + * If everything is freed up to consumer then check if the ring is full + * If the ring is full then check if more needs to be freed and + * schedule the call back again. + * + * This happens when there are 2 CPUs. One could be freeing and the + * other filling it. If the ring is full when we get out of here and + * the card has already interrupted the host then the host can miss the + * interrupt. + * + * There is still a possible race condition and the host could miss an + * interrupt. The card has to take care of this. + */ + if (adapter->last_cmd_consumer == consumer && + (((adapter->cmd_producer + 1) % + adapter->max_tx_desc_count) == adapter->last_cmd_consumer)) { + consumer = *(adapter->cmd_consumer); + } + done = (adapter->last_cmd_consumer == consumer); spin_unlock(&adapter->tx_lock); DPRINTK(INFO, "last consumer is %d in %s\n", last_consumer, __FUNCTION__); + return (done); } /* @@ -999,17 +1095,16 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) struct sk_buff *skb; struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctx]); struct netxen_rcv_desc_ctx *rcv_desc = NULL; - struct netxen_recv_crb *crbarea = &recv_crb_registers[ctx]; - struct netxen_rcv_desc_crb *rcv_desc_crb = NULL; - u32 producer; + uint producer; struct rcv_desc *pdesc; struct netxen_rx_buffer *buffer; int count = 0; int index = 0; + netxen_ctx_msg msg = 0; + dma_addr_t dma; adapter->stats.post_called++; rcv_desc = &recv_ctx->rcv_desc[ringid]; - rcv_desc_crb = &crbarea->rcv_desc_crb[ringid]; producer = rcv_desc->producer; index = rcv_desc->begin_alloc; @@ -1019,6 +1114,7 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) skb = dev_alloc_skb(rcv_desc->skb_size); if (unlikely(!skb)) { /* + * TODO * We need to schedule the posting of buffers to the pegs. */ rcv_desc->begin_alloc = index; @@ -1026,9 +1122,105 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) " allocated only %d buffers\n", count); break; } + count++; /* now there should be no failure */ pdesc = &rcv_desc->desc_head[producer]; - skb_reserve(skb, NET_IP_ALIGN); + +#if defined(XGB_DEBUG) + *(unsigned long *)(skb->head) = 0xc0debabe; + if (skb_is_nonlinear(skb)) { + printk("Allocated SKB @%p is nonlinear\n"); + } +#endif + skb_reserve(skb, 2); + /* This will be setup when we receive the + * buffer after it has been filled FSL TBD TBD + * skb->dev = netdev; + */ + dma = pci_map_single(pdev, skb->data, rcv_desc->dma_size, + PCI_DMA_FROMDEVICE); + pdesc->addr_buffer = dma; + buffer->skb = skb; + buffer->state = NETXEN_BUFFER_BUSY; + buffer->dma = dma; + /* make a rcv descriptor */ + pdesc->reference_handle = buffer->ref_handle; + pdesc->buffer_length = rcv_desc->dma_size; + DPRINTK(INFO, "done writing descripter\n"); + producer = + get_next_index(producer, rcv_desc->max_rx_desc_count); + index = get_next_index(index, rcv_desc->max_rx_desc_count); + buffer = &rcv_desc->rx_buf_arr[index]; + } + /* if we did allocate buffers, then write the count to Phantom */ + if (count) { + rcv_desc->begin_alloc = index; + rcv_desc->rcv_pending += count; + adapter->stats.lastposted = count; + adapter->stats.posted += count; + rcv_desc->producer = producer; + if (rcv_desc->rcv_free >= 32) { + rcv_desc->rcv_free = 0; + /* Window = 1 */ + writel((producer - 1) & + (rcv_desc->max_rx_desc_count - 1), + NETXEN_CRB_NORMALIZE(adapter, + recv_crb_registers[0]. + rcv_desc_crb[ringid]. + crb_rcv_producer_offset)); + /* + * Write a doorbell msg to tell phanmon of change in + * receive ring producer + */ + netxen_set_msg_peg_id(msg, NETXEN_RCV_PEG_DB_ID); + netxen_set_msg_privid(msg); + netxen_set_msg_count(msg, + ((producer - + 1) & (rcv_desc-> + max_rx_desc_count - 1))); + netxen_set_msg_ctxid(msg, 0); + netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid)); + writel(msg, + DB_NORMALIZE(adapter, + NETXEN_RCV_PRODUCER_OFFSET)); + } + } +} + +void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx, + uint32_t ringid) +{ + struct pci_dev *pdev = adapter->ahw.pdev; + struct sk_buff *skb; + struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctx]); + struct netxen_rcv_desc_ctx *rcv_desc = NULL; + u32 producer; + struct rcv_desc *pdesc; + struct netxen_rx_buffer *buffer; + int count = 0; + int index = 0; + + adapter->stats.post_called++; + rcv_desc = &recv_ctx->rcv_desc[ringid]; + + producer = rcv_desc->producer; + index = rcv_desc->begin_alloc; + buffer = &rcv_desc->rx_buf_arr[index]; + /* We can start writing rx descriptors into the phantom memory. */ + while (buffer->state == NETXEN_BUFFER_FREE) { + skb = dev_alloc_skb(rcv_desc->skb_size); + if (unlikely(!skb)) { + /* + * We need to schedule the posting of buffers to the pegs. + */ + rcv_desc->begin_alloc = index; + DPRINTK(ERR, "netxen_post_rx_buffers_nodb: " + " allocated only %d buffers\n", count); + break; + } + count++; /* now there should be no failure */ + pdesc = &rcv_desc->desc_head[producer]; + skb_reserve(skb, 2); /* * This will be setup when we receive the * buffer after it has been filled @@ -1039,6 +1231,7 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) buffer->dma = pci_map_single(pdev, skb->data, rcv_desc->dma_size, PCI_DMA_FROMDEVICE); + /* make a rcv descriptor */ pdesc->reference_handle = le16_to_cpu(buffer->ref_handle); pdesc->buffer_length = le16_to_cpu(rcv_desc->dma_size); @@ -1063,7 +1256,8 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) writel((producer - 1) & (rcv_desc->max_rx_desc_count - 1), NETXEN_CRB_NORMALIZE(adapter, - rcv_desc_crb-> + recv_crb_registers[0]. + rcv_desc_crb[ringid]. crb_rcv_producer_offset)); wmb(); } @@ -1196,8 +1390,8 @@ netxen_nic_do_ioctl(struct netxen_adapter *adapter, void *u_data, switch (data.cmd) { case netxen_nic_cmd_pci_read: - if ((retval = netxen_nic_hw_read_wx(adapter, data.off, - &(data.u), data.size))) + if ((retval = netxen_nic_hw_read_ioctl(adapter, data.off, + &(data.u), data.size))) goto error_out; if (copy_to_user ((void __user *)&(up_data->u), &(data.u), data.size)) { @@ -1210,8 +1404,35 @@ netxen_nic_do_ioctl(struct netxen_adapter *adapter, void *u_data, break; case netxen_nic_cmd_pci_write: - data.rv = netxen_nic_hw_write_wx(adapter, data.off, &(data.u), - data.size); + if ((retval = netxen_nic_hw_write_ioctl(adapter, data.off, + &(data.u), data.size))) + goto error_out; + data.rv = 0; + break; + + case netxen_nic_cmd_pci_mem_read: + if (netxen_nic_pci_mem_read_ioctl(adapter, data.off, &(data.u), + data.size)) { + DPRINTK(ERR, "Failed to read the data.\n"); + retval = -EFAULT; + goto error_out; + } + if (copy_to_user + ((void __user *)&(up_data->u), &(data.u), data.size)) { + DPRINTK(ERR, "bad copy to userland: %d\n", + (int)sizeof(data)); + retval = -EFAULT; + goto error_out; + } + data.rv = 0; + break; + + case netxen_nic_cmd_pci_mem_write: + if ((retval = netxen_nic_pci_mem_write_ioctl(adapter, data.off, + &(data.u), + data.size))) + goto error_out; + data.rv = 0; break; case netxen_nic_cmd_pci_config_read: @@ -1296,7 +1517,7 @@ netxen_nic_do_ioctl(struct netxen_adapter *adapter, void *u_data, retval = -EOPNOTSUPP; goto error_out; } - put_user(data.rv, (u16 __user *) (&(up_data->rv))); + put_user(data.rv, (&(up_data->rv))); DPRINTK(INFO, "done ioctl for %p well.\n", adapter); error_out: diff --git a/drivers/net/netxen/netxen_nic_ioctl.h b/drivers/net/netxen/netxen_nic_ioctl.h index 23e53adbf12..1221fa52755 100644 --- a/drivers/net/netxen/netxen_nic_ioctl.h +++ b/drivers/net/netxen/netxen_nic_ioctl.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -16,10 +16,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, @@ -36,7 +36,7 @@ #define NETXEN_NIC_CMD (NETXEN_CMD_START + 1) #define NETXEN_NIC_NAME (NETXEN_CMD_START + 2) #define NETXEN_NIC_NAME_LEN 16 -#define NETXEN_NIC_NAME_RSP "NETXEN" +#define NETXEN_NIC_NAME_RSP "NETXEN-UNM" typedef enum { netxen_nic_cmd_none = 0, diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c index ae180fee800..1b45f50fa6a 100644 --- a/drivers/net/netxen/netxen_nic_isr.c +++ b/drivers/net/netxen/netxen_nic_isr.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -16,10 +16,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, @@ -68,8 +68,7 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno, u32 link) { - struct netxen_port *pport = adapter->port[portno]; - struct net_device *netdev = pport->netdev; + struct net_device *netdev = (adapter->port[portno])->netdev; if (link) netif_carrier_on(netdev); @@ -84,46 +83,41 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno, struct netxen_port *port; /* This should clear the interrupt source */ - if (adapter->ops->phy_read) - adapter->ops->phy_read(adapter, portno, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, - &int_src); + if (adapter->phy_read) + adapter->phy_read(adapter, portno, + NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, + &int_src); if (int_src == 0) { DPRINTK(INFO, "No phy interrupts for port #%d\n", portno); return; } - if (adapter->ops->disable_phy_interrupts) - adapter->ops->disable_phy_interrupts(adapter, portno); + if (adapter->disable_phy_interrupts) + adapter->disable_phy_interrupts(adapter, portno); port = adapter->port[portno]; if (netxen_get_phy_int_jabber(int_src)) - DPRINTK(INFO, "NetXen: %s Jabber interrupt \n", - port->netdev->name); + DPRINTK(INFO, "Jabber interrupt \n"); if (netxen_get_phy_int_polarity_changed(int_src)) - DPRINTK(INFO, "NetXen: %s POLARITY CHANGED int \n", - port->netdev->name); + DPRINTK(INFO, "POLARITY CHANGED int \n"); if (netxen_get_phy_int_energy_detect(int_src)) - DPRINTK(INFO, "NetXen: %s ENERGY DETECT INT \n", - port->netdev->name); + DPRINTK(INFO, "ENERGY DETECT INT \n"); if (netxen_get_phy_int_downshift(int_src)) - DPRINTK(INFO, "NetXen: %s DOWNSHIFT INT \n", - port->netdev->name); + DPRINTK(INFO, "DOWNSHIFT INT \n"); /* write it down later.. */ if ((netxen_get_phy_int_speed_changed(int_src)) || (netxen_get_phy_int_link_status_changed(int_src))) { __le32 status; - DPRINTK(INFO, "NetXen: %s SPEED CHANGED OR" - " LINK STATUS CHANGED \n", port->netdev->name); + DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n"); - if (adapter->ops->phy_read - && adapter->ops->phy_read(adapter, portno, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - &status) == 0) { + if (adapter->phy_read + && adapter->phy_read(adapter, portno, + NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + &status) == 0) { if (netxen_get_phy_int_link_status_changed(int_src)) { if (netxen_get_phy_link(status)) { netxen_niu_gbe_init_port(adapter, @@ -143,8 +137,8 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno, } } } - if (adapter->ops->enable_phy_interrupts) - adapter->ops->enable_phy_interrupts(adapter, portno); + if (adapter->enable_phy_interrupts) + adapter->enable_phy_interrupts(adapter, portno); } void netxen_nic_isr_other(struct netxen_adapter *adapter) @@ -159,8 +153,7 @@ void netxen_nic_isr_other(struct netxen_adapter *adapter) qg_linksup = adapter->ahw.qg_linksup; adapter->ahw.qg_linksup = val; - DPRINTK(1, INFO, "%s: link update 0x%08x\n", netxen_nic_driver_name, - val); + DPRINTK(INFO, "link update 0x%08x\n", val); for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) { linkup = val & 1; if (linkup != (qg_linksup & 1)) { diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 1cb662d5bd7..913e8147114 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1,25 +1,25 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, @@ -32,6 +32,7 @@ */ #include <linux/vmalloc.h> +#include <linux/highmem.h> #include "netxen_nic_hw.h" #include "netxen_nic.h" @@ -48,14 +49,21 @@ MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID); -char netxen_nic_driver_name[] = "netxen"; +char netxen_nic_driver_name[] = "netxen-nic"; static char netxen_nic_driver_string[] = "NetXen Network Driver version " NETXEN_NIC_LINUX_VERSIONID; +struct netxen_adapter *g_adapter = NULL; + #define NETXEN_NETDEV_WEIGHT 120 #define NETXEN_ADAPTER_UP_MAGIC 777 #define NETXEN_NIC_PEG_TUNE 0 +u8 nx_p2_id = NX_P2_C0; + +#define DMA_32BIT_MASK 0x00000000ffffffffULL +#define DMA_35BIT_MASK 0x00000007ffffffffULL + /* Local functions to NetXen NIC driver */ static int __devinit netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent); @@ -64,7 +72,7 @@ static int netxen_nic_open(struct net_device *netdev); static int netxen_nic_close(struct net_device *netdev); static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); -static void netxen_tx_timeout_task(struct net_device *netdev); +static void netxen_tx_timeout_task(struct work_struct *work); static void netxen_watchdog(unsigned long); static int netxen_handle_int(struct netxen_adapter *, struct net_device *); static int netxen_nic_ioctl(struct net_device *netdev, @@ -87,6 +95,9 @@ static struct pci_device_id netxen_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci, netxen_pci_tbl); +struct workqueue_struct *netxen_workq; +static void netxen_watchdog(unsigned long); + /* * netxen_nic_probe() * @@ -105,20 +116,28 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct net_device *netdev = NULL; struct netxen_adapter *adapter = NULL; struct netxen_port *port = NULL; - u8 *mem_ptr0 = NULL; - u8 *mem_ptr1 = NULL; - u8 *mem_ptr2 = NULL; + void __iomem *mem_ptr0 = NULL; + void __iomem *mem_ptr1 = NULL; + void __iomem *mem_ptr2 = NULL; - unsigned long mem_base, mem_len; + u8 *db_ptr = NULL; + unsigned long mem_base, mem_len, db_base, db_len; int pci_using_dac, i, err; int ring; struct netxen_recv_context *recv_ctx = NULL; struct netxen_rcv_desc_ctx *rcv_desc = NULL; struct netxen_cmd_buffer *cmd_buf_arr = NULL; u64 mac_addr[FLASH_NUM_PORTS + 1]; - int valid_mac; + int valid_mac = 0; + static int netxen_cards_found = 0; printk(KERN_INFO "%s \n", netxen_nic_driver_string); + /* In current scheme, we use only PCI function 0 */ + if (PCI_FUNC(pdev->devfn) != 0) { + DPRINTK(ERR, "NetXen function %d will not be enabled.\n", + PCI_FUNC(pdev->devfn)); + return -ENODEV; + } if ((err = pci_enable_device(pdev))) return err; if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { @@ -130,10 +149,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_disable_pdev; pci_set_master(pdev); - if ((pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) && - (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) == 0)) + pci_read_config_byte(pdev, PCI_REVISION_ID, &nx_p2_id); + if (nx_p2_id == NX_P2_C1 && + (pci_set_dma_mask(pdev, DMA_35BIT_MASK) == 0) && + (pci_set_consistent_dma_mask(pdev, DMA_35BIT_MASK) == 0)) { pci_using_dac = 1; - else { + } else { if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) || (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) goto err_out_free_res; @@ -153,21 +174,34 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); if ((mem_ptr0 == 0UL) || (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) { - DPRINTK(1, ERR, + DPRINTK(ERR, "Cannot remap adapter memory aborting.:" "0 -> %p, 1 -> %p, 2 -> %p\n", mem_ptr0, mem_ptr1, mem_ptr2); err = -EIO; - if (mem_ptr0) - iounmap(mem_ptr0); - if (mem_ptr1) - iounmap(mem_ptr1); - if (mem_ptr2) - iounmap(mem_ptr2); - - goto err_out_free_res; + goto err_out_iounmap; + } + db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ + db_len = pci_resource_len(pdev, 4); + + if (db_len == 0) { + printk(KERN_ERR "%s: doorbell is disabled\n", + netxen_nic_driver_name); + err = -EIO; + goto err_out_iounmap; + } + DPRINTK(INFO, "doorbell ioremap from %lx a size of %lx\n", db_base, + db_len); + + db_ptr = ioremap(db_base, NETXEN_DB_MAPSIZE_BYTES); + if (db_ptr == 0UL) { + printk(KERN_ERR "%s: Failed to allocate doorbell map.", + netxen_nic_driver_name); + err = -EIO; + goto err_out_iounmap; } + DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr); /* * Allocate a adapter structure which will manage all the initialization @@ -183,17 +217,24 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netxen_nic_driver_name, (int)sizeof(struct netxen_adapter)); err = -ENOMEM; - goto err_out_iounmap; + goto err_out_dbunmap; } + if (netxen_cards_found == 0) { + g_adapter = adapter; + } adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS; adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS; adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS; + adapter->max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS; pci_set_drvdata(pdev, adapter); cmd_buf_arr = (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE); if (cmd_buf_arr == NULL) { + printk(KERN_ERR + "%s: Could not allocate cmd_buf_arr memory:%d\n", + netxen_nic_driver_name, (int)TX_RINGSIZE); err = -ENOMEM; goto err_out_free_adapter; } @@ -220,11 +261,23 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) rcv_desc->skb_size = MAX_RX_JUMBO_BUFFER_LENGTH; break; + case RCV_RING_LRO: + rcv_desc->max_rx_desc_count = + adapter->max_lro_rx_desc_count; + rcv_desc->flags = RCV_DESC_LRO; + rcv_desc->dma_size = RX_LRO_DMA_MAP_LEN; + rcv_desc->skb_size = MAX_RX_LRO_BUFFER_LENGTH; + break; + } rcv_desc->rx_buf_arr = (struct netxen_rx_buffer *) vmalloc(RCV_BUFFSIZE); if (rcv_desc->rx_buf_arr == NULL) { + printk(KERN_ERR "%s: Could not allocate" + "rcv_desc->rx_buf_arr memory:%d\n", + netxen_nic_driver_name, + (int)RCV_BUFFSIZE); err = -ENOMEM; goto err_out_free_rx_buffer; } @@ -233,30 +286,21 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } - adapter->ops = kzalloc(sizeof(struct netxen_drvops), GFP_KERNEL); - if (adapter->ops == NULL) { - printk(KERN_ERR - "%s: Could not allocate memory for adapter->ops:%d\n", - netxen_nic_driver_name, - (int)sizeof(struct netxen_adapter)); - err = -ENOMEM; - goto err_out_free_rx_buffer; - } - adapter->cmd_buf_arr = cmd_buf_arr; adapter->ahw.pci_base0 = mem_ptr0; adapter->ahw.pci_base1 = mem_ptr1; adapter->ahw.pci_base2 = mem_ptr2; + adapter->ahw.db_base = db_ptr; + adapter->ahw.db_len = db_len; spin_lock_init(&adapter->tx_lock); spin_lock_init(&adapter->lock); + netxen_initialize_adapter_sw(adapter); /* initialize the buffers in adapter */ #ifdef CONFIG_IA64 netxen_pinit_from_rom(adapter, 0); udelay(500); netxen_load_firmware(adapter); #endif - /* initialize the buffers in adapter */ - netxen_initialize_adapter_sw(adapter); /* * Set the CRB window to invalid. If any register in window 0 is * accessed it should set the window to 0 and then reset it to 1. @@ -274,11 +318,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->ahw.xg_linkup = 0; adapter->watchdog_timer.function = &netxen_watchdog; adapter->watchdog_timer.data = (unsigned long)adapter; - INIT_WORK(&adapter->watchdog_task, - (void (*)(void *))netxen_watchdog_task, adapter); + INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task); adapter->ahw.pdev = pdev; adapter->proc_cmd_buf_counter = 0; - pci_read_config_byte(pdev, PCI_REVISION_ID, &adapter->ahw.revision_id); + adapter->ahw.revision_id = nx_p2_id; if (pci_enable_msi(pdev)) { adapter->flags &= ~NETXEN_NIC_MSI_ENABLED; @@ -300,6 +343,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_CONSUMER_OFFSET)); writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO)); + /* do this before waking up pegs so that we have valid dummy dma addr */ + err = netxen_initialize_adapter_offload(adapter); + if (err) { + goto err_out_free_dev; + } + /* Unlock the HW, prompting the boot sequence */ writel(1, NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE)); @@ -308,6 +357,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); /* initialize the all the ports */ + adapter->active_ports = 0; for (i = 0; i < adapter->ahw.max_ports; i++) { netdev = alloc_etherdev(sizeof(struct netxen_port)); @@ -373,14 +423,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->dev_addr[4], netdev->dev_addr[5]); } else { - if (adapter->ops->macaddr_set) - adapter->ops->macaddr_set(port, - netdev-> - dev_addr); + if (adapter->macaddr_set) + adapter->macaddr_set(port, + netdev->dev_addr); } } - INIT_WORK(&adapter->tx_timeout_task, - (void (*)(void *))netxen_tx_timeout_task, netdev); + adapter->netdev = netdev; + INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task); netif_carrier_off(netdev); netif_stop_queue(netdev); @@ -392,7 +441,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_dev; } adapter->port_count++; - adapter->active_ports = 0; adapter->port[i] = port; } @@ -413,6 +461,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; } + adapter->number = netxen_cards_found; adapter->driver_mismatch = 0; return 0; @@ -427,7 +476,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) free_netdev(port->netdev); } } - kfree(adapter->ops); + + netxen_free_adapter_offload(adapter); err_out_free_rx_buffer: for (i = 0; i < MAX_RCV_CTX; ++i) { @@ -440,19 +490,23 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } } } - vfree(cmd_buf_arr); - kfree(adapter->port); - err_out_free_adapter: pci_set_drvdata(pdev, NULL); kfree(adapter); + err_out_dbunmap: + if (db_ptr) + iounmap(db_ptr); + err_out_iounmap: - iounmap(mem_ptr0); - iounmap(mem_ptr1); - iounmap(mem_ptr2); + if (mem_ptr0) + iounmap(mem_ptr0); + if (mem_ptr1) + iounmap(mem_ptr1); + if (mem_ptr2) + iounmap(mem_ptr2); err_out_free_res: pci_release_regions(pdev); @@ -477,12 +531,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) netxen_nic_stop_all_ports(adapter); /* leave the hw in the same state as reboot */ - netxen_pinit_from_rom(adapter, 0); - udelay(500); netxen_load_firmware(adapter); - - if ((adapter->flags & NETXEN_NIC_MSI_ENABLED)) - netxen_nic_disable_int(adapter); + netxen_free_adapter_offload(adapter); udelay(500); /* Delay for a while to drain the DMA engines */ for (i = 0; i < adapter->port_count; i++) { @@ -499,6 +549,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) netxen_free_hw_resources(adapter); + iounmap(adapter->ahw.db_base); iounmap(adapter->ahw.pci_base0); iounmap(adapter->ahw.pci_base1); iounmap(adapter->ahw.pci_base2); @@ -525,7 +576,6 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) } vfree(adapter->cmd_buf_arr); - kfree(adapter->ops); kfree(adapter); } @@ -547,6 +597,8 @@ static int netxen_nic_open(struct net_device *netdev) return -EIO; } netxen_nic_flash_print(adapter); + if (adapter->init_niu) + adapter->init_niu(adapter); /* setup all the resources for the Phantom... */ /* this include the descriptors for rcv, tx, and status */ @@ -557,32 +609,31 @@ static int netxen_nic_open(struct net_device *netdev) err); return err; } - if (adapter->ops->init_port - && adapter->ops->init_port(adapter, port->portnum) != 0) { + if (adapter->init_port + && adapter->init_port(adapter, port->portnum) != 0) { printk(KERN_ERR "%s: Failed to initialize port %d\n", netxen_nic_driver_name, port->portnum); netxen_free_hw_resources(adapter); return -EIO; } - if (adapter->ops->init_niu) - adapter->ops->init_niu(adapter); for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) netxen_post_rx_buffers(adapter, ctx, ring); } - adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; - } - adapter->active_ports++; - if (adapter->active_ports == 1) { + adapter->irq = adapter->ahw.pdev->irq; err = request_irq(adapter->ahw.pdev->irq, &netxen_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, adapter); if (err) { printk(KERN_ERR "request_irq failed with: %d\n", err); - adapter->active_ports--; + netxen_free_hw_resources(adapter); return err; } - adapter->irq = adapter->ahw.pdev->irq; + + adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; + } + adapter->active_ports++; + if (adapter->active_ports == 1) { if (!adapter->driver_mismatch) mod_timer(&adapter->watchdog_timer, jiffies); @@ -591,11 +642,14 @@ static int netxen_nic_open(struct net_device *netdev) /* Done here again so that even if phantom sw overwrote it, * we set it */ - if (adapter->ops->macaddr_set) - adapter->ops->macaddr_set(port, netdev->dev_addr); + if (adapter->macaddr_set) + adapter->macaddr_set(port, netdev->dev_addr); netxen_nic_set_link_parameters(port); netxen_nic_set_multi(netdev); + if (adapter->set_mtu) + adapter->set_mtu(port, netdev->mtu); + if (!adapter->driver_mismatch) netif_start_queue(netdev); @@ -648,6 +702,7 @@ static int netxen_nic_close(struct net_device *netdev) } cmd_buff++; } + FLUSH_SCHEDULED_WORK(); del_timer_sync(&adapter->watchdog_timer); } @@ -668,7 +723,6 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct cmd_desc_type0 *hwdesc; int k; struct netxen_cmd_buffer *pbuf = NULL; - unsigned int tries = 0; static int dropped_packet = 0; int frag_count; u32 local_producer = 0; @@ -730,7 +784,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (((skb->nh.iph)->ihl * sizeof(u32)) + ((skb->h.th)->doff * sizeof(u32)) + sizeof(struct ethhdr) > - (sizeof(struct cmd_desc_type0) - NET_IP_ALIGN)) { + (sizeof(struct cmd_desc_type0) - 2)) { no_of_desc++; } } @@ -741,27 +795,17 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if ((k + no_of_desc) >= ((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count : last_cmd_consumer)) { + port->stats.nocmddescriptor++; + DPRINTK(ERR, "No command descriptors available," + " producer = %d, consumer = %d count=%llu," + " dropping packet\n", producer, + adapter->last_cmd_consumer, + port->stats.nocmddescriptor); + + netif_stop_queue(netdev); + port->flags |= NETXEN_NETDEV_STATUS; spin_unlock_bh(&adapter->tx_lock); - if (tries == 0) { - local_bh_disable(); - netxen_process_cmd_ring((unsigned long)adapter); - local_bh_enable(); - ++tries; - goto retry_getting_window; - } else { - port->stats.nocmddescriptor++; - DPRINTK(ERR, "No command descriptors available," - " producer = %d, consumer = %d count=%llu," - " dropping packet\n", producer, - adapter->last_cmd_consumer, - port->stats.nocmddescriptor); - - spin_lock_bh(&adapter->tx_lock); - netif_stop_queue(netdev); - port->flags |= NETXEN_NETDEV_STATUS; - spin_unlock_bh(&adapter->tx_lock); - return NETDEV_TX_BUSY; - } + return NETDEV_TX_BUSY; } k = get_index_range(k, max_tx_desc_count, no_of_desc); adapter->cmd_producer = k; @@ -783,7 +827,6 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) pbuf->mss = 0; hwdesc->mss = 0; } - pbuf->no_of_descriptors = no_of_desc; pbuf->total_length = skb->len; pbuf->skb = skb; pbuf->cmd = TX_ETHER_PKT; @@ -793,11 +836,11 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) buffrag->dma = pci_map_single(port->pdev, skb->data, first_seg_len, PCI_DMA_TODEVICE); buffrag->length = first_seg_len; - CMD_DESC_TOTAL_LENGTH_WRT(hwdesc, skb->len); - hwdesc->num_of_buffers = frag_count; - hwdesc->opcode = TX_ETHER_PKT; + netxen_set_cmd_desc_totallength(hwdesc, skb->len); + netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count); + netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT); - CMD_DESC_PORT_WRT(hwdesc, port->portnum); + netxen_set_cmd_desc_port(hwdesc, port->portnum); hwdesc->buffer1_length = cpu_to_le16(first_seg_len); hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); @@ -856,12 +899,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* For LSO, we need to copy the MAC/IP/TCP headers into * the descriptor ring */ - if (hw->cmd_desc_head[saved_producer].opcode == TX_TCP_LSO) { + if (netxen_get_cmd_desc_opcode(&hw->cmd_desc_head[saved_producer]) + == TX_TCP_LSO) { int hdr_len, first_hdr_len, more_hdr; hdr_len = hw->cmd_desc_head[saved_producer].total_hdr_length; - if (hdr_len > (sizeof(struct cmd_desc_type0) - NET_IP_ALIGN)) { - first_hdr_len = - sizeof(struct cmd_desc_type0) - NET_IP_ALIGN; + if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) { + first_hdr_len = sizeof(struct cmd_desc_type0) - 2; more_hdr = 1; } else { first_hdr_len = hdr_len; @@ -871,7 +914,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) hwdesc = &hw->cmd_desc_head[producer]; /* copy the first 64 bytes */ - memcpy(((void *)hwdesc) + NET_IP_ALIGN, + memcpy(((void *)hwdesc) + 2, (void *)(skb->data), first_hdr_len); producer = get_next_index(producer, max_tx_desc_count); @@ -887,7 +930,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } spin_lock_bh(&adapter->tx_lock); port->stats.txbytes += - CMD_DESC_TOTAL_LENGTH(&hw->cmd_desc_head[saved_producer]); + netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]); /* Code to update the adapter considering how many producer threads are currently working */ if ((--adapter->num_threads) == 0) { @@ -897,20 +940,6 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET)); wmb(); adapter->total_threads = 0; - } else { - u32 crb_producer = 0; - crb_producer = - readl(NETXEN_CRB_NORMALIZE - (adapter, CRB_CMD_PRODUCER_OFFSET)); - if (crb_producer == local_producer) { - crb_producer = get_index_range(crb_producer, - max_tx_desc_count, - no_of_desc); - writel(crb_producer, - NETXEN_CRB_NORMALIZE(adapter, - CRB_CMD_PRODUCER_OFFSET)); - wmb(); - } } port->stats.xmitfinished++; @@ -927,29 +956,36 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) static void netxen_watchdog(unsigned long v) { struct netxen_adapter *adapter = (struct netxen_adapter *)v; - schedule_work(&adapter->watchdog_task); + if (adapter != g_adapter) { + printk("%s: ***BUG*** adapter[%p] != g_adapter[%p]\n", + __FUNCTION__, adapter, g_adapter); + return; + } + + SCHEDULE_WORK(&adapter->watchdog_task); } static void netxen_tx_timeout(struct net_device *netdev) { struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev); - struct netxen_adapter *adapter = port->adapter; - schedule_work(&adapter->tx_timeout_task); + SCHEDULE_WORK(port->adapter->tx_timeout_task + port->portnum); } -static void netxen_tx_timeout_task(struct net_device *netdev) +static void netxen_tx_timeout_task(struct work_struct *work) { - struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev); + struct netxen_adapter *adapter = + container_of(work, struct netxen_adapter, tx_timeout_task); + struct net_device *netdev = adapter->netdev; unsigned long flags; printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", netxen_nic_driver_name, netdev->name); - spin_lock_irqsave(&port->adapter->lock, flags); + spin_lock_irqsave(&adapter->lock, flags); netxen_nic_close(netdev); netxen_nic_open(netdev); - spin_unlock_irqrestore(&port->adapter->lock, flags); + spin_unlock_irqrestore(&adapter->lock, flags); netdev->trans_start = jiffies; netif_wake_queue(netdev); } @@ -966,6 +1002,11 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { int count = 0; u32 mask; + mask = readl(pci_base_offset(adapter, ISR_INT_VECTOR)); + if ((mask & 0x80) == 0) { + /* not our interrupt */ + return ret; + } netxen_nic_disable_int(adapter); /* Window = 0 or 1 */ do { @@ -1025,7 +1066,10 @@ irqreturn_t netxen_intr(int irq, void *data) netdev = port->netdev; /* process our status queue (for all 4 ports) */ - netxen_handle_int(adapter, netdev); + if (netif_running(netdev)) { + netxen_handle_int(adapter, netdev); + break; + } } return IRQ_HANDLED; @@ -1039,11 +1083,12 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget) int done = 1; int ctx; int this_work_done; + int work_done = 0; DPRINTK(INFO, "polling for %d descriptors\n", *budget); port->stats.polled++; - adapter->work_done = 0; + work_done = 0; for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { /* * Fairness issue. This will give undue weight to the @@ -1060,20 +1105,20 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget) this_work_done = netxen_process_rcv_ring(adapter, ctx, work_to_do / MAX_RCV_CTX); - adapter->work_done += this_work_done; + work_done += this_work_done; } - netdev->quota -= adapter->work_done; - *budget -= adapter->work_done; + netdev->quota -= work_done; + *budget -= work_done; - if (adapter->work_done >= work_to_do - && netxen_nic_rx_has_work(adapter) != 0) + if (work_done >= work_to_do && netxen_nic_rx_has_work(adapter) != 0) done = 0; - netxen_process_cmd_ring((unsigned long)adapter); + if (netxen_process_cmd_ring((unsigned long)adapter) == 0) + done = 0; DPRINTK(INFO, "new work_done: %d work_to_do: %d\n", - adapter->work_done, work_to_do); + work_done, work_to_do); if (done) { netif_rx_complete(netdev); netxen_nic_enable_int(adapter); @@ -1116,8 +1161,9 @@ netxen_nic_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) if (ifr->ifr_data) { sprintf(dev_name, "%s-%d", NETXEN_NIC_NAME_RSP, port->portnum); - nr_bytes = copy_to_user((char *)ifr->ifr_data, dev_name, - NETXEN_NIC_NAME_LEN); + nr_bytes = + copy_to_user((char __user *)ifr->ifr_data, dev_name, + NETXEN_NIC_NAME_LEN); if (nr_bytes) err = -EIO; @@ -1144,6 +1190,9 @@ static struct pci_driver netxen_driver = { static int __init netxen_init_module(void) { + if ((netxen_workq = create_singlethread_workqueue("netxen")) == 0) + return -ENOMEM; + return pci_module_init(&netxen_driver); } @@ -1154,7 +1203,7 @@ static void __exit netxen_exit_module(void) /* * Wait for some time to allow the dma to drain, if any. */ - mdelay(5); + destroy_workqueue(netxen_workq); pci_unregister_driver(&netxen_driver); } diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 7950a04532e..4987dc765d9 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -16,10 +16,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, @@ -40,13 +40,15 @@ static long phy_lock_timeout = 100000000; -static inline int phy_lock(void) +static inline int phy_lock(struct netxen_adapter *adapter) { int i; int done = 0, timeout = 0; while (!done) { - done = readl((void __iomem *)NETXEN_PCIE_REG(PCIE_SEM3_LOCK)); + done = + readl(pci_base_offset + (adapter, NETXEN_PCIE_REG(PCIE_SEM3_LOCK))); if (done == 1) break; if (timeout >= phy_lock_timeout) { @@ -61,13 +63,15 @@ static inline int phy_lock(void) } } - writel(NETXEN_PHY_LOCK_ID, (void __iomem *)PHY_LOCK_DRIVER); + writel(PHY_LOCK_DRIVER, + NETXEN_CRB_NORMALIZE(adapter, NETXEN_PHY_LOCK_ID)); return 0; } -static inline int phy_unlock(void) +static inline int phy_unlock(struct netxen_adapter *adapter) { - readl((void __iomem *)NETXEN_PCIE_REG(PCIE_SEM3_UNLOCK)); + readl(pci_base_offset(adapter, NETXEN_PCIE_REG(PCIE_SEM3_UNLOCK))); + return 0; } @@ -95,7 +99,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, __le32 status; __le32 mac_cfg0; - if (phy_lock() != 0) { + if (phy_lock(adapter) != 0) { return -1; } @@ -162,7 +166,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, NETXEN_NIU_GB_MAC_CONFIG_0(0), &mac_cfg0, 4)) return -EIO; - phy_unlock(); + phy_unlock(adapter); return result; } @@ -399,8 +403,8 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) { int result = 0; __le32 status; - if (adapter->ops->disable_phy_interrupts) - adapter->ops->disable_phy_interrupts(adapter, port); + if (adapter->disable_phy_interrupts) + adapter->disable_phy_interrupts(adapter, port); mdelay(2); if (0 == @@ -612,7 +616,7 @@ int netxen_niu_macaddr_set(struct netxen_port *port, __le32 temp = 0; struct netxen_adapter *adapter = port->adapter; int phy = port->portnum; - unsigned char mac_addr[MAX_ADDR_LEN]; + unsigned char mac_addr[6]; int i; for (i = 0; i < 10; i++) { @@ -631,7 +635,7 @@ int netxen_niu_macaddr_set(struct netxen_port *port, netxen_niu_macaddr_get(adapter, phy, (netxen_ethernet_macaddr_t *) mac_addr); - if (memcmp(mac_addr, addr, MAX_ADDR_LEN == 0)) + if (memcmp(mac_addr, addr, 6) == 0) break; } diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h index 8181d436783..7879f855af0 100644 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/drivers/net/netxen/netxen_nic_phan_reg.h @@ -33,15 +33,74 @@ /* * CRB Registers or queue message done only at initialization time. */ +#define NIC_CRB_BASE NETXEN_CAM_RAM(0x200) +#define NETXEN_NIC_REG(X) (NIC_CRB_BASE+(X)) -/* - * The following 2 are the base adresses for the CRB registers and their - * offsets will be added to get addresses for the index addresses. - */ -#define NIC_CRB_BASE_PORT1 NETXEN_CAM_RAM(0x200) -#define NIC_CRB_BASE_PORT2 NETXEN_CAM_RAM(0x250) +#define CRB_PHAN_CNTRL_LO_OFFSET NETXEN_NIC_REG(0x00) +#define CRB_PHAN_CNTRL_HI_OFFSET NETXEN_NIC_REG(0x04) +#define CRB_CMD_PRODUCER_OFFSET NETXEN_NIC_REG(0x08) +#define CRB_CMD_CONSUMER_OFFSET NETXEN_NIC_REG(0x0c) +#define CRB_PAUSE_ADDR_LO NETXEN_NIC_REG(0x10) /* C0 EPG BUG */ +#define CRB_PAUSE_ADDR_HI NETXEN_NIC_REG(0x14) +#define CRB_HOST_CMD_ADDR_HI NETXEN_NIC_REG(0x18) /* host add:cmd ring */ +#define CRB_HOST_CMD_ADDR_LO NETXEN_NIC_REG(0x1c) +#define CRB_CMD_INTR_LOOP NETXEN_NIC_REG(0x20) /* 4 regs for perf */ +#define CRB_CMD_DMA_LOOP NETXEN_NIC_REG(0x24) +#define CRB_RCV_INTR_LOOP NETXEN_NIC_REG(0x28) +#define CRB_RCV_DMA_LOOP NETXEN_NIC_REG(0x2c) +#define CRB_ENABLE_TX_INTR NETXEN_NIC_REG(0x30) /* phantom init status */ +#define CRB_MMAP_ADDR_3 NETXEN_NIC_REG(0x34) +#define CRB_CMDPEG_CMDRING NETXEN_NIC_REG(0x38) +#define CRB_HOST_DUMMY_BUF_ADDR_HI NETXEN_NIC_REG(0x3c) +#define CRB_HOST_DUMMY_BUF_ADDR_LO NETXEN_NIC_REG(0x40) +#define CRB_MMAP_ADDR_0 NETXEN_NIC_REG(0x44) +#define CRB_MMAP_ADDR_1 NETXEN_NIC_REG(0x48) +#define CRB_MMAP_ADDR_2 NETXEN_NIC_REG(0x4c) +#define CRB_CMDPEG_STATE NETXEN_NIC_REG(0x50) +#define CRB_MMAP_SIZE_0 NETXEN_NIC_REG(0x54) +#define CRB_MMAP_SIZE_1 NETXEN_NIC_REG(0x58) +#define CRB_MMAP_SIZE_2 NETXEN_NIC_REG(0x5c) +#define CRB_MMAP_SIZE_3 NETXEN_NIC_REG(0x60) +#define CRB_GLOBAL_INT_COAL NETXEN_NIC_REG(0x64) /* interrupt coalescing */ +#define CRB_INT_COAL_MODE NETXEN_NIC_REG(0x68) +#define CRB_MAX_RCV_BUFS NETXEN_NIC_REG(0x6c) +#define CRB_TX_INT_THRESHOLD NETXEN_NIC_REG(0x70) +#define CRB_RX_PKT_TIMER NETXEN_NIC_REG(0x74) +#define CRB_TX_PKT_TIMER NETXEN_NIC_REG(0x78) +#define CRB_RX_PKT_CNT NETXEN_NIC_REG(0x7c) +#define CRB_RX_TMR_CNT NETXEN_NIC_REG(0x80) +#define CRB_RX_LRO_TIMER NETXEN_NIC_REG(0x84) +#define CRB_RX_LRO_MID_TIMER NETXEN_NIC_REG(0x88) +#define CRB_DMA_MAX_RCV_BUFS NETXEN_NIC_REG(0x8c) +#define CRB_MAX_DMA_ENTRIES NETXEN_NIC_REG(0x90) +#define CRB_XG_STATE NETXEN_NIC_REG(0x94) /* XG Link status */ +#define CRB_AGENT_GO NETXEN_NIC_REG(0x98) /* NIC pkt gen agent */ +#define CRB_AGENT_TX_SIZE NETXEN_NIC_REG(0x9c) +#define CRB_AGENT_TX_TYPE NETXEN_NIC_REG(0xa0) +#define CRB_AGENT_TX_ADDR NETXEN_NIC_REG(0xa4) +#define CRB_AGENT_TX_MSS NETXEN_NIC_REG(0xa8) +#define CRB_TX_STATE NETXEN_NIC_REG(0xac) /* Debug -performance */ +#define CRB_TX_COUNT NETXEN_NIC_REG(0xb0) +#define CRB_RX_STATE NETXEN_NIC_REG(0xb4) +#define CRB_RX_PERF_DEBUG_1 NETXEN_NIC_REG(0xb8) +#define CRB_RX_LRO_CONTROL NETXEN_NIC_REG(0xbc) /* LRO On/OFF */ +#define CRB_RX_LRO_START_NUM NETXEN_NIC_REG(0xc0) +#define CRB_MPORT_MODE NETXEN_NIC_REG(0xc4) /* Multiport Mode */ +#define CRB_CMD_RING_SIZE NETXEN_NIC_REG(0xc8) +#define CRB_INT_VECTOR NETXEN_NIC_REG(0xd4) +#define CRB_CTX_RESET NETXEN_NIC_REG(0xd8) +#define CRB_HOST_STS_PROD NETXEN_NIC_REG(0xdc) +#define CRB_HOST_STS_CONS NETXEN_NIC_REG(0xe0) +#define CRB_PEG_CMD_PROD NETXEN_NIC_REG(0xe4) +#define CRB_PEG_CMD_CONS NETXEN_NIC_REG(0xe8) +#define CRB_HOST_BUFFER_PROD NETXEN_NIC_REG(0xec) +#define CRB_HOST_BUFFER_CONS NETXEN_NIC_REG(0xf0) +#define CRB_JUMBO_BUFFER_PROD NETXEN_NIC_REG(0xf4) +#define CRB_JUMBO_BUFFER_CONS NETXEN_NIC_REG(0xf8) -#define NETXEN_NIC_REG(X) (NIC_CRB_BASE_PORT1+(X)) +#define CRB_CMD_PRODUCER_OFFSET_1 NETXEN_NIC_REG(0x1ac) +#define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0) +#define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4) /* * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address @@ -51,74 +110,20 @@ * on the Phantom. */ -#define CRB_PHAN_CNTRL_LO_OFFSET NETXEN_NIC_REG(0x00) -#define CRB_PHAN_CNTRL_HI_OFFSET NETXEN_NIC_REG(0x04) - -/* point to the indexes */ -#define CRB_CMD_PRODUCER_OFFSET NETXEN_NIC_REG(0x08) -#define CRB_CMD_CONSUMER_OFFSET NETXEN_NIC_REG(0x0c) - -#define CRB_PAUSE_ADDR_LO NETXEN_NIC_REG(0x10) -#define CRB_PAUSE_ADDR_HI NETXEN_NIC_REG(0x14) - -/* address of command descriptors in the host memory */ -#define CRB_HOST_CMD_ADDR_HI NETXEN_NIC_REG(0x30) -#define CRB_HOST_CMD_ADDR_LO NETXEN_NIC_REG(0x34) - -/* The following 4 CRB registers are for doing performance coal */ -#define CRB_CMD_INTR_LOOP NETXEN_NIC_REG(0x38) -#define CRB_CMD_DMA_LOOP NETXEN_NIC_REG(0x3c) -#define CRB_RCV_INTR_LOOP NETXEN_NIC_REG(0x40) -#define CRB_RCV_DMA_LOOP NETXEN_NIC_REG(0x44) - -/* Needed by the host to find out the state of Phantom's initialization */ -#define CRB_ENABLE_TX_INTR NETXEN_NIC_REG(0x4c) -#define CRB_CMDPEG_STATE NETXEN_NIC_REG(0x50) -#define CRB_CMDPEG_CMDRING NETXEN_NIC_REG(0x54) - -/* Interrupt coalescing parameters */ -#define CRB_GLOBAL_INT_COAL NETXEN_NIC_REG(0x80) -#define CRB_INT_COAL_MODE NETXEN_NIC_REG(0x84) -#define CRB_MAX_RCV_BUFS NETXEN_NIC_REG(0x88) -#define CRB_TX_INT_THRESHOLD NETXEN_NIC_REG(0x8c) -#define CRB_RX_PKT_TIMER NETXEN_NIC_REG(0x90) -#define CRB_TX_PKT_TIMER NETXEN_NIC_REG(0x94) -#define CRB_RX_PKT_CNT NETXEN_NIC_REG(0x98) -#define CRB_RX_TMR_CNT NETXEN_NIC_REG(0x9c) -#define CRB_INT_THRESH NETXEN_NIC_REG(0xa4) - -/* Register for communicating XG link status */ -#define CRB_XG_STATE NETXEN_NIC_REG(0xa0) - -/* Register for communicating card temperature */ -/* Upper 16 bits are temperature value. Lower 16 bits are the state */ -#define CRB_TEMP_STATE NETXEN_NIC_REG(0xa8) -#define nx_get_temp_val(x) ((x) >> 16) -#define nx_get_temp_state(x) ((x) & 0xffff) -#define nx_encode_temp(val, state) (((val) << 16) | (state)) - -/* Debug registers for controlling NIC pkt gen agent */ -#define CRB_AGENT_GO NETXEN_NIC_REG(0xb0) -#define CRB_AGENT_TX_SIZE NETXEN_NIC_REG(0xb4) -#define CRB_AGENT_TX_TYPE NETXEN_NIC_REG(0xb8) -#define CRB_AGENT_TX_ADDR NETXEN_NIC_REG(0xbc) -#define CRB_AGENT_TX_MSS NETXEN_NIC_REG(0xc0) - -/* Debug registers for observing NIC performance */ -#define CRB_TX_STATE NETXEN_NIC_REG(0xd0) -#define CRB_TX_COUNT NETXEN_NIC_REG(0xd4) -#define CRB_RX_STATE NETXEN_NIC_REG(0xd8) +#define nx_get_temp_val(x) ((x) >> 16) +#define nx_get_temp_state(x) ((x) & 0xffff) +#define nx_encode_temp(val, state) (((val) << 16) | (state)) /* CRB registers per Rcv Descriptor ring */ struct netxen_rcv_desc_crb { u32 crb_rcv_producer_offset __attribute__ ((aligned(512))); u32 crb_rcv_consumer_offset; u32 crb_globalrcv_ring; + u32 crb_rcv_ring_size; }; /* - * CRB registers used by the receive peg logic. One instance of these - * needs to be instantiated per instance of the receive peg. + * CRB registers used by the receive peg logic. */ struct netxen_recv_crb { @@ -127,6 +132,7 @@ struct netxen_recv_crb { u32 crb_rcv_status_producer; u32 crb_rcv_status_consumer; u32 crb_rcvpeg_state; + u32 crb_status_ring_size; }; #if defined(DEFINE_GLOBAL_RECV_CRB) @@ -139,30 +145,48 @@ struct netxen_recv_crb recv_crb_registers[] = { { { /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x18), + NETXEN_NIC_REG(0x100), /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x1c), + NETXEN_NIC_REG(0x104), /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x20), + NETXEN_NIC_REG(0x108), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x10c), + }, /* Jumbo frames */ { /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x100), + NETXEN_NIC_REG(0x110), /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x104), + NETXEN_NIC_REG(0x114), /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x108), + NETXEN_NIC_REG(0x118), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x11c), + }, + /* LRO */ + { + /* crb_rcv_producer_offset: */ + NETXEN_NIC_REG(0x120), + /* crb_rcv_consumer_offset: */ + NETXEN_NIC_REG(0x124), + /* crb_gloablrcv_ring: */ + NETXEN_NIC_REG(0x128), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x12c), } }, /* crb_rcvstatus_ring: */ - NETXEN_NIC_REG(0x24), + NETXEN_NIC_REG(0x130), /* crb_rcv_status_producer: */ - NETXEN_NIC_REG(0x28), + NETXEN_NIC_REG(0x134), /* crb_rcv_status_consumer: */ - NETXEN_NIC_REG(0x2c), + NETXEN_NIC_REG(0x138), /* crb_rcvpeg_state: */ - NETXEN_NIC_REG(0x48), + NETXEN_NIC_REG(0x13c), + /* crb_status_ring_size */ + NETXEN_NIC_REG(0x140), }, /* @@ -173,34 +197,66 @@ struct netxen_recv_crb recv_crb_registers[] = { { { /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x80), + NETXEN_NIC_REG(0x144), /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x84), + NETXEN_NIC_REG(0x148), /* crb_globalrcv_ring: */ - NETXEN_NIC_REG(0x88), + NETXEN_NIC_REG(0x14c), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x150), + }, /* Jumbo frames */ { /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x10C), + NETXEN_NIC_REG(0x154), /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x110), + NETXEN_NIC_REG(0x158), /* crb_globalrcv_ring: */ - NETXEN_NIC_REG(0x114), + NETXEN_NIC_REG(0x15c), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x160), + }, + /* LRO */ + { + /* crb_rcv_producer_offset: */ + NETXEN_NIC_REG(0x164), + /* crb_rcv_consumer_offset: */ + NETXEN_NIC_REG(0x168), + /* crb_globalrcv_ring: */ + NETXEN_NIC_REG(0x16c), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x170), } + }, /* crb_rcvstatus_ring: */ - NETXEN_NIC_REG(0x8c), + NETXEN_NIC_REG(0x174), /* crb_rcv_status_producer: */ - NETXEN_NIC_REG(0x90), + NETXEN_NIC_REG(0x178), /* crb_rcv_status_consumer: */ - NETXEN_NIC_REG(0x94), + NETXEN_NIC_REG(0x17c), /* crb_rcvpeg_state: */ - NETXEN_NIC_REG(0x98), + NETXEN_NIC_REG(0x180), + /* crb_status_ring_size */ + NETXEN_NIC_REG(0x184), + }, }; + +u64 ctx_addr_sig_regs[][3] = { + {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)}, + {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)}, + {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)}, + {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)} +}; + #else extern struct netxen_recv_crb recv_crb_registers[]; +extern u64 ctx_addr_sig_regs[][3]; +#define CRB_CTX_ADDR_REG_LO (ctx_addr_sig_regs[0][0]) +#define CRB_CTX_ADDR_REG_HI (ctx_addr_sig_regs[0][2]) +#define CRB_CTX_SIGNATURE_REG (ctx_addr_sig_regs[0][1]) #endif /* DEFINE_GLOBAL_RECEIVE_CRB */ /* diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 26e42f6e9fb..196993a29b0 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -1335,7 +1335,7 @@ int __init init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(dev_ni52); release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE); diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 340ad0d5388..1578f4d9849 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -1259,7 +1259,7 @@ int __init init_module(void) return IS_ERR(dev_ni65) ? PTR_ERR(dev_ni65) : 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(dev_ni65); cleanup_card(dev_ni65); diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index b0127c71a5b..568daeb3e9d 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -414,10 +414,10 @@ struct rx_info { struct sk_buff *skbs[NR_RX_DESC]; - u32 *next_rx_desc; + __le32 *next_rx_desc; u16 next_rx, next_empty; - u32 *descs; + __le32 *descs; dma_addr_t phy_descs; }; @@ -427,6 +427,7 @@ struct ns83820 { u8 __iomem *base; struct pci_dev *pci_dev; + struct net_device *ndev; #ifdef NS83820_VLAN_ACCEL_SUPPORT struct vlan_group *vlgrp; @@ -459,7 +460,7 @@ struct ns83820 { struct sk_buff *tx_skbs[NR_TX_DESC]; char pad[16] __attribute__((aligned(16))); - u32 *tx_descs; + __le32 *tx_descs; dma_addr_t tx_phy_descs; struct timer_list tx_watchdog; @@ -533,7 +534,7 @@ static void ns83820_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid * conditions, still route realtime traffic with as low jitter as * possible. */ -static inline void build_rx_desc(struct ns83820 *dev, u32 *desc, dma_addr_t link, dma_addr_t buf, u32 cmdsts, u32 extsts) +static inline void build_rx_desc(struct ns83820 *dev, __le32 *desc, dma_addr_t link, dma_addr_t buf, u32 cmdsts, u32 extsts) { desc_addr_set(desc + DESC_LINK, link); desc_addr_set(desc + DESC_BUFPTR, buf); @@ -547,7 +548,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb) { unsigned next_empty; u32 cmdsts; - u32 *sg; + __le32 *sg; dma_addr_t buf; next_empty = dev->rx_info.next_empty; @@ -631,10 +632,10 @@ static void fastcall rx_refill_atomic(struct net_device *ndev) } /* REFILL */ -static inline void queue_refill(void *_dev) +static inline void queue_refill(struct work_struct *work) { - struct net_device *ndev = _dev; - struct ns83820 *dev = PRIV(ndev); + struct ns83820 *dev = container_of(work, struct ns83820, tq_refill); + struct net_device *ndev = dev->ndev; rx_refill(ndev, GFP_KERNEL); if (dev->rx_info.up) @@ -874,7 +875,8 @@ static void fastcall rx_irq(struct net_device *ndev) struct rx_info *info = &dev->rx_info; unsigned next_rx; int rx_rc, len; - u32 cmdsts, *desc; + u32 cmdsts; + __le32 *desc; unsigned long flags; int nr = 0; @@ -1010,7 +1012,8 @@ static inline void kick_tx(struct ns83820 *dev) static void do_tx_done(struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); - u32 cmdsts, tx_done_idx, *desc; + u32 cmdsts, tx_done_idx; + __le32 *desc; dprintk("do_tx_done(%p)\n", ndev); tx_done_idx = dev->tx_done_idx; @@ -1077,7 +1080,7 @@ static void ns83820_cleanup_tx(struct ns83820 *dev) struct sk_buff *skb = dev->tx_skbs[i]; dev->tx_skbs[i] = NULL; if (skb) { - u32 *desc = dev->tx_descs + (i * DESC_SIZE); + __le32 *desc = dev->tx_descs + (i * DESC_SIZE); pci_unmap_single(dev->pci_dev, desc_addr_get(desc + DESC_BUFPTR), le32_to_cpu(desc[DESC_CMDSTS]) & CMDSTS_LEN_MASK, @@ -1107,7 +1110,7 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) skb_frag_t *frag; int stopped = 0; int do_intr = 0; - volatile u32 *first_desc; + volatile __le32 *first_desc; dprintk("ns83820_hard_start_xmit\n"); @@ -1180,7 +1183,7 @@ again: first_desc = dev->tx_descs + (free_idx * DESC_SIZE); for (;;) { - volatile u32 *desc = dev->tx_descs + (free_idx * DESC_SIZE); + volatile __le32 *desc = dev->tx_descs + (free_idx * DESC_SIZE); dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len, (unsigned long long)buf); @@ -1455,7 +1458,8 @@ static int ns83820_stop(struct net_device *ndev) static void ns83820_tx_timeout(struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); - u32 tx_done_idx, *desc; + u32 tx_done_idx; + __le32 *desc; unsigned long flags; spin_lock_irqsave(&dev->tx_lock, flags); @@ -1841,6 +1845,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ndev = alloc_etherdev(sizeof(struct ns83820)); dev = PRIV(ndev); + dev->ndev = ndev; err = -ENOMEM; if (!dev) goto out; @@ -1853,7 +1858,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pci_dev->dev); - INIT_WORK(&dev->tq_refill, queue_refill, ndev); + INIT_WORK(&dev->tq_refill, queue_refill); tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)ndev); err = pci_enable_device(pci_dev); diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 04600992852..794cc61819d 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -338,7 +338,6 @@ static int tc574_config(struct pcmcia_device *link) struct net_device *dev = link->priv; struct el3_private *lp = netdev_priv(dev); tuple_t tuple; - cisparse_t parse; unsigned short buf[32]; int last_fn, last_ret, i, j; kio_addr_t ioaddr; @@ -350,17 +349,6 @@ static int tc574_config(struct pcmcia_device *link) DEBUG(0, "3c574_config(0x%p)\n", link); - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - link->io.IOAddrLines = 16; for (i = j = 0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; @@ -382,6 +370,10 @@ static int tc574_config(struct pcmcia_device *link) /* The 3c574 normally uses an EEPROM for configuration info, including the hardware address. The future products may include a modem chip and put the address in the CIS. */ + tuple.Attributes = 0; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; tuple.DesiredTuple = 0x88; if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) { pcmcia_get_tuple_data(link, &tuple); @@ -397,12 +389,9 @@ static int tc574_config(struct pcmcia_device *link) goto failed; } } - tuple.DesiredTuple = CISTPL_VERS_1; - if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS && - pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS && - pcmcia_parse_tuple(link, &tuple, &parse) == CS_SUCCESS) { - cardname = parse.version_1.str + parse.version_1.ofs[1]; - } else + if (link->prod_id[1]) + cardname = link->prod_id[1]; + else cardname = "3Com 3c574"; { diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 231fa2c9ec6..1e73ff7d5d8 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -253,7 +253,6 @@ static int tc589_config(struct pcmcia_device *link) struct net_device *dev = link->priv; struct el3_private *lp = netdev_priv(dev); tuple_t tuple; - cisparse_t parse; u16 buf[32], *phys_addr; int last_fn, last_ret, i, j, multi = 0, fifo; kio_addr_t ioaddr; @@ -263,26 +262,16 @@ static int tc589_config(struct pcmcia_device *link) phys_addr = (u16 *)dev->dev_addr; tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* Is this a 3c562? */ - tuple.DesiredTuple = CISTPL_MANFID; tuple.Attributes = TUPLE_RETURN_COMMON; - if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) && - (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS)) { - if (le16_to_cpu(buf[0]) != MANFID_3COM) + + /* Is this a 3c562? */ + if (link->manf_id != MANFID_3COM) printk(KERN_INFO "3c589_cs: hmmm, is this really a " "3Com card??\n"); - multi = (le16_to_cpu(buf[1]) == PRODID_3COM_3C562); - } + multi = (link->card_id == PRODID_3COM_3C562); /* For the 3c562, the base address must be xx00-xx7f */ link->io.IOAddrLines = 16; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 5ddd5742f77..6139048f811 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -299,11 +299,7 @@ static int axnet_config(struct pcmcia_device *link) tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; + /* don't trust the CIS on this; Linksys got it wrong */ link->conf.Present = 0x63; diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 48434d7924e..91f65e91cd5 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -249,12 +249,9 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int com20020_config(struct pcmcia_device *link) { struct arcnet_local *lp; - tuple_t tuple; - cisparse_t parse; com20020_dev_t *info; struct net_device *dev; int i, last_ret, last_fn; - u_char buf[64]; int ioaddr; info = link->priv; @@ -264,16 +261,6 @@ static int com20020_config(struct pcmcia_device *link) DEBUG(0, "com20020_config(0x%p)\n", link); - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1); i = !CS_SUCCESS; if (!link->io.BasePort1) diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 65f6fdf4372..0d7de617e53 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -342,7 +342,7 @@ static int fmvj18x_config(struct pcmcia_device *link) tuple_t tuple; cisparse_t parse; u_short buf[32]; - int i, last_fn, last_ret, ret; + int i, last_fn = 0, last_ret = 0, ret; kio_addr_t ioaddr; cardtype_t cardtype; char *card_name = "unknown"; @@ -350,21 +350,9 @@ static int fmvj18x_config(struct pcmcia_device *link) DEBUG(0, "fmvj18x_config(0x%p)\n", link); - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = (u_char *)buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - tuple.DesiredTuple = CISTPL_FUNCE; tuple.TupleOffset = 0; if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) { @@ -374,17 +362,12 @@ static int fmvj18x_config(struct pcmcia_device *link) CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigIndex = parse.cftable_entry.index; - tuple.DesiredTuple = CISTPL_MANFID; - if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - else - buf[0] = 0xffff; - switch (le16_to_cpu(buf[0])) { + switch (link->manf_id) { case MANFID_TDK: cardtype = TDK; - if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410 - || le16_to_cpu(buf[1]) == PRODID_TDK_NP9610 - || le16_to_cpu(buf[1]) == PRODID_TDK_MN3200) { + if (link->card_id == PRODID_TDK_GN3410 + || link->card_id == PRODID_TDK_NP9610 + || link->card_id == PRODID_TDK_MN3200) { /* MultiFunction Card */ link->conf.ConfigBase = 0x800; link->conf.ConfigIndex = 0x47; @@ -395,11 +378,11 @@ static int fmvj18x_config(struct pcmcia_device *link) cardtype = CONTEC; break; case MANFID_FUJITSU: - if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10302) + if (link->card_id == PRODID_FUJITSU_MBH10302) /* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302), but these are MBH10304 based card. */ cardtype = MBH10304; - else if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10304) + else if (link->card_id == PRODID_FUJITSU_MBH10304) cardtype = MBH10304; else cardtype = LA501; @@ -409,14 +392,9 @@ static int fmvj18x_config(struct pcmcia_device *link) } } else { /* old type card */ - tuple.DesiredTuple = CISTPL_MANFID; - if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - else - buf[0] = 0xffff; - switch (le16_to_cpu(buf[0])) { + switch (link->manf_id) { case MANFID_FUJITSU: - if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10304) { + if (link->card_id == PRODID_FUJITSU_MBH10304) { cardtype = XXX10304; /* MBH10304 with buggy CIS */ link->conf.ConfigIndex = 0x20; } else { diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index bc0ca41a054..a956a51d284 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -222,24 +222,12 @@ static int ibmtr_config(struct pcmcia_device *link) ibmtr_dev_t *info = link->priv; struct net_device *dev = info->dev; struct tok_info *ti = netdev_priv(dev); - tuple_t tuple; - cisparse_t parse; win_req_t req; memreq_t mem; int i, last_ret, last_fn; - u_char buf[64]; DEBUG(0, "ibmtr_config(0x%p)\n", link); - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; link->conf.ConfigIndex = 0x61; /* Determine if this is PRIMARY or ALTERNATE. */ diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index e77110e4c28..3b707747a81 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -656,23 +656,12 @@ static int nmclan_config(struct pcmcia_device *link) struct net_device *dev = link->priv; mace_private *lp = netdev_priv(dev); tuple_t tuple; - cisparse_t parse; u_char buf[64]; int i, last_ret, last_fn; kio_addr_t ioaddr; DEBUG(0, "nmclan_config(0x%p)\n", link); - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); @@ -686,6 +675,7 @@ static int nmclan_config(struct pcmcia_device *link) tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; + tuple.Attributes = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); memcpy(dev->dev_addr, tuple.TupleData, ETHER_ADDR_LEN); diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index c51cc5d8789..2b1238e2dbd 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -519,31 +519,15 @@ static int pcnet_config(struct pcmcia_device *link) tuple_t tuple; cisparse_t parse; int i, last_ret, last_fn, start_pg, stop_pg, cm_offset; - int manfid = 0, prodid = 0, has_shmem = 0; + int has_shmem = 0; u_short buf[64]; hw_info_t *hw_info; DEBUG(0, "pcnet_config(0x%p)\n", link); - tuple.Attributes = 0; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - tuple.DesiredTuple = CISTPL_MANFID; - tuple.Attributes = TUPLE_RETURN_COMMON; - if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) && - (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS)) { - manfid = le16_to_cpu(buf[0]); - prodid = le16_to_cpu(buf[1]); - } - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); @@ -589,8 +573,8 @@ static int pcnet_config(struct pcmcia_device *link) link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } - if ((manfid == MANFID_IBM) && - (prodid == PRODID_IBM_HOME_AND_AWAY)) + if ((link->manf_id == MANFID_IBM) && + (link->card_id == PRODID_IBM_HOME_AND_AWAY)) link->conf.ConfigIndex |= 0x10; CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); @@ -624,10 +608,10 @@ static int pcnet_config(struct pcmcia_device *link) info->flags = hw_info->flags; /* Check for user overrides */ info->flags |= (delay_output) ? DELAY_OUTPUT : 0; - if ((manfid == MANFID_SOCKET) && - ((prodid == PRODID_SOCKET_LPE) || - (prodid == PRODID_SOCKET_LPE_CF) || - (prodid == PRODID_SOCKET_EIO))) + if ((link->manf_id == MANFID_SOCKET) && + ((link->card_id == PRODID_SOCKET_LPE) || + (link->card_id == PRODID_SOCKET_LPE_CF) || + (link->card_id == PRODID_SOCKET_EIO))) info->flags &= ~USE_BIG_BUF; if (!use_big_buf) info->flags &= ~USE_BIG_BUF; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 20fcc357620..530df8883fe 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -560,16 +560,8 @@ static int mhz_setup(struct pcmcia_device *link) /* Read the station address from the CIS. It is stored as the last (fourth) string in the Version 1 Version/ID tuple. */ - tuple->DesiredTuple = CISTPL_VERS_1; - if (first_tuple(link, tuple, parse) != CS_SUCCESS) { - rc = -1; - goto free_cfg_mem; - } - /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ - if (next_tuple(link, tuple, parse) != CS_SUCCESS) - first_tuple(link, tuple, parse); - if (parse->version_1.ns > 3) { - station_addr = parse->version_1.str + parse->version_1.ofs[3]; + if (link->prod_id[3]) { + station_addr = link->prod_id[3]; if (cvt_ascii_address(dev, station_addr) == 0) { rc = 0; goto free_cfg_mem; @@ -744,15 +736,12 @@ static int smc_setup(struct pcmcia_device *link) } } /* Try the third string in the Version 1 Version/ID tuple. */ - tuple->DesiredTuple = CISTPL_VERS_1; - if (first_tuple(link, tuple, parse) != CS_SUCCESS) { - rc = -1; - goto free_cfg_mem; - } - station_addr = parse->version_1.str + parse->version_1.ofs[2]; - if (cvt_ascii_address(dev, station_addr) == 0) { - rc = 0; - goto free_cfg_mem; + if (link->prod_id[2]) { + station_addr = link->prod_id[2]; + if (cvt_ascii_address(dev, station_addr) == 0) { + rc = 0; + goto free_cfg_mem; + } } rc = -1; @@ -970,10 +959,6 @@ static int smc91c92_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); - struct smc_cfg_mem *cfg_mem; - tuple_t *tuple; - cisparse_t *parse; - u_char *buf; char *name; int i, j, rev; kio_addr_t ioaddr; @@ -981,30 +966,8 @@ static int smc91c92_config(struct pcmcia_device *link) DEBUG(0, "smc91c92_config(0x%p)\n", link); - cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); - if (!cfg_mem) - goto config_failed; - - tuple = &cfg_mem->tuple; - parse = &cfg_mem->parse; - buf = cfg_mem->buf; - - tuple->Attributes = tuple->TupleOffset = 0; - tuple->TupleData = (cisdata_t *)buf; - tuple->TupleDataMax = 64; - - tuple->DesiredTuple = CISTPL_CONFIG; - i = first_tuple(link, tuple, parse); - CS_EXIT_TEST(i, ParseTuple, config_failed); - link->conf.ConfigBase = parse->config.base; - link->conf.Present = parse->config.rmask[0]; - - tuple->DesiredTuple = CISTPL_MANFID; - tuple->Attributes = TUPLE_RETURN_COMMON; - if (first_tuple(link, tuple, parse) == CS_SUCCESS) { - smc->manfid = parse->manfid.manf; - smc->cardid = parse->manfid.card; - } + smc->manfid = link->manf_id; + smc->cardid = link->card_id; if ((smc->manfid == MANFID_OSITECH) && (smc->cardid != PRODID_OSITECH_SEVEN)) { @@ -1134,14 +1097,12 @@ static int smc91c92_config(struct pcmcia_device *link) printk(KERN_NOTICE " No MII transceivers found!\n"); } } - kfree(cfg_mem); return 0; config_undo: unregister_netdev(dev); config_failed: /* CS_EXIT_TEST() calls jump to here... */ smc91c92_release(link); - kfree(cfg_mem); return -ENODEV; } /* smc91c92_config */ diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index f3914f58d67..8478dca3d8d 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -332,6 +332,7 @@ static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id); */ typedef struct local_info_t { + struct net_device *dev; struct pcmcia_device *p_dev; dev_node_t node; struct net_device_stats stats; @@ -353,7 +354,7 @@ typedef struct local_info_t { */ static int do_start_xmit(struct sk_buff *skb, struct net_device *dev); static void do_tx_timeout(struct net_device *dev); -static void xirc2ps_tx_timeout_task(void *data); +static void xirc2ps_tx_timeout_task(struct work_struct *work); static struct net_device_stats *do_get_stats(struct net_device *dev); static void set_addresses(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -567,6 +568,7 @@ xirc2ps_probe(struct pcmcia_device *link) if (!dev) return -ENOMEM; local = netdev_priv(dev); + local->dev = dev; local->p_dev = link; link->priv = dev; @@ -591,7 +593,7 @@ xirc2ps_probe(struct pcmcia_device *link) #ifdef HAVE_TX_TIMEOUT dev->tx_timeout = do_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task, dev); + INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task); #endif return xirc2ps_config(link); @@ -707,22 +709,11 @@ set_card_type(struct pcmcia_device *link, const void *s) * Returns: true if this is a CE2 */ static int -has_ce2_string(struct pcmcia_device * link) +has_ce2_string(struct pcmcia_device * p_dev) { - tuple_t tuple; - cisparse_t parse; - u_char buf[256]; - - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = 254; - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_VERS_1; - if (!first_tuple(link, &tuple, &parse) && parse.version_1.ns > 2) { - if (strstr(parse.version_1.str + parse.version_1.ofs[2], "CE2")) - return 1; - } - return 0; + if (p_dev->prod_id[2] && strstr(p_dev->prod_id[2], "CE2")) + return 1; + return 0; } /**************** @@ -792,13 +783,6 @@ xirc2ps_config(struct pcmcia_device * link) goto failure; } - /* get configuration stuff */ - tuple.DesiredTuple = CISTPL_CONFIG; - if ((err=first_tuple(link, &tuple, &parse))) - goto cis_error; - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - /* get the ethernet address from the CIS */ tuple.DesiredTuple = CISTPL_FUNCE; for (err = first_tuple(link, &tuple, &parse); !err; @@ -1062,8 +1046,6 @@ xirc2ps_config(struct pcmcia_device * link) xirc2ps_release(link); return -ENODEV; - cis_error: - printk(KNOT_XIRC "unable to parse CIS\n"); failure: return -ENODEV; } /* xirc2ps_config */ @@ -1344,9 +1326,11 @@ xirc2ps_interrupt(int irq, void *dev_id) /*====================================================================*/ static void -xirc2ps_tx_timeout_task(void *data) +xirc2ps_tx_timeout_task(struct work_struct *work) { - struct net_device *dev = data; + local_info_t *local = + container_of(work, local_info_t, tx_timeout_task); + struct net_device *dev = local->dev; /* reset the card */ do_reset(dev,1); dev->trans_start = jiffies; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 88237bdb525..4044bb1ada8 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -397,7 +397,7 @@ out_unlock: EXPORT_SYMBOL(phy_start_aneg); -static void phy_change(void *data); +static void phy_change(struct work_struct *work); static void phy_timer(unsigned long data); /* phy_start_machine: @@ -555,7 +555,7 @@ int phy_start_interrupts(struct phy_device *phydev) { int err = 0; - INIT_WORK(&phydev->phy_queue, phy_change, phydev); + INIT_WORK(&phydev->phy_queue, phy_change); if (request_irq(phydev->irq, phy_interrupt, IRQF_SHARED, @@ -598,10 +598,11 @@ EXPORT_SYMBOL(phy_stop_interrupts); /* Scheduled by the phy_interrupt/timer to handle PHY changes */ -static void phy_change(void *data) +static void phy_change(struct work_struct *work) { int err; - struct phy_device *phydev = data; + struct phy_device *phydev = + container_of(work, struct phy_device, phy_queue); err = phy_disable_interrupts(phydev); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 71afb274498..6bb085f5443 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -138,9 +138,9 @@ static const unsigned int net_debug = NET_DEBUG; #define PLIP_NIBBLE_WAIT 3000 /* Bottom halves */ -static void plip_kick_bh(struct net_device *dev); -static void plip_bh(struct net_device *dev); -static void plip_timer_bh(struct net_device *dev); +static void plip_kick_bh(struct work_struct *work); +static void plip_bh(struct work_struct *work); +static void plip_timer_bh(struct work_struct *work); /* Interrupt handler */ static void plip_interrupt(int irq, void *dev_id); @@ -207,9 +207,10 @@ struct plip_local { struct net_local { struct net_device_stats enet_stats; + struct net_device *dev; struct work_struct immediate; - struct work_struct deferred; - struct work_struct timer; + struct delayed_work deferred; + struct delayed_work timer; struct plip_local snd_data; struct plip_local rcv_data; struct pardevice *pardev; @@ -306,11 +307,11 @@ plip_init_netdev(struct net_device *dev) nl->nibble = PLIP_NIBBLE_WAIT; /* Initialize task queue structures */ - INIT_WORK(&nl->immediate, (void (*)(void *))plip_bh, dev); - INIT_WORK(&nl->deferred, (void (*)(void *))plip_kick_bh, dev); + INIT_WORK(&nl->immediate, plip_bh); + INIT_DELAYED_WORK(&nl->deferred, plip_kick_bh); if (dev->irq == -1) - INIT_WORK(&nl->timer, (void (*)(void *))plip_timer_bh, dev); + INIT_DELAYED_WORK(&nl->timer, plip_timer_bh); spin_lock_init(&nl->lock); } @@ -319,9 +320,10 @@ plip_init_netdev(struct net_device *dev) This routine is kicked by do_timer(). Request `plip_bh' to be invoked. */ static void -plip_kick_bh(struct net_device *dev) +plip_kick_bh(struct work_struct *work) { - struct net_local *nl = netdev_priv(dev); + struct net_local *nl = + container_of(work, struct net_local, deferred.work); if (nl->is_deferred) schedule_work(&nl->immediate); @@ -362,9 +364,9 @@ static const plip_func connection_state_table[] = /* Bottom half handler of PLIP. */ static void -plip_bh(struct net_device *dev) +plip_bh(struct work_struct *work) { - struct net_local *nl = netdev_priv(dev); + struct net_local *nl = container_of(work, struct net_local, immediate); struct plip_local *snd = &nl->snd_data; struct plip_local *rcv = &nl->rcv_data; plip_func f; @@ -372,20 +374,21 @@ plip_bh(struct net_device *dev) nl->is_deferred = 0; f = connection_state_table[nl->connection]; - if ((r = (*f)(dev, nl, snd, rcv)) != OK - && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) { + if ((r = (*f)(nl->dev, nl, snd, rcv)) != OK + && (r = plip_bh_timeout_error(nl->dev, nl, snd, rcv, r)) != OK) { nl->is_deferred = 1; schedule_delayed_work(&nl->deferred, 1); } } static void -plip_timer_bh(struct net_device *dev) +plip_timer_bh(struct work_struct *work) { - struct net_local *nl = netdev_priv(dev); + struct net_local *nl = + container_of(work, struct net_local, timer.work); if (!(atomic_read (&nl->kill_timer))) { - plip_interrupt (-1, dev); + plip_interrupt (-1, nl->dev); schedule_delayed_work(&nl->timer, 1); } @@ -1284,6 +1287,7 @@ static void plip_attach (struct parport *port) } nl = netdev_priv(dev); + nl->dev = dev; nl->pardev = parport_register_device(port, name, plip_preempt, plip_wakeup, plip_interrupt, 0, dev); diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index ec640f6229a..d79d141a601 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2008,7 +2008,7 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) "%s: Another function issued a reset to the " "chip. ISR value = %x.\n", ndev->name, value); } - queue_work(qdev->workqueue, &qdev->reset_work); + queue_delayed_work(qdev->workqueue, &qdev->reset_work, 0); spin_unlock(&qdev->adapter_lock); } else if (value & ISP_IMR_DISABLE_CMPL_INT) { ql_disable_interrupts(qdev); @@ -3182,11 +3182,13 @@ static void ql3xxx_tx_timeout(struct net_device *ndev) /* * Wake up the worker to process this event. */ - queue_work(qdev->workqueue, &qdev->tx_timeout_work); + queue_delayed_work(qdev->workqueue, &qdev->tx_timeout_work, 0); } -static void ql_reset_work(struct ql3_adapter *qdev) +static void ql_reset_work(struct work_struct *work) { + struct ql3_adapter *qdev = + container_of(work, struct ql3_adapter, reset_work.work); struct net_device *ndev = qdev->ndev; u32 value; struct ql_tx_buf_cb *tx_cb; @@ -3278,9 +3280,12 @@ static void ql_reset_work(struct ql3_adapter *qdev) } } -static void ql_tx_timeout_work(struct ql3_adapter *qdev) +static void ql_tx_timeout_work(struct work_struct *work) { - ql_cycle_adapter(qdev,QL_DO_RESET); + struct ql3_adapter *qdev = + container_of(work, struct ql3_adapter, tx_timeout_work.work); + + ql_cycle_adapter(qdev, QL_DO_RESET); } static void ql_get_board_info(struct ql3_adapter *qdev) @@ -3459,9 +3464,8 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, netif_stop_queue(ndev); qdev->workqueue = create_singlethread_workqueue(ndev->name); - INIT_WORK(&qdev->reset_work, (void (*)(void *))ql_reset_work, qdev); - INIT_WORK(&qdev->tx_timeout_work, - (void (*)(void *))ql_tx_timeout_work, qdev); + INIT_DELAYED_WORK(&qdev->reset_work, ql_reset_work); + INIT_DELAYED_WORK(&qdev->tx_timeout_work, ql_tx_timeout_work); init_timer(&qdev->adapter_timer); qdev->adapter_timer.function = ql3xxx_timer; diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h index 65da2c0bfda..ea94de7fd07 100644 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -1186,8 +1186,8 @@ struct ql3_adapter { u32 numPorts; struct net_device_stats stats; struct workqueue_struct *workqueue; - struct work_struct reset_work; - struct work_struct tx_timeout_work; + struct delayed_work reset_work; + struct delayed_work tx_timeout_work; u32 max_frame_size; }; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 45d3ca43195..85a392fab5c 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -424,6 +424,7 @@ struct ring_info { struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; /* Index of PCI device */ + struct net_device *dev; struct net_device_stats stats; /* statistics of net device */ spinlock_t lock; /* spin lock flag */ u32 msg_enable; @@ -455,7 +456,7 @@ struct rtl8169_private { void (*phy_reset_enable)(void __iomem *); unsigned int (*phy_reset_pending)(void __iomem *); unsigned int (*link_ok)(void __iomem *); - struct work_struct task; + struct delayed_work task; unsigned wol_enabled : 1; }; @@ -1510,6 +1511,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); + tp->dev = dev; tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); /* enable device (incl. PCI PM wakeup and hotplug setup) */ @@ -1782,7 +1784,7 @@ static int rtl8169_open(struct net_device *dev) if (retval < 0) goto err_free_rx; - INIT_WORK(&tp->task, NULL, dev); + INIT_DELAYED_WORK(&tp->task, NULL); rtl8169_hw_start(dev); @@ -2105,11 +2107,11 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp) tp->cur_tx = tp->dirty_tx = 0; } -static void rtl8169_schedule_work(struct net_device *dev, void (*task)(void *)) +static void rtl8169_schedule_work(struct net_device *dev, work_func_t task) { struct rtl8169_private *tp = netdev_priv(dev); - PREPARE_WORK(&tp->task, task, dev); + PREPARE_DELAYED_WORK(&tp->task, task); schedule_delayed_work(&tp->task, 4); } @@ -2128,9 +2130,11 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev) netif_poll_enable(dev); } -static void rtl8169_reinit_task(void *_data) +static void rtl8169_reinit_task(struct work_struct *work) { - struct net_device *dev = _data; + struct rtl8169_private *tp = + container_of(work, struct rtl8169_private, task.work); + struct net_device *dev = tp->dev; int ret; if (netif_running(dev)) { @@ -2153,10 +2157,11 @@ static void rtl8169_reinit_task(void *_data) } } -static void rtl8169_reset_task(void *_data) +static void rtl8169_reset_task(struct work_struct *work) { - struct net_device *dev = _data; - struct rtl8169_private *tp = netdev_priv(dev); + struct rtl8169_private *tp = + container_of(work, struct rtl8169_private, task.work); + struct net_device *dev = tp->dev; if (!netif_running(dev)) return; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 33569ec9dbf..250cdbeefdf 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5872,9 +5872,9 @@ static void s2io_tasklet(unsigned long dev_addr) * Description: Sets the link status for the adapter */ -static void s2io_set_link(unsigned long data) +static void s2io_set_link(struct work_struct *work) { - nic_t *nic = (nic_t *) data; + nic_t *nic = container_of(work, nic_t, set_link_task); struct net_device *dev = nic->dev; XENA_dev_config_t __iomem *bar0 = nic->bar0; register u64 val64; @@ -6379,10 +6379,10 @@ static int s2io_card_up(nic_t * sp) * spin lock. */ -static void s2io_restart_nic(unsigned long data) +static void s2io_restart_nic(struct work_struct *work) { - struct net_device *dev = (struct net_device *) data; - nic_t *sp = dev->priv; + nic_t *sp = container_of(work, nic_t, rst_timer_task); + struct net_device *dev = sp->dev; s2io_card_down(sp); if (s2io_card_up(sp)) { @@ -6992,10 +6992,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->tx_timeout = &s2io_tx_watchdog; dev->watchdog_timeo = WATCH_DOG_TIMEOUT; - INIT_WORK(&sp->rst_timer_task, - (void (*)(void *)) s2io_restart_nic, dev); - INIT_WORK(&sp->set_link_task, - (void (*)(void *)) s2io_set_link, sp); + INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); + INIT_WORK(&sp->set_link_task, s2io_set_link); pci_save_state(sp->pdev); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 12b719f4d00..3b0bafd273c 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -1000,7 +1000,7 @@ s2io_msix_fifo_handle(int irq, void *dev_id); static irqreturn_t s2io_isr(int irq, void *dev_id); static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); static const struct ethtool_ops netdev_ethtool_ops; -static void s2io_set_link(unsigned long data); +static void s2io_set_link(struct work_struct *work); static int s2io_set_swapper(nic_t * sp); static void s2io_card_down(nic_t *nic); static int s2io_card_up(nic_t *nic); diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index d9d0a3a3c55..0d6c95c7aed 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -750,7 +750,7 @@ int __init init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(dev_seeq); release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT); diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index aaba458584f..b70ed79d412 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -280,6 +280,7 @@ enum sis190_feature { struct sis190_private { void __iomem *mmio_addr; struct pci_dev *pci_dev; + struct net_device *dev; struct net_device_stats stats; spinlock_t lock; u32 rx_buf_sz; @@ -897,10 +898,11 @@ static void sis190_hw_start(struct net_device *dev) netif_start_queue(dev); } -static void sis190_phy_task(void * data) +static void sis190_phy_task(struct work_struct *work) { - struct net_device *dev = data; - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = + container_of(work, struct sis190_private, phy_task); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->mmio_addr; int phy_id = tp->mii_if.phy_id; u16 val; @@ -1047,7 +1049,7 @@ static int sis190_open(struct net_device *dev) if (rc < 0) goto err_free_rx_1; - INIT_WORK(&tp->phy_task, sis190_phy_task, dev); + INIT_WORK(&tp->phy_task, sis190_phy_task); sis190_request_timer(dev); @@ -1436,6 +1438,7 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev) SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); + tp->dev = dev; tp->msg_enable = netif_msg_init(debug.msg_enable, SIS190_MSG_DEFAULT); rc = pci_enable_device(pdev); @@ -1798,7 +1801,7 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, sis190_init_rxfilter(dev); - INIT_WORK(&tp->phy_task, sis190_phy_task, dev); + INIT_WORK(&tp->phy_task, sis190_phy_task); dev->open = sis190_open; dev->stop = sis190_close; diff --git a/drivers/net/sk98lin/skgesirq.c b/drivers/net/sk98lin/skgesirq.c index ab66d80a445..3e7aa49afd0 100644 --- a/drivers/net/sk98lin/skgesirq.c +++ b/drivers/net/sk98lin/skgesirq.c @@ -1319,7 +1319,7 @@ SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &Isrc); #ifdef xDEBUG - if ((Isrc & ~(PHY_B_IS_HCT | PHY_B_IS_LCT) == + if ((Isrc & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) == (PHY_B_IS_SCR_S_ER | PHY_B_IS_RRS_CHANGE | PHY_B_IS_LRS_CHANGE)) { SK_U32 Stat1, Stat2, Stat3; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 5513907e839..b60f0451f6c 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -1327,10 +1327,11 @@ static void xm_check_link(struct net_device *dev) * Since internal PHY is wired to a level triggered pin, can't * get an interrupt when carrier is detected. */ -static void xm_link_timer(void *arg) +static void xm_link_timer(struct work_struct *work) { - struct net_device *dev = arg; - struct skge_port *skge = netdev_priv(arg); + struct skge_port *skge = + container_of(work, struct skge_port, link_thread.work); + struct net_device *dev = skge->netdev; struct skge_hw *hw = skge->hw; int port = skge->port; @@ -3072,9 +3073,9 @@ static void skge_error_irq(struct skge_hw *hw) * because accessing phy registers requires spin wait which might * cause excess interrupt latency. */ -static void skge_extirq(void *arg) +static void skge_extirq(struct work_struct *work) { - struct skge_hw *hw = arg; + struct skge_hw *hw = container_of(work, struct skge_hw, phy_work); int port; mutex_lock(&hw->phy_mutex); @@ -3456,7 +3457,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, skge->port = port; /* Only used for Genesis XMAC */ - INIT_WORK(&skge->link_thread, xm_link_timer, dev); + INIT_DELAYED_WORK(&skge->link_thread, xm_link_timer); if (hw->chip_id != CHIP_ID_GENESIS) { dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; @@ -3543,7 +3544,7 @@ static int __devinit skge_probe(struct pci_dev *pdev, hw->pdev = pdev; mutex_init(&hw->phy_mutex); - INIT_WORK(&hw->phy_work, skge_extirq, hw); + INIT_WORK(&hw->phy_work, skge_extirq); spin_lock_init(&hw->hw_lock); hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 537c0aaa1db..f6223c533c0 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -389,10 +389,10 @@ enum { /* Packet Arbiter Registers */ /* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */ enum { - PA_CLR_TO_TX2 = 1<<13, /* Clear IRQ Packet Timeout TX2 */ - PA_CLR_TO_TX1 = 1<<12, /* Clear IRQ Packet Timeout TX1 */ - PA_CLR_TO_RX2 = 1<<11, /* Clear IRQ Packet Timeout RX2 */ - PA_CLR_TO_RX1 = 1<<10, /* Clear IRQ Packet Timeout RX1 */ + PA_CLR_TO_TX2 = 1<<13,/* Clear IRQ Packet Timeout TX2 */ + PA_CLR_TO_TX1 = 1<<12,/* Clear IRQ Packet Timeout TX1 */ + PA_CLR_TO_RX2 = 1<<11,/* Clear IRQ Packet Timeout RX2 */ + PA_CLR_TO_RX1 = 1<<10,/* Clear IRQ Packet Timeout RX1 */ PA_ENA_TO_TX2 = 1<<9, /* Enable Timeout Timer TX2 */ PA_DIS_TO_TX2 = 1<<8, /* Disable Timeout Timer TX2 */ PA_ENA_TO_TX1 = 1<<7, /* Enable Timeout Timer TX1 */ @@ -481,14 +481,14 @@ enum { /* RAM Buffer Register Offsets */ enum { - RB_START = 0x00,/* 32 bit RAM Buffer Start Address */ + RB_START= 0x00,/* 32 bit RAM Buffer Start Address */ RB_END = 0x04,/* 32 bit RAM Buffer End Address */ RB_WP = 0x08,/* 32 bit RAM Buffer Write Pointer */ RB_RP = 0x0c,/* 32 bit RAM Buffer Read Pointer */ - RB_RX_UTPP = 0x10,/* 32 bit Rx Upper Threshold, Pause Packet */ - RB_RX_LTPP = 0x14,/* 32 bit Rx Lower Threshold, Pause Packet */ - RB_RX_UTHP = 0x18,/* 32 bit Rx Upper Threshold, High Prio */ - RB_RX_LTHP = 0x1c,/* 32 bit Rx Lower Threshold, High Prio */ + RB_RX_UTPP= 0x10,/* 32 bit Rx Upper Threshold, Pause Packet */ + RB_RX_LTPP= 0x14,/* 32 bit Rx Lower Threshold, Pause Packet */ + RB_RX_UTHP= 0x18,/* 32 bit Rx Upper Threshold, High Prio */ + RB_RX_LTHP= 0x1c,/* 32 bit Rx Lower Threshold, High Prio */ /* 0x10 - 0x1f: reserved at Tx RAM Buffer Registers */ RB_PC = 0x20,/* 32 bit RAM Buffer Packet Counter */ RB_LEV = 0x24,/* 32 bit RAM Buffer Level Register */ @@ -532,7 +532,7 @@ enum { PHY_ADDR_MARV = 0, }; -#define RB_ADDR(offs, queue) (B16_RAM_REGS + (queue) + (offs)) +#define RB_ADDR(offs, queue) ((u16)B16_RAM_REGS + (u16)(queue) + (offs)) /* Receive MAC FIFO, Receive LED, and Link_Sync regs (GENESIS only) */ enum { @@ -578,15 +578,15 @@ enum { MFF_DIS_TIST = 1<<2, /* Disable Time Stamp Gener */ MFF_CLR_INTIST = 1<<1, /* Clear IRQ No Time Stamp */ MFF_CLR_INSTAT = 1<<0, /* Clear IRQ No Status */ -#define MFF_RX_CTRL_DEF MFF_ENA_TIM_PAT + MFF_RX_CTRL_DEF = MFF_ENA_TIM_PAT, }; /* TX_MFF_CTRL1 16 bit Transmit MAC FIFO Control Reg 1 */ enum { - MFF_CLR_PERR = 1<<15, /* Clear Parity Error IRQ */ - /* Bit 14: reserved */ - MFF_ENA_PKT_REC = 1<<13, /* Enable Packet Recovery */ - MFF_DIS_PKT_REC = 1<<12, /* Disable Packet Recovery */ + MFF_CLR_PERR = 1<<15, /* Clear Parity Error IRQ */ + + MFF_ENA_PKT_REC = 1<<13, /* Enable Packet Recovery */ + MFF_DIS_PKT_REC = 1<<12, /* Disable Packet Recovery */ MFF_ENA_W4E = 1<<7, /* Enable Wait for Empty */ MFF_DIS_W4E = 1<<6, /* Disable Wait for Empty */ @@ -595,9 +595,10 @@ enum { MFF_DIS_LOOPB = 1<<2, /* Disable Loopback */ MFF_CLR_MAC_RST = 1<<1, /* Clear XMAC Reset */ MFF_SET_MAC_RST = 1<<0, /* Set XMAC Reset */ + + MFF_TX_CTRL_DEF = MFF_ENA_PKT_REC | (u16) MFF_ENA_TIM_PAT | MFF_ENA_FLUSH, }; -#define MFF_TX_CTRL_DEF (MFF_ENA_PKT_REC | MFF_ENA_TIM_PAT | MFF_ENA_FLUSH) /* RX_MFF_TST2 8 bit Receive MAC FIFO Test Register 2 */ /* TX_MFF_TST2 8 bit Transmit MAC FIFO Test Register 2 */ @@ -1304,8 +1305,8 @@ enum { /* special defines for FIBER (88E1011S only) */ enum { - PHY_M_AN_ASP_X = 1<<8, /* Asymmetric Pause */ - PHY_M_AN_PC_X = 1<<7, /* MAC Pause implemented */ + PHY_M_AN_ASP_X = 1<<8, /* Asymmetric Pause */ + PHY_M_AN_PC_X = 1<<7, /* MAC Pause implemented */ PHY_M_AN_1000X_AHD = 1<<6, /* Advertise 10000Base-X Half Duplex */ PHY_M_AN_1000X_AFD = 1<<5, /* Advertise 10000Base-X Full Duplex */ }; @@ -1320,7 +1321,7 @@ enum { /***** PHY_MARV_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ enum { - PHY_M_1000C_TEST = 7<<13,/* Bit 15..13: Test Modes */ + PHY_M_1000C_TEST= 7<<13,/* Bit 15..13: Test Modes */ PHY_M_1000C_MSE = 1<<12, /* Manual Master/Slave Enable */ PHY_M_1000C_MSC = 1<<11, /* M/S Configuration (1=Master) */ PHY_M_1000C_MPD = 1<<10, /* Multi-Port Device */ @@ -1349,7 +1350,7 @@ enum { PHY_M_PC_EN_DET_PLUS = 3<<8, /* Energy Detect Plus (Mode 2) */ }; -#define PHY_M_PC_MDI_XMODE(x) (((x)<<5) & PHY_M_PC_MDIX_MSK) +#define PHY_M_PC_MDI_XMODE(x) ((((u16)(x)<<5) & PHY_M_PC_MDIX_MSK) enum { PHY_M_PC_MAN_MDI = 0, /* 00 = Manual MDI configuration */ @@ -1432,24 +1433,24 @@ enum { PHY_M_EC_DIS_LINK_P = 1<<12, /* Disable Link Pulses (88E1111 only) */ PHY_M_EC_M_DSC_MSK = 3<<10, /* Bit 11..10: Master Downshift Counter */ /* (88E1011 only) */ - PHY_M_EC_S_DSC_MSK = 3<<8,/* Bit 9.. 8: Slave Downshift Counter */ + PHY_M_EC_S_DSC_MSK = 3<<8, /* Bit 9.. 8: Slave Downshift Counter */ /* (88E1011 only) */ - PHY_M_EC_M_DSC_MSK2 = 7<<9,/* Bit 11.. 9: Master Downshift Counter */ + PHY_M_EC_M_DSC_MSK2 = 7<<9, /* Bit 11.. 9: Master Downshift Counter */ /* (88E1111 only) */ - PHY_M_EC_DOWN_S_ENA = 1<<8, /* Downshift Enable (88E1111 only) */ + PHY_M_EC_DOWN_S_ENA = 1<<8, /* Downshift Enable (88E1111 only) */ /* !!! Errata in spec. (1 = disable) */ - PHY_M_EC_RX_TIM_CT = 1<<7, /* RGMII Rx Timing Control*/ - PHY_M_EC_MAC_S_MSK = 7<<4,/* Bit 6.. 4: Def. MAC interface speed */ - PHY_M_EC_FIB_AN_ENA = 1<<3, /* Fiber Auto-Neg. Enable (88E1011S only) */ - PHY_M_EC_DTE_D_ENA = 1<<2, /* DTE Detect Enable (88E1111 only) */ - PHY_M_EC_TX_TIM_CT = 1<<1, /* RGMII Tx Timing Control */ - PHY_M_EC_TRANS_DIS = 1<<0, /* Transmitter Disable (88E1111 only) */}; - -#define PHY_M_EC_M_DSC(x) ((x)<<10) /* 00=1x; 01=2x; 10=3x; 11=4x */ -#define PHY_M_EC_S_DSC(x) ((x)<<8) /* 00=dis; 01=1x; 10=2x; 11=3x */ -#define PHY_M_EC_MAC_S(x) ((x)<<4) /* 01X=0; 110=2.5; 111=25 (MHz) */ - -#define PHY_M_EC_M_DSC_2(x) ((x)<<9) /* 000=1x; 001=2x; 010=3x; 011=4x */ + PHY_M_EC_RX_TIM_CT = 1<<7, /* RGMII Rx Timing Control*/ + PHY_M_EC_MAC_S_MSK = 7<<4, /* Bit 6.. 4: Def. MAC interface speed */ + PHY_M_EC_FIB_AN_ENA = 1<<3, /* Fiber Auto-Neg. Enable (88E1011S only) */ + PHY_M_EC_DTE_D_ENA = 1<<2, /* DTE Detect Enable (88E1111 only) */ + PHY_M_EC_TX_TIM_CT = 1<<1, /* RGMII Tx Timing Control */ + PHY_M_EC_TRANS_DIS = 1<<0, /* Transmitter Disable (88E1111 only) */}; + +#define PHY_M_EC_M_DSC(x) ((u16)(x)<<10) /* 00=1x; 01=2x; 10=3x; 11=4x */ +#define PHY_M_EC_S_DSC(x) ((u16)(x)<<8) /* 00=dis; 01=1x; 10=2x; 11=3x */ +#define PHY_M_EC_MAC_S(x) ((u16)(x)<<4) /* 01X=0; 110=2.5; 111=25 (MHz) */ + +#define PHY_M_EC_M_DSC_2(x) ((u16)(x)<<9) /* 000=1x; 001=2x; 010=3x; 011=4x */ /* 100=5x; 101=6x; 110=7x; 111=8x */ enum { MAC_TX_CLK_0_MHZ = 2, @@ -1468,10 +1469,12 @@ enum { PHY_M_LEDC_LK_C_MSK = 7<<3,/* Bit 5.. 3: Link Control Mask */ /* (88E1111 only) */ }; +#define PHY_M_LED_PULS_DUR(x) (((u16)(x)<<12) & PHY_M_LEDC_PULS_MSK) +#define PHY_M_LED_BLINK_RT(x) (((u16)(x)<<8) & PHY_M_LEDC_BL_R_MSK) enum { - PHY_M_LEDC_LINK_MSK = 3<<3,/* Bit 4.. 3: Link Control Mask */ - /* (88E1011 only) */ + PHY_M_LEDC_LINK_MSK = 3<<3, /* Bit 4.. 3: Link Control Mask */ + /* (88E1011 only) */ PHY_M_LEDC_DP_CTRL = 1<<2, /* Duplex Control */ PHY_M_LEDC_DP_C_MSB = 1<<2, /* Duplex Control (MSB, 88E1111 only) */ PHY_M_LEDC_RX_CTRL = 1<<1, /* Rx Activity / Link */ @@ -1479,27 +1482,24 @@ enum { PHY_M_LEDC_TX_C_MSB = 1<<0, /* Tx Control (MSB, 88E1111 only) */ }; -#define PHY_M_LED_PULS_DUR(x) (((x)<<12) & PHY_M_LEDC_PULS_MSK) - enum { - PULS_NO_STR = 0,/* no pulse stretching */ - PULS_21MS = 1,/* 21 ms to 42 ms */ - PULS_42MS = 2,/* 42 ms to 84 ms */ - PULS_84MS = 3,/* 84 ms to 170 ms */ - PULS_170MS = 4,/* 170 ms to 340 ms */ - PULS_340MS = 5,/* 340 ms to 670 ms */ - PULS_670MS = 6,/* 670 ms to 1.3 s */ - PULS_1300MS = 7,/* 1.3 s to 2.7 s */ + PULS_NO_STR = 0, /* no pulse stretching */ + PULS_21MS = 1, /* 21 ms to 42 ms */ + PULS_42MS = 2, /* 42 ms to 84 ms */ + PULS_84MS = 3, /* 84 ms to 170 ms */ + PULS_170MS = 4, /* 170 ms to 340 ms */ + PULS_340MS = 5, /* 340 ms to 670 ms */ + PULS_670MS = 6, /* 670 ms to 1.3 s */ + PULS_1300MS = 7, /* 1.3 s to 2.7 s */ }; -#define PHY_M_LED_BLINK_RT(x) (((x)<<8) & PHY_M_LEDC_BL_R_MSK) enum { - BLINK_42MS = 0,/* 42 ms */ - BLINK_84MS = 1,/* 84 ms */ - BLINK_170MS = 2,/* 170 ms */ - BLINK_340MS = 3,/* 340 ms */ - BLINK_670MS = 4,/* 670 ms */ + BLINK_42MS = 0, /* 42 ms */ + BLINK_84MS = 1, /* 84 ms */ + BLINK_170MS = 2, /* 170 ms */ + BLINK_340MS = 3, /* 340 ms */ + BLINK_670MS = 4, /* 670 ms */ }; /***** PHY_MARV_LED_OVER 16 bit r/w Manual LED Override Reg *****/ @@ -1525,7 +1525,7 @@ enum { PHY_M_EC2_FO_IMPED = 1<<5, /* Fiber Output Impedance */ PHY_M_EC2_FO_M_CLK = 1<<4, /* Fiber Mode Clock Enable */ PHY_M_EC2_FO_BOOST = 1<<3, /* Fiber Output Boost */ - PHY_M_EC2_FO_AM_MSK = 7,/* Bit 2.. 0: Fiber Output Amplitude */ + PHY_M_EC2_FO_AM_MSK = 7, /* Bit 2.. 0: Fiber Output Amplitude */ }; /***** PHY_MARV_EXT_P_STAT 16 bit r/w Ext. PHY Specific Status *****/ @@ -1550,7 +1550,7 @@ enum { PHY_M_CABD_DIS_WAIT = 1<<15, /* Disable Waiting Period (Page 1) */ /* (88E1111 only) */ PHY_M_CABD_STAT_MSK = 3<<13, /* Bit 14..13: Status Mask */ - PHY_M_CABD_AMPL_MSK = 0x1f<<8,/* Bit 12.. 8: Amplitude Mask */ + PHY_M_CABD_AMPL_MSK = 0x1f<<8, /* Bit 12.. 8: Amplitude Mask */ /* (88E1111 only) */ PHY_M_CABD_DIST_MSK = 0xff, /* Bit 7.. 0: Distance Mask */ }; @@ -1605,9 +1605,9 @@ enum { /***** PHY_MARV_PHY_CTRL (page 3) 16 bit r/w LED Control Reg. *****/ enum { - PHY_M_LEDC_LOS_MSK = 0xf<<12,/* Bit 15..12: LOS LED Ctrl. Mask */ + PHY_M_LEDC_LOS_MSK = 0xf<<12, /* Bit 15..12: LOS LED Ctrl. Mask */ PHY_M_LEDC_INIT_MSK = 0xf<<8, /* Bit 11.. 8: INIT LED Ctrl. Mask */ - PHY_M_LEDC_STA1_MSK = 0xf<<4,/* Bit 7.. 4: STAT1 LED Ctrl. Mask */ + PHY_M_LEDC_STA1_MSK = 0xf<<4, /* Bit 7.. 4: STAT1 LED Ctrl. Mask */ PHY_M_LEDC_STA0_MSK = 0xf, /* Bit 3.. 0: STAT0 LED Ctrl. Mask */ }; @@ -1804,8 +1804,8 @@ enum { /* GM_SMI_CTRL 16 bit r/w SMI Control Register */ enum { - GM_SMI_CT_PHY_A_MSK = 0x1f<<11,/* Bit 15..11: PHY Device Address */ - GM_SMI_CT_REG_A_MSK = 0x1f<<6,/* Bit 10.. 6: PHY Register Address */ + GM_SMI_CT_PHY_A_MSK = 0x1f<<11, /* Bit 15..11: PHY Device Address */ + GM_SMI_CT_REG_A_MSK = 0x1f<<6, /* Bit 10.. 6: PHY Register Address */ GM_SMI_CT_OP_RD = 1<<5, /* Bit 5: OpCode Read (0=Write)*/ GM_SMI_CT_RD_VAL = 1<<4, /* Bit 4: Read Valid (Read completed) */ GM_SMI_CT_BUSY = 1<<3, /* Bit 3: Busy (Operation in progress) */ @@ -1875,9 +1875,9 @@ enum { /* TX_GMF_CTRL_T 32 bit Tx GMAC FIFO Control/Test */ enum { - GMF_WSP_TST_ON = 1<<18,/* Write Shadow Pointer Test On */ - GMF_WSP_TST_OFF = 1<<17,/* Write Shadow Pointer Test Off */ - GMF_WSP_STEP = 1<<16,/* Write Shadow Pointer Step/Increment */ + GMF_WSP_TST_ON = 1<<18, /* Write Shadow Pointer Test On */ + GMF_WSP_TST_OFF = 1<<17, /* Write Shadow Pointer Test Off */ + GMF_WSP_STEP = 1<<16, /* Write Shadow Pointer Step/Increment */ GMF_CLI_TX_FU = 1<<6, /* Clear IRQ Tx FIFO Underrun */ GMF_CLI_TX_FC = 1<<5, /* Clear IRQ Tx Frame Complete */ @@ -2111,18 +2111,18 @@ enum { /* XM_MMU_CMD 16 bit r/w MMU Command Register */ enum { - XM_MMU_PHY_RDY = 1<<12,/* Bit 12: PHY Read Ready */ - XM_MMU_PHY_BUSY = 1<<11,/* Bit 11: PHY Busy */ - XM_MMU_IGN_PF = 1<<10,/* Bit 10: Ignore Pause Frame */ - XM_MMU_MAC_LB = 1<<9, /* Bit 9: Enable MAC Loopback */ - XM_MMU_FRC_COL = 1<<7, /* Bit 7: Force Collision */ - XM_MMU_SIM_COL = 1<<6, /* Bit 6: Simulate Collision */ - XM_MMU_NO_PRE = 1<<5, /* Bit 5: No MDIO Preamble */ - XM_MMU_GMII_FD = 1<<4, /* Bit 4: GMII uses Full Duplex */ - XM_MMU_RAT_CTRL = 1<<3, /* Bit 3: Enable Rate Control */ - XM_MMU_GMII_LOOP= 1<<2, /* Bit 2: PHY is in Loopback Mode */ - XM_MMU_ENA_RX = 1<<1, /* Bit 1: Enable Receiver */ - XM_MMU_ENA_TX = 1<<0, /* Bit 0: Enable Transmitter */ + XM_MMU_PHY_RDY = 1<<12, /* Bit 12: PHY Read Ready */ + XM_MMU_PHY_BUSY = 1<<11, /* Bit 11: PHY Busy */ + XM_MMU_IGN_PF = 1<<10, /* Bit 10: Ignore Pause Frame */ + XM_MMU_MAC_LB = 1<<9, /* Bit 9: Enable MAC Loopback */ + XM_MMU_FRC_COL = 1<<7, /* Bit 7: Force Collision */ + XM_MMU_SIM_COL = 1<<6, /* Bit 6: Simulate Collision */ + XM_MMU_NO_PRE = 1<<5, /* Bit 5: No MDIO Preamble */ + XM_MMU_GMII_FD = 1<<4, /* Bit 4: GMII uses Full Duplex */ + XM_MMU_RAT_CTRL = 1<<3, /* Bit 3: Enable Rate Control */ + XM_MMU_GMII_LOOP= 1<<2, /* Bit 2: PHY is in Loopback Mode */ + XM_MMU_ENA_RX = 1<<1, /* Bit 1: Enable Receiver */ + XM_MMU_ENA_TX = 1<<0, /* Bit 0: Enable Transmitter */ }; @@ -2456,7 +2456,7 @@ struct skge_port { struct net_device_stats net_stats; - struct work_struct link_thread; + struct delayed_work link_thread; enum pause_control flow_control; enum pause_status flow_status; u8 rx_csum; @@ -2506,7 +2506,7 @@ static inline void skge_write8(const struct skge_hw *hw, int reg, u8 val) } /* MAC Related Registers inside the device. */ -#define SK_REG(port,reg) (((port)<<7)+(reg)) +#define SK_REG(port,reg) (((port)<<7)+(u16)(reg)) #define SK_XMAC_REG(port, reg) \ ((BASE_XMAC_1 + (port) * (BASE_XMAC_2 - BASE_XMAC_1)) | (reg) << 1) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 842abd9396c..fb1d2c30c1b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -100,33 +100,32 @@ module_param(idle_timeout, int, 0); MODULE_PARM_DESC(idle_timeout, "Watchdog timer for lost interrupts (ms)"); static const struct pci_device_id sky2_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, - { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, + { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, /* SK-9Sxx */ + { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, /* DGE-560T */ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) }, /* DGE-550SX */ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B02) }, /* DGE-560SX */ - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4343) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4344) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4345) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4346) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4347) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4350) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, /* 88E8021 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, /* 88E8022 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, /* 88E8061 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4343) }, /* 88E8062 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4344) }, /* 88E8021 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4345) }, /* 88E8022 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4346) }, /* 88E8061 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4347) }, /* 88E8062 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4350) }, /* 88E8035 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) }, /* 88E8036 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, /* 88E8038 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) }, /* 88E8052 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */ { 0 } }; @@ -522,7 +521,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */ ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL; /* turn off the Rx LED (LED_RX) */ - ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); + ledover &= ~PHY_M_LED_MO_RX; } if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_A1) { @@ -545,7 +544,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { /* turn on 100 Mbps LED (LED_LINK100) */ - ledover |= PHY_M_LED_MO_100(MO_LED_ON); + ledover |= PHY_M_LED_MO_100; } if (ledover) @@ -697,10 +696,15 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) } -/* Assign Ram Buffer allocation in units of 64bit (8 bytes) */ -static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 end) +/* Assign Ram Buffer allocation to queue */ +static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 space) { - pr_debug(PFX "q %d %#x %#x\n", q, start, end); + u32 end; + + /* convert from K bytes to qwords used for hw register */ + start *= 1024/8; + space *= 1024/8; + end = start + space - 1; sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR); sky2_write32(hw, RB_ADDR(q, RB_START), start); @@ -709,7 +713,6 @@ static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 end) sky2_write32(hw, RB_ADDR(q, RB_RP), start); if (q == Q_R1 || q == Q_R2) { - u32 space = end - start + 1; u32 tp = space - space/4; /* On receive queue's set the thresholds @@ -1059,11 +1062,16 @@ static int sky2_rx_start(struct sky2_port *sky2) sky2->rx_put = sky2->rx_next = 0; sky2_qset(hw, rxq); + /* On PCI express lowering the watermark gives better performance */ + if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) + sky2_write32(hw, Q_ADDR(rxq, Q_WM), BMU_WM_PEX); + + /* These chips have no ram buffer? + * MAC Rx RAM Read is controlled by hardware */ if (hw->chip_id == CHIP_ID_YUKON_EC_U && - (hw->chip_rev == CHIP_REV_YU_EC_U_A1 || hw->chip_rev == CHIP_REV_YU_EC_U_B0)) { - /* MAC Rx RAM Read is controlled by hardware */ + (hw->chip_rev == CHIP_REV_YU_EC_U_A1 + || hw->chip_rev == CHIP_REV_YU_EC_U_B0)) sky2_write32(hw, Q_ADDR(rxq, Q_F), F_M_RX_RAM_DIS); - } sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1); @@ -1139,7 +1147,7 @@ static int sky2_up(struct net_device *dev) struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; - u32 ramsize, rxspace, imask; + u32 ramsize, imask; int cap, err = -ENOMEM; struct net_device *otherdev = hw->dev[sky2->port^1]; @@ -1192,20 +1200,25 @@ static int sky2_up(struct net_device *dev) sky2_mac_init(hw, port); - /* Determine available ram buffer space in qwords. */ - ramsize = sky2_read8(hw, B2_E_0) * 4096/8; + /* Register is number of 4K blocks on internal RAM buffer. */ + ramsize = sky2_read8(hw, B2_E_0) * 4; + printk(KERN_INFO PFX "%s: ram buffer %dK\n", dev->name, ramsize); - if (ramsize > 6*1024/8) - rxspace = ramsize - (ramsize + 2) / 3; - else - rxspace = ramsize / 2; + if (ramsize > 0) { + u32 rxspace; - sky2_ramset(hw, rxqaddr[port], 0, rxspace-1); - sky2_ramset(hw, txqaddr[port], rxspace, ramsize-1); + if (ramsize < 16) + rxspace = ramsize / 2; + else + rxspace = 8 + (2*(ramsize - 16))/3; + + sky2_ramset(hw, rxqaddr[port], 0, rxspace); + sky2_ramset(hw, txqaddr[port], rxspace, ramsize - rxspace); - /* Make sure SyncQ is disabled */ - sky2_write8(hw, RB_ADDR(port == 0 ? Q_XS1 : Q_XS2, RB_CTRL), - RB_RST_SET); + /* Make sure SyncQ is disabled */ + sky2_write8(hw, RB_ADDR(port == 0 ? Q_XS1 : Q_XS2, RB_CTRL), + RB_RST_SET); + } sky2_qset(hw, txqaddr[port]); @@ -2917,18 +2930,8 @@ static void sky2_led(struct sky2_hw *hw, unsigned port, int on) default: gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); - gm_phy_write(hw, port, PHY_MARV_LED_OVER, - on ? PHY_M_LED_MO_DUP(MO_LED_ON) | - PHY_M_LED_MO_10(MO_LED_ON) | - PHY_M_LED_MO_100(MO_LED_ON) | - PHY_M_LED_MO_1000(MO_LED_ON) | - PHY_M_LED_MO_RX(MO_LED_ON) - : PHY_M_LED_MO_DUP(MO_LED_OFF) | - PHY_M_LED_MO_10(MO_LED_OFF) | - PHY_M_LED_MO_100(MO_LED_OFF) | - PHY_M_LED_MO_1000(MO_LED_OFF) | - PHY_M_LED_MO_RX(MO_LED_OFF)); - + gm_phy_write(hw, port, PHY_MARV_LED_OVER, + on ? PHY_M_LED_ALL : 0); } } diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 7760545edbf..6ed1d47dbbd 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -608,7 +608,7 @@ enum { PHY_ADDR_MARV = 0, }; -#define RB_ADDR(offs, queue) (B16_RAM_REGS + (queue) + (offs)) +#define RB_ADDR(offs, queue) ((u16) B16_RAM_REGS + (queue) + (offs)) enum { @@ -680,6 +680,7 @@ enum { BMU_FIFO_ENA | BMU_OP_ON, BMU_WM_DEFAULT = 0x600, + BMU_WM_PEX = 0x80, }; /* Tx BMU Control / Status Registers (Yukon-2) */ @@ -1060,7 +1061,7 @@ enum { PHY_M_PC_EN_DET_PLUS = 3<<8, /* Energy Detect Plus (Mode 2) */ }; -#define PHY_M_PC_MDI_XMODE(x) (((x)<<5) & PHY_M_PC_MDIX_MSK) +#define PHY_M_PC_MDI_XMODE(x) (((u16)(x)<<5) & PHY_M_PC_MDIX_MSK) enum { PHY_M_PC_MAN_MDI = 0, /* 00 = Manual MDI configuration */ @@ -1156,13 +1157,13 @@ enum { PHY_M_EC_TX_TIM_CT = 1<<1, /* RGMII Tx Timing Control */ PHY_M_EC_TRANS_DIS = 1<<0, /* Transmitter Disable (88E1111 only) */}; -#define PHY_M_EC_M_DSC(x) ((x)<<10 & PHY_M_EC_M_DSC_MSK) +#define PHY_M_EC_M_DSC(x) ((u16)(x)<<10 & PHY_M_EC_M_DSC_MSK) /* 00=1x; 01=2x; 10=3x; 11=4x */ -#define PHY_M_EC_S_DSC(x) ((x)<<8 & PHY_M_EC_S_DSC_MSK) +#define PHY_M_EC_S_DSC(x) ((u16)(x)<<8 & PHY_M_EC_S_DSC_MSK) /* 00=dis; 01=1x; 10=2x; 11=3x */ -#define PHY_M_EC_DSC_2(x) ((x)<<9 & PHY_M_EC_M_DSC_MSK2) +#define PHY_M_EC_DSC_2(x) ((u16)(x)<<9 & PHY_M_EC_M_DSC_MSK2) /* 000=1x; 001=2x; 010=3x; 011=4x */ -#define PHY_M_EC_MAC_S(x) ((x)<<4 & PHY_M_EC_MAC_S_MSK) +#define PHY_M_EC_MAC_S(x) ((u16)(x)<<4 & PHY_M_EC_MAC_S_MSK) /* 01X=0; 110=2.5; 111=25 (MHz) */ /* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */ @@ -1173,7 +1174,7 @@ enum { }; /* !!! Errata in spec. (1 = disable) */ -#define PHY_M_PC_DSC(x) (((x)<<12) & PHY_M_PC_DSC_MSK) +#define PHY_M_PC_DSC(x) (((u16)(x)<<12) & PHY_M_PC_DSC_MSK) /* 100=5x; 101=6x; 110=7x; 111=8x */ enum { MAC_TX_CLK_0_MHZ = 2, @@ -1203,7 +1204,7 @@ enum { PHY_M_LEDC_TX_C_MSB = 1<<0, /* Tx Control (MSB, 88E1111 only) */ }; -#define PHY_M_LED_PULS_DUR(x) (((x)<<12) & PHY_M_LEDC_PULS_MSK) +#define PHY_M_LED_PULS_DUR(x) (((u16)(x)<<12) & PHY_M_LEDC_PULS_MSK) /***** PHY_MARV_PHY_STAT (page 3)16 bit r/w Polarity Control Reg. *****/ enum { @@ -1233,7 +1234,7 @@ enum { PULS_1300MS = 7,/* 1.3 s to 2.7 s */ }; -#define PHY_M_LED_BLINK_RT(x) (((x)<<8) & PHY_M_LEDC_BL_R_MSK) +#define PHY_M_LED_BLINK_RT(x) (((u16)(x)<<8) & PHY_M_LEDC_BL_R_MSK) enum { BLINK_42MS = 0,/* 42 ms */ @@ -1243,21 +1244,18 @@ enum { BLINK_670MS = 4,/* 670 ms */ }; -/***** PHY_MARV_LED_OVER 16 bit r/w Manual LED Override Reg *****/ -#define PHY_M_LED_MO_SGMII(x) ((x)<<14) /* Bit 15..14: SGMII AN Timer */ - /* Bit 13..12: reserved */ -#define PHY_M_LED_MO_DUP(x) ((x)<<10) /* Bit 11..10: Duplex */ -#define PHY_M_LED_MO_10(x) ((x)<<8) /* Bit 9.. 8: Link 10 */ -#define PHY_M_LED_MO_100(x) ((x)<<6) /* Bit 7.. 6: Link 100 */ -#define PHY_M_LED_MO_1000(x) ((x)<<4) /* Bit 5.. 4: Link 1000 */ -#define PHY_M_LED_MO_RX(x) ((x)<<2) /* Bit 3.. 2: Rx */ -#define PHY_M_LED_MO_TX(x) ((x)<<0) /* Bit 1.. 0: Tx */ - +/**** PHY_MARV_LED_OVER 16 bit r/w LED control */ enum { - MO_LED_NORM = 0, - MO_LED_BLINK = 1, - MO_LED_OFF = 2, - MO_LED_ON = 3, + PHY_M_LED_MO_DUP = 3<<10,/* Bit 11..10: Duplex */ + PHY_M_LED_MO_10 = 3<<8, /* Bit 9.. 8: Link 10 */ + PHY_M_LED_MO_100 = 3<<6, /* Bit 7.. 6: Link 100 */ + PHY_M_LED_MO_1000 = 3<<4, /* Bit 5.. 4: Link 1000 */ + PHY_M_LED_MO_RX = 3<<2, /* Bit 3.. 2: Rx */ + PHY_M_LED_MO_TX = 3<<0, /* Bit 1.. 0: Tx */ + + PHY_M_LED_ALL = PHY_M_LED_MO_DUP | PHY_M_LED_MO_10 + | PHY_M_LED_MO_100 | PHY_M_LED_MO_1000 + | PHY_M_LED_MO_RX, }; /***** PHY_MARV_EXT_CTRL_2 16 bit r/w Ext. PHY Specific Ctrl 2 *****/ @@ -1294,9 +1292,9 @@ enum { PHY_M_FELP_LED0_MSK = 0xf, /* Bit 3.. 0: LED0 Mask (SPEED) */ }; -#define PHY_M_FELP_LED2_CTRL(x) (((x)<<8) & PHY_M_FELP_LED2_MSK) -#define PHY_M_FELP_LED1_CTRL(x) (((x)<<4) & PHY_M_FELP_LED1_MSK) -#define PHY_M_FELP_LED0_CTRL(x) (((x)<<0) & PHY_M_FELP_LED0_MSK) +#define PHY_M_FELP_LED2_CTRL(x) (((u16)(x)<<8) & PHY_M_FELP_LED2_MSK) +#define PHY_M_FELP_LED1_CTRL(x) (((u16)(x)<<4) & PHY_M_FELP_LED1_MSK) +#define PHY_M_FELP_LED0_CTRL(x) (((u16)(x)<<0) & PHY_M_FELP_LED0_MSK) enum { LED_PAR_CTRL_COLX = 0x00, @@ -1552,8 +1550,8 @@ enum { GM_SMI_CT_BUSY = 1<<3, /* Bit 3: Busy (Operation in progress) */ }; -#define GM_SMI_CT_PHY_AD(x) (((x)<<11) & GM_SMI_CT_PHY_A_MSK) -#define GM_SMI_CT_REG_AD(x) (((x)<<6) & GM_SMI_CT_REG_A_MSK) +#define GM_SMI_CT_PHY_AD(x) (((u16)(x)<<11) & GM_SMI_CT_PHY_A_MSK) +#define GM_SMI_CT_REG_AD(x) (((u16)(x)<<6) & GM_SMI_CT_REG_A_MSK) /* GM_PHY_ADDR 16 bit r/w GPHY Address Register */ enum { diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index 889ef0d7c37..d70bc979534 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -593,7 +593,7 @@ static void cleanup_card(struct net_device *dev) iounmap(ei_status.mem); } -void +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index e10755ec5de..2c5319c62fa 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -437,7 +437,7 @@ int __init init_module(void) return -ENXIO; } -void cleanup_module(void) +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index c0d13d65091..bd6e84506c2 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -1616,7 +1616,7 @@ int __init init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(devSMC9194); free_irq(devSMC9194->irq, devSMC9194); diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 95b6478f55c..e62a9586fb9 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -210,6 +210,7 @@ struct smc_local { /* work queue */ struct work_struct phy_configure; + struct net_device *dev; int work_pending; spinlock_t lock; @@ -1114,10 +1115,11 @@ static void smc_phy_check_media(struct net_device *dev, int init) * of autonegotiation.) If the RPC ANEG bit is cleared, the selection * is controlled by the RPC SPEED and RPC DPLX bits. */ -static void smc_phy_configure(void *data) +static void smc_phy_configure(struct work_struct *work) { - struct net_device *dev = data; - struct smc_local *lp = netdev_priv(dev); + struct smc_local *lp = + container_of(work, struct smc_local, phy_configure); + struct net_device *dev = lp->dev; void __iomem *ioaddr = lp->base; int phyaddr = lp->mii.phy_id; int my_phy_caps; /* My PHY capabilities */ @@ -1592,7 +1594,7 @@ smc_open(struct net_device *dev) /* Configure the PHY, initialize the link state */ if (lp->phy_type != 0) - smc_phy_configure(dev); + smc_phy_configure(&lp->phy_configure); else { spin_lock_irq(&lp->lock); smc_10bt_check_media(dev, 1); @@ -1972,7 +1974,8 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) #endif tasklet_init(&lp->tx_task, smc_hardware_send_pkt, (unsigned long)dev); - INIT_WORK(&lp->phy_configure, smc_phy_configure, dev); + INIT_WORK(&lp->phy_configure, smc_phy_configure); + lp->dev = dev; lp->mii.phy_id_mask = 0x1f; lp->mii.reg_num_mask = 0x1f; lp->mii.force_media = 0; @@ -2322,7 +2325,7 @@ static int smc_drv_resume(struct platform_device *dev) smc_reset(ndev); smc_enable(ndev); if (lp->phy_type != 0) - smc_phy_configure(ndev); + smc_phy_configure(&lp->phy_configure); netif_device_attach(ndev); } } diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index a8640169fc7..9367c574477 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -238,7 +238,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_CAN_USE_16BIT 1 #define SMC_CAN_USE_32BIT 0 -#define SMC_inb(a, r) inb((u32)a) + (r)) +#define SMC_inb(a, r) inb(((u32)a) + (r)) #define SMC_inw(a, r) inw(((u32)a) + (r)) #define SMC_outb(v, a, r) outb(v, ((u32)a) + (r)) #define SMC_outw(v, a, r) outw(v, ((u32)a) + (r)) @@ -434,6 +434,24 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #define SMC_IRQ_FLAGS (0) +#elif defined(CONFIG_ARCH_VERSATILE) + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + +#define SMC_IRQ_FLAGS (0) + #else #define SMC_CAN_USE_8BIT 1 @@ -1216,7 +1234,7 @@ static const char * chip_ids[ 16 ] = { if (SMC_CAN_USE_32BIT) { \ void *__ptr = (p); \ int __len = (l); \ - void *__ioaddr = ioaddr; \ + void __iomem *__ioaddr = ioaddr; \ if (__len >= 2 && (unsigned long)__ptr & 2) { \ __len -= 2; \ SMC_outw(*(u16 *)__ptr, ioaddr, DATA_REG); \ @@ -1240,7 +1258,7 @@ static const char * chip_ids[ 16 ] = { if (SMC_CAN_USE_32BIT) { \ void *__ptr = (p); \ int __len = (l); \ - void *__ioaddr = ioaddr; \ + void __iomem *__ioaddr = ioaddr; \ if ((unsigned long)__ptr & 2) { \ /* \ * We want 32bit alignment here. \ diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 13e0a43e423..ebb6aa39f9c 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1939,10 +1939,11 @@ spider_net_stop(struct net_device *netdev) * called as task when tx hangs, resets interface (if interface is up) */ static void -spider_net_tx_timeout_task(void *data) +spider_net_tx_timeout_task(struct work_struct *work) { - struct net_device *netdev = data; - struct spider_net_card *card = netdev_priv(netdev); + struct spider_net_card *card = + container_of(work, struct spider_net_card, tx_timeout_task); + struct net_device *netdev = card->netdev; if (!(netdev->flags & IFF_UP)) goto out; @@ -2116,7 +2117,7 @@ spider_net_alloc_card(void) card = netdev_priv(netdev); card->netdev = netdev; card->msg_enable = SPIDER_NET_DEFAULT_MSG; - INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task, netdev); + INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task); init_waitqueue_head(&card->waitq); atomic_set(&card->tx_timeout_task_counter, 0); diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 47a1c09d19a..c62e85d89f4 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -945,7 +945,7 @@ static void set_multicast_list( struct net_device *dev ) static struct net_device *sun3lance_dev; -int init_module(void) +int __init init_module(void) { sun3lance_dev = sun3lance_probe(-1); if (IS_ERR(sun3lance_dev)) @@ -953,7 +953,7 @@ int init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(sun3lance_dev); #ifdef CONFIG_SUN3 diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index cf44e72399b..785e4a535f9 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2282,9 +2282,9 @@ static void gem_do_stop(struct net_device *dev, int wol) } } -static void gem_reset_task(void *data) +static void gem_reset_task(struct work_struct *work) { - struct gem *gp = (struct gem *) data; + struct gem *gp = container_of(work, struct gem, reset_task); mutex_lock(&gp->pm_mutex); @@ -3044,7 +3044,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gp->link_timer.function = gem_link_timer; gp->link_timer.data = (unsigned long) gp; - INIT_WORK(&gp->reset_task, gem_reset_task, gp); + INIT_WORK(&gp->reset_task, gem_reset_task); gp->lstate = link_down; gp->timer_ticks = 0; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c20bb998e0e..d9123c9adc1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3654,9 +3654,9 @@ static void tg3_poll_controller(struct net_device *dev) } #endif -static void tg3_reset_task(void *_data) +static void tg3_reset_task(struct work_struct *work) { - struct tg3 *tp = _data; + struct tg3 *tp = container_of(work, struct tg3, reset_task); unsigned int restart_timer; tg3_full_lock(tp, 0); @@ -11734,7 +11734,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, #endif spin_lock_init(&tp->lock); spin_lock_init(&tp->indirect_lock); - INIT_WORK(&tp->reset_task, tg3_reset_task, tp); + INIT_WORK(&tp->reset_task, tg3_reset_task); tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len); if (tp->regs == 0UL) { diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index e14f5a00f65..f85f0025112 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -296,6 +296,7 @@ static void TLan_SetMulticastList( struct net_device *); static int TLan_ioctl( struct net_device *dev, struct ifreq *rq, int cmd); static int TLan_probe1( struct pci_dev *pdev, long ioaddr, int irq, int rev, const struct pci_device_id *ent); static void TLan_tx_timeout( struct net_device *dev); +static void TLan_tx_timeout_work(struct work_struct *work); static int tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent); static u32 TLan_HandleInvalid( struct net_device *, u16 ); @@ -562,6 +563,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, priv = netdev_priv(dev); priv->pciDev = pdev; + priv->dev = dev; /* Is this a PCI device? */ if (pdev) { @@ -634,7 +636,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, /* This will be used when we get an adapter error from * within our irq handler */ - INIT_WORK(&priv->tlan_tqueue, (void *)(void*)TLan_tx_timeout, dev); + INIT_WORK(&priv->tlan_tqueue, TLan_tx_timeout_work); spin_lock_init(&priv->lock); @@ -1040,6 +1042,25 @@ static void TLan_tx_timeout(struct net_device *dev) } + /*************************************************************** + * TLan_tx_timeout_work + * + * Returns: nothing + * + * Params: + * work work item of device which timed out + * + **************************************************************/ + +static void TLan_tx_timeout_work(struct work_struct *work) +{ + TLanPrivateInfo *priv = + container_of(work, TLanPrivateInfo, tlan_tqueue); + + TLan_tx_timeout(priv->dev); +} + + /*************************************************************** * TLan_StartTx diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index a44e2f2ef62..41ce0b66593 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -170,6 +170,7 @@ typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE]; typedef struct tlan_private_tag { struct net_device *nextDevice; struct pci_dev *pciDev; + struct net_device *dev; void *dmaStorage; dma_addr_t dmaStorageDMA; unsigned int dmaSize; diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 46dabdb1207..cec282a6f62 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -5706,7 +5706,7 @@ int __init init_module(void) return found ? 0 : -ENODEV; } -void cleanup_module(void) +void __exit cleanup_module(void) { int i; diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c index fa3a2bb105a..942b839ccc5 100644 --- a/drivers/net/tulip/21142.c +++ b/drivers/net/tulip/21142.c @@ -26,10 +26,11 @@ static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; /* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list of available transceivers. */ -void t21142_media_task(void *data) +void t21142_media_task(struct work_struct *work) { - struct net_device *dev = data; - struct tulip_private *tp = netdev_priv(dev); + struct tulip_private *tp = + container_of(work, struct tulip_private, media_work); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->base_addr; int csr12 = ioread32(ioaddr + CSR12); int next_tick = 60*HZ; diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c index 066e5d6bcbd..df326fe1cc8 100644 --- a/drivers/net/tulip/timer.c +++ b/drivers/net/tulip/timer.c @@ -18,10 +18,11 @@ #include "tulip.h" -void tulip_media_task(void *data) +void tulip_media_task(struct work_struct *work) { - struct net_device *dev = data; - struct tulip_private *tp = netdev_priv(dev); + struct tulip_private *tp = + container_of(work, struct tulip_private, media_work); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->base_addr; u32 csr12 = ioread32(ioaddr + CSR12); int next_tick = 2*HZ; diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index ad107f45c7b..25f25da7691 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -44,7 +44,7 @@ struct tulip_chip_table { int valid_intrs; /* CSR7 interrupt enable settings */ int flags; void (*media_timer) (unsigned long); - void (*media_task) (void *); + work_func_t media_task; }; @@ -392,6 +392,7 @@ struct tulip_private { int csr12_shadow; int pad0; /* Used for 8-byte alignment */ struct work_struct media_work; + struct net_device *dev; }; @@ -406,7 +407,7 @@ struct eeprom_fixup { /* 21142.c */ extern u16 t21142_csr14[]; -void t21142_media_task(void *data); +void t21142_media_task(struct work_struct *work); void t21142_start_nway(struct net_device *dev); void t21142_lnk_change(struct net_device *dev, int csr5); @@ -444,7 +445,7 @@ void pnic_lnk_change(struct net_device *dev, int csr5); void pnic_timer(unsigned long data); /* timer.c */ -void tulip_media_task(void *data); +void tulip_media_task(struct work_struct *work); void mxic_timer(unsigned long data); void comet_timer(unsigned long data); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 0aee618f883..5a35354aa52 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1367,6 +1367,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, * it is zeroed and aligned in alloc_etherdev */ tp = netdev_priv(dev); + tp->dev = dev; tp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct tulip_rx_desc) * RX_RING_SIZE + @@ -1389,7 +1390,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, tp->timer.data = (unsigned long)dev; tp->timer.function = tulip_tbl[tp->chip_id].media_timer; - INIT_WORK(&tp->media_work, tulip_tbl[tp->chip_id].media_task, dev); + INIT_WORK(&tp->media_work, tulip_tbl[tp->chip_id].media_task); dev->base_addr = (unsigned long)ioaddr; diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index 931cbdf6d79..b2a23aed442 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -125,8 +125,8 @@ static int cpc_tty_write_room(struct tty_struct *tty); static int cpc_tty_chars_in_buffer(struct tty_struct *tty); static void cpc_tty_flush_buffer(struct tty_struct *tty); static void cpc_tty_hangup(struct tty_struct *tty); -static void cpc_tty_rx_work(void *data); -static void cpc_tty_tx_work(void *data); +static void cpc_tty_rx_work(struct work_struct *work); +static void cpc_tty_tx_work(struct work_struct *work); static int cpc_tty_send_to_card(pc300dev_t *dev,void *buf, int len); static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx); static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char); @@ -261,8 +261,8 @@ void cpc_tty_init(pc300dev_t *pc300dev) cpc_tty->tty_minor = port + CPC_TTY_MINOR_START; cpc_tty->pc300dev = pc300dev; - INIT_WORK(&cpc_tty->tty_tx_work, cpc_tty_tx_work, (void *)cpc_tty); - INIT_WORK(&cpc_tty->tty_rx_work, cpc_tty_rx_work, (void *)port); + INIT_WORK(&cpc_tty->tty_tx_work, cpc_tty_tx_work); + INIT_WORK(&cpc_tty->tty_rx_work, cpc_tty_rx_work); cpc_tty->buf_rx.first = cpc_tty->buf_rx.last = NULL; @@ -659,21 +659,23 @@ static void cpc_tty_hangup(struct tty_struct *tty) * o call the line disc. read * o free memory */ -static void cpc_tty_rx_work(void * data) +static void cpc_tty_rx_work(struct work_struct *work) { + st_cpc_tty_area *cpc_tty; unsigned long port; int i, j; - st_cpc_tty_area *cpc_tty; volatile st_cpc_rx_buf *buf; char flags=0,flg_rx=1; struct tty_ldisc *ld; if (cpc_tty_cnt == 0) return; - for (i=0; (i < 4) && flg_rx ; i++) { flg_rx = 0; - port = (unsigned long)data; + + cpc_tty = container_of(work, st_cpc_tty_area, tty_rx_work); + port = cpc_tty - cpc_tty_area; + for (j=0; j < CPC_TTY_NPORTS; j++) { cpc_tty = &cpc_tty_area[port]; @@ -882,9 +884,10 @@ void cpc_tty_receive(pc300dev_t *pc300dev) * o if need call line discipline wakeup * o call wake_up_interruptible */ -static void cpc_tty_tx_work(void *data) +static void cpc_tty_tx_work(struct work_struct *work) { - st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *) data; + st_cpc_tty_area *cpc_tty = + container_of(work, st_cpc_tty_area, tty_tx_work); struct tty_struct *tty; CPC_TTY_DBG("%s: cpc_tty_tx_work init\n",cpc_tty->name); diff --git a/drivers/net/wd.c b/drivers/net/wd.c index 41f1d677884..7f38012b9c9 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -538,7 +538,7 @@ static void cleanup_card(struct net_device *dev) iounmap(ei_status.mem); } -void +void __exit cleanup_module(void) { int this_dev; diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index ac9437d497f..f12355398fe 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -219,21 +219,6 @@ static int airo_config(struct pcmcia_device *link) dev = link->priv; DEBUG(0, "airo_config(0x%p)\n", link); - - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; /* In this loop, we scan the CIS for configuration table entries, @@ -247,6 +232,10 @@ static int airo_config(struct pcmcia_device *link) these things without consulting the CIS, and most client drivers will only use the CIS to fill in implementation-defined details. */ + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 5c410989c4d..12617cd0b78 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -244,17 +244,6 @@ static int atmel_config(struct pcmcia_device *link) tuple.TupleOffset = 0; /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* In this loop, we scan the CIS for configuration table entries, each of which describes a valid card configuration, including voltage, IO window, memory window, and interrupt settings. diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 94dfb92fab5..8286678513b 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -819,7 +819,7 @@ struct bcm43xx_private { struct tasklet_struct isr_tasklet; /* Periodic tasks */ - struct work_struct periodic_work; + struct delayed_work periodic_work; unsigned int periodic_state; struct work_struct restart_work; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 5b3c27359a1..2ec2e5afce6 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3215,9 +3215,10 @@ static void do_periodic_work(struct bcm43xx_private *bcm) schedule_delayed_work(&bcm->periodic_work, HZ * 15); } -static void bcm43xx_periodic_work_handler(void *d) +static void bcm43xx_periodic_work_handler(struct work_struct *work) { - struct bcm43xx_private *bcm = d; + struct bcm43xx_private *bcm = + container_of(work, struct bcm43xx_private, periodic_work.work); struct net_device *net_dev = bcm->net_dev; unsigned long flags; u32 savedirqs = 0; @@ -3279,11 +3280,11 @@ void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) { - struct work_struct *work = &(bcm->periodic_work); + struct delayed_work *work = &bcm->periodic_work; assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); - INIT_WORK(work, bcm43xx_periodic_work_handler, bcm); - schedule_work(work); + INIT_DELAYED_WORK(work, bcm43xx_periodic_work_handler); + schedule_delayed_work(work, 0); } static void bcm43xx_security_init(struct bcm43xx_private *bcm) @@ -3635,7 +3636,7 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) bcm43xx_periodic_tasks_setup(bcm); /*FIXME: This should be handled by softmac instead. */ - schedule_work(&bcm->softmac->associnfo.work); + schedule_delayed_work(&bcm->softmac->associnfo.work, 0); out: mutex_unlock(&(bcm)->mutex); @@ -4182,9 +4183,10 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) /* Hard-reset the chip. Do not call this directly. * Use bcm43xx_controller_restart() */ -static void bcm43xx_chip_reset(void *_bcm) +static void bcm43xx_chip_reset(struct work_struct *work) { - struct bcm43xx_private *bcm = _bcm; + struct bcm43xx_private *bcm = + container_of(work, struct bcm43xx_private, restart_work); struct bcm43xx_phyinfo *phy; int err = -ENODEV; @@ -4211,7 +4213,7 @@ void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) return; printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); - INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); + INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset); schedule_work(&bcm->restart_work); } diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index e663518bd57..e89c890d16f 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -35,7 +35,7 @@ int hostap_80211_get_hdrlen(u16 fc); struct net_device_stats *hostap_get_stats(struct net_device *dev); void hostap_setup_dev(struct net_device *dev, local_info_t *local, int main_dev); -void hostap_set_multicast_list_queue(void *data); +void hostap_set_multicast_list_queue(struct work_struct *work); int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked); void hostap_cleanup(local_info_t *local); diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 798a8555fbd..974a8e5bec8 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -49,10 +49,10 @@ MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs " static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta); static void hostap_event_expired_sta(struct net_device *dev, struct sta_info *sta); -static void handle_add_proc_queue(void *data); +static void handle_add_proc_queue(struct work_struct *work); #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -static void handle_wds_oper_queue(void *data); +static void handle_wds_oper_queue(struct work_struct *work); static void prism2_send_mgmt(struct net_device *dev, u16 type_subtype, char *body, int body_len, u8 *addr, u16 tx_cb_idx); @@ -807,7 +807,7 @@ void hostap_init_data(local_info_t *local) INIT_LIST_HEAD(&ap->sta_list); /* Initialize task queue structure for AP management */ - INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap); + INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue); ap->tx_callback_idx = hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); @@ -815,7 +815,7 @@ void hostap_init_data(local_info_t *local) printk(KERN_WARNING "%s: failed to register TX callback for " "AP\n", local->dev->name); #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue, local); + INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue); ap->tx_callback_auth = hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); @@ -1062,9 +1062,10 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, } -static void handle_add_proc_queue(void *data) +static void handle_add_proc_queue(struct work_struct *work) { - struct ap_data *ap = (struct ap_data *) data; + struct ap_data *ap = container_of(work, struct ap_data, + add_sta_proc_queue); struct sta_info *sta; char name[20]; struct add_sta_proc_data *entry, *prev; @@ -1950,9 +1951,11 @@ static void handle_pspoll(local_info_t *local, #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -static void handle_wds_oper_queue(void *data) +static void handle_wds_oper_queue(struct work_struct *work) { - local_info_t *local = data; + struct ap_data *ap = container_of(work, struct ap_data, + wds_oper_queue); + local_info_t *local = ap->local; struct wds_oper_data *entry, *prev; spin_lock_bh(&local->lock); diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index ef470e6e1c2..8d8f4b9b8b0 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -293,15 +293,12 @@ static int sandisk_enable_wireless(struct net_device *dev) goto done; } - tuple.DesiredTuple = CISTPL_MANFID; tuple.Attributes = TUPLE_RETURN_COMMON; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if (pcmcia_get_first_tuple(hw_priv->link, &tuple) || - pcmcia_get_tuple_data(hw_priv->link, &tuple) || - pcmcia_parse_tuple(hw_priv->link, &tuple, parse) || - parse->manfid.manf != 0xd601 || parse->manfid.card != 0x0101) { + + if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) { /* No SanDisk manfid found */ ret = -ENODEV; goto done; @@ -572,16 +569,10 @@ static int prism2_config(struct pcmcia_device *link) goto failed; } - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, parse)); - link->conf.ConfigBase = parse->config.base; - link->conf.Present = parse->config.rmask[0]; CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf)); diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 9c503364ca3..a394a23b9a2 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -1641,9 +1641,9 @@ static void prism2_schedule_reset(local_info_t *local) /* Called only as scheduled task after noticing card timeout in interrupt * context */ -static void handle_reset_queue(void *data) +static void handle_reset_queue(struct work_struct *work) { - local_info_t *local = (local_info_t *) data; + local_info_t *local = container_of(work, local_info_t, reset_queue); printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); prism2_hw_reset(local->dev); @@ -2892,9 +2892,10 @@ static void hostap_passive_scan(unsigned long data) /* Called only as a scheduled task when communications quality values should * be updated. */ -static void handle_comms_qual_update(void *data) +static void handle_comms_qual_update(struct work_struct *work) { - local_info_t *local = data; + local_info_t *local = + container_of(work, local_info_t, comms_qual_update); prism2_update_comms_qual(local->dev); } @@ -3044,9 +3045,9 @@ static int prism2_set_tim(struct net_device *dev, int aid, int set) } -static void handle_set_tim_queue(void *data) +static void handle_set_tim_queue(struct work_struct *work) { - local_info_t *local = (local_info_t *) data; + local_info_t *local = container_of(work, local_info_t, set_tim_queue); struct set_tim_data *entry; u16 val; @@ -3203,15 +3204,15 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, local->scan_channel_mask = 0xffff; /* Initialize task queue structures */ - INIT_WORK(&local->reset_queue, handle_reset_queue, local); + INIT_WORK(&local->reset_queue, handle_reset_queue); INIT_WORK(&local->set_multicast_list_queue, - hostap_set_multicast_list_queue, local->dev); + hostap_set_multicast_list_queue); - INIT_WORK(&local->set_tim_queue, handle_set_tim_queue, local); + INIT_WORK(&local->set_tim_queue, handle_set_tim_queue); INIT_LIST_HEAD(&local->set_tim_list); spin_lock_init(&local->set_tim_lock); - INIT_WORK(&local->comms_qual_update, handle_comms_qual_update, local); + INIT_WORK(&local->comms_qual_update, handle_comms_qual_update); /* Initialize tasklets for handling hardware IRQ related operations * outside hw IRQ handler */ diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 00ed6389076..b6a02a02da7 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -473,9 +473,9 @@ static void handle_info_queue_scanresults(local_info_t *local) /* Called only as scheduled task after receiving info frames (used to avoid * pending too much time in HW IRQ handler). */ -static void handle_info_queue(void *data) +static void handle_info_queue(struct work_struct *work) { - local_info_t *local = (local_info_t *) data; + local_info_t *local = container_of(work, local_info_t, info_queue); if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info)) @@ -492,7 +492,7 @@ void hostap_info_init(local_info_t *local) { skb_queue_head_init(&local->info_list); #ifndef PRISM2_NO_STATION_MODES - INIT_WORK(&local->info_queue, handle_info_queue, local); + INIT_WORK(&local->info_queue, handle_info_queue); #endif /* PRISM2_NO_STATION_MODES */ } diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 53374fcba77..0796be9d9e7 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -767,14 +767,14 @@ static int prism2_set_mac_address(struct net_device *dev, void *p) /* TODO: to be further implemented as soon as Prism2 fully supports * GroupAddresses and correct documentation is available */ -void hostap_set_multicast_list_queue(void *data) +void hostap_set_multicast_list_queue(struct work_struct *work) { - struct net_device *dev = (struct net_device *) data; + local_info_t *local = + container_of(work, local_info_t, set_multicast_list_queue); + struct net_device *dev = local->dev; struct hostap_interface *iface; - local_info_t *local; iface = netdev_priv(dev); - local = iface->local; if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, local->is_promisc)) { printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 060018e084b..dd9ba4aad7b 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -316,7 +316,7 @@ static void ipw2100_release_firmware(struct ipw2100_priv *priv, struct ipw2100_fw *fw); static int ipw2100_ucode_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw); -static void ipw2100_wx_event_work(struct ipw2100_priv *priv); +static void ipw2100_wx_event_work(struct work_struct *work); static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev); static struct iw_handler_def ipw2100_wx_handler_def; @@ -679,7 +679,8 @@ static void schedule_reset(struct ipw2100_priv *priv) queue_delayed_work(priv->workqueue, &priv->reset_work, priv->reset_backoff * HZ); else - queue_work(priv->workqueue, &priv->reset_work); + queue_delayed_work(priv->workqueue, &priv->reset_work, + 0); if (priv->reset_backoff < MAX_RESET_BACKOFF) priv->reset_backoff++; @@ -1873,8 +1874,10 @@ static void ipw2100_down(struct ipw2100_priv *priv) netif_stop_queue(priv->net_dev); } -static void ipw2100_reset_adapter(struct ipw2100_priv *priv) +static void ipw2100_reset_adapter(struct work_struct *work) { + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, reset_work.work); unsigned long flags; union iwreq_data wrqu = { .ap_addr = { @@ -2071,9 +2074,9 @@ static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) return; if (priv->status & STATUS_SECURITY_UPDATED) - queue_work(priv->workqueue, &priv->security_work); + queue_delayed_work(priv->workqueue, &priv->security_work, 0); - queue_work(priv->workqueue, &priv->wx_event_work); + queue_delayed_work(priv->workqueue, &priv->wx_event_work, 0); } static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status) @@ -5524,8 +5527,11 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) return err; } -static void ipw2100_security_work(struct ipw2100_priv *priv) +static void ipw2100_security_work(struct work_struct *work) { + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, security_work.work); + /* If we happen to have reconnected before we get a chance to * process this, then update the security settings--which causes * a disassociation to occur */ @@ -5748,7 +5754,7 @@ static int ipw2100_set_address(struct net_device *dev, void *p) priv->reset_backoff = 0; mutex_unlock(&priv->action_mutex); - ipw2100_reset_adapter(priv); + ipw2100_reset_adapter(&priv->reset_work.work); return 0; done: @@ -5910,9 +5916,10 @@ static const struct ethtool_ops ipw2100_ethtool_ops = { .get_drvinfo = ipw_ethtool_get_drvinfo, }; -static void ipw2100_hang_check(void *adapter) +static void ipw2100_hang_check(struct work_struct *work) { - struct ipw2100_priv *priv = adapter; + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, hang_check.work); unsigned long flags; u32 rtc = 0xa5a5a5a5; u32 len = sizeof(rtc); @@ -5952,9 +5959,10 @@ static void ipw2100_hang_check(void *adapter) spin_unlock_irqrestore(&priv->low_lock, flags); } -static void ipw2100_rf_kill(void *adapter) +static void ipw2100_rf_kill(struct work_struct *work) { - struct ipw2100_priv *priv = adapter; + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, rf_kill.work); unsigned long flags; spin_lock_irqsave(&priv->low_lock, flags); @@ -6103,14 +6111,11 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, priv->workqueue = create_workqueue(DRV_NAME); - INIT_WORK(&priv->reset_work, - (void (*)(void *))ipw2100_reset_adapter, priv); - INIT_WORK(&priv->security_work, - (void (*)(void *))ipw2100_security_work, priv); - INIT_WORK(&priv->wx_event_work, - (void (*)(void *))ipw2100_wx_event_work, priv); - INIT_WORK(&priv->hang_check, ipw2100_hang_check, priv); - INIT_WORK(&priv->rf_kill, ipw2100_rf_kill, priv); + INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter); + INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work); + INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work); + INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check); + INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill); tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) ipw2100_irq_tasklet, (unsigned long)priv); @@ -8281,8 +8286,10 @@ static struct iw_handler_def ipw2100_wx_handler_def = { .get_wireless_stats = ipw2100_wx_wireless_stats, }; -static void ipw2100_wx_event_work(struct ipw2100_priv *priv) +static void ipw2100_wx_event_work(struct work_struct *work) { + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, wx_event_work.work); union iwreq_data wrqu; int len = ETH_ALEN; diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 55b7227198d..de7d384d38a 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -583,11 +583,11 @@ struct ipw2100_priv { struct tasklet_struct irq_tasklet; struct workqueue_struct *workqueue; - struct work_struct reset_work; - struct work_struct security_work; - struct work_struct wx_event_work; - struct work_struct hang_check; - struct work_struct rf_kill; + struct delayed_work reset_work; + struct delayed_work security_work; + struct delayed_work wx_event_work; + struct delayed_work hang_check; + struct delayed_work rf_kill; u32 interrupts; int tx_interrupts; diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index d29f42773a8..22cb3fb7502 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -187,9 +187,9 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *); static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *); static void ipw_rx_queue_replenish(void *); static int ipw_up(struct ipw_priv *); -static void ipw_bg_up(void *); +static void ipw_bg_up(struct work_struct *work); static void ipw_down(struct ipw_priv *); -static void ipw_bg_down(void *); +static void ipw_bg_down(struct work_struct *work); static int ipw_config(struct ipw_priv *); static int init_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *prates); @@ -862,11 +862,12 @@ static void ipw_led_link_on(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_led_link_on(void *data) +static void ipw_bg_led_link_on(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_link_on.work); mutex_lock(&priv->mutex); - ipw_led_link_on(data); + ipw_led_link_on(priv); mutex_unlock(&priv->mutex); } @@ -906,11 +907,12 @@ static void ipw_led_link_off(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_led_link_off(void *data) +static void ipw_bg_led_link_off(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_link_off.work); mutex_lock(&priv->mutex); - ipw_led_link_off(data); + ipw_led_link_off(priv); mutex_unlock(&priv->mutex); } @@ -985,11 +987,12 @@ static void ipw_led_activity_off(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_led_activity_off(void *data) +static void ipw_bg_led_activity_off(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_act_off.work); mutex_lock(&priv->mutex); - ipw_led_activity_off(data); + ipw_led_activity_off(priv); mutex_unlock(&priv->mutex); } @@ -2228,11 +2231,12 @@ static void ipw_adapter_restart(void *adapter) } } -static void ipw_bg_adapter_restart(void *data) +static void ipw_bg_adapter_restart(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, adapter_restart); mutex_lock(&priv->mutex); - ipw_adapter_restart(data); + ipw_adapter_restart(priv); mutex_unlock(&priv->mutex); } @@ -2249,11 +2253,12 @@ static void ipw_scan_check(void *data) } } -static void ipw_bg_scan_check(void *data) +static void ipw_bg_scan_check(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, scan_check.work); mutex_lock(&priv->mutex); - ipw_scan_check(data); + ipw_scan_check(priv); mutex_unlock(&priv->mutex); } @@ -3831,17 +3836,19 @@ static int ipw_disassociate(void *data) return 1; } -static void ipw_bg_disassociate(void *data) +static void ipw_bg_disassociate(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, disassociate); mutex_lock(&priv->mutex); - ipw_disassociate(data); + ipw_disassociate(priv); mutex_unlock(&priv->mutex); } -static void ipw_system_config(void *data) +static void ipw_system_config(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, system_config); #ifdef CONFIG_IPW2200_PROMISCUOUS if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) { @@ -4208,11 +4215,12 @@ static void ipw_gather_stats(struct ipw_priv *priv) IPW_STATS_INTERVAL); } -static void ipw_bg_gather_stats(void *data) +static void ipw_bg_gather_stats(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, gather_stats.work); mutex_lock(&priv->mutex); - ipw_gather_stats(data); + ipw_gather_stats(priv); mutex_unlock(&priv->mutex); } @@ -4268,8 +4276,8 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, if (!(priv->status & STATUS_ROAMING)) { priv->status |= STATUS_ROAMING; if (!(priv->status & STATUS_SCANNING)) - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); } return; } @@ -4607,8 +4615,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { priv->status |= STATUS_SCAN_FORCED; - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); break; } priv->status &= ~STATUS_SCAN_FORCED; @@ -4631,8 +4639,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, /* Don't schedule if we aborted the scan */ priv->status &= ~STATUS_ROAMING; } else if (priv->status & STATUS_SCAN_PENDING) - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); else if (priv->config & CFG_BACKGROUND_SCAN && priv->status & STATUS_ASSOCIATED) queue_delayed_work(priv->workqueue, @@ -5055,11 +5063,12 @@ static void ipw_rx_queue_replenish(void *data) ipw_rx_queue_restock(priv); } -static void ipw_bg_rx_queue_replenish(void *data) +static void ipw_bg_rx_queue_replenish(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, rx_replenish); mutex_lock(&priv->mutex); - ipw_rx_queue_replenish(data); + ipw_rx_queue_replenish(priv); mutex_unlock(&priv->mutex); } @@ -5489,9 +5498,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, return 1; } -static void ipw_merge_adhoc_network(void *data) +static void ipw_merge_adhoc_network(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, merge_networks); struct ieee80211_network *network = NULL; struct ipw_network_match match = { .network = priv->assoc_network @@ -5948,11 +5958,12 @@ static void ipw_adhoc_check(void *data) priv->assoc_request.beacon_interval); } -static void ipw_bg_adhoc_check(void *data) +static void ipw_bg_adhoc_check(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, adhoc_check.work); mutex_lock(&priv->mutex); - ipw_adhoc_check(data); + ipw_adhoc_check(priv); mutex_unlock(&priv->mutex); } @@ -6299,19 +6310,26 @@ done: return err; } -static int ipw_request_passive_scan(struct ipw_priv *priv) { - return ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE); +static void ipw_request_passive_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_passive_scan); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE); } -static int ipw_request_scan(struct ipw_priv *priv) { - return ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE); +static void ipw_request_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_scan.work); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE); } -static void ipw_bg_abort_scan(void *data) +static void ipw_bg_abort_scan(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, abort_scan); mutex_lock(&priv->mutex); - ipw_abort_scan(data); + ipw_abort_scan(priv); mutex_unlock(&priv->mutex); } @@ -7084,9 +7102,10 @@ static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, /* * background support to run QoS activate functionality */ -static void ipw_bg_qos_activate(void *data) +static void ipw_bg_qos_activate(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, qos_activate); if (priv == NULL) return; @@ -7394,11 +7413,12 @@ static void ipw_roam(void *data) priv->status &= ~STATUS_ROAMING; } -static void ipw_bg_roam(void *data) +static void ipw_bg_roam(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, roam); mutex_lock(&priv->mutex); - ipw_roam(data); + ipw_roam(priv); mutex_unlock(&priv->mutex); } @@ -7479,8 +7499,8 @@ static int ipw_associate(void *data) &priv->request_scan, SCAN_INTERVAL); else - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); } return 0; @@ -7491,11 +7511,12 @@ static int ipw_associate(void *data) return 1; } -static void ipw_bg_associate(void *data) +static void ipw_bg_associate(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, associate); mutex_lock(&priv->mutex); - ipw_associate(data); + ipw_associate(priv); mutex_unlock(&priv->mutex); } @@ -9419,7 +9440,7 @@ static int ipw_wx_set_scan(struct net_device *dev, IPW_DEBUG_WX("Start scan\n"); - queue_work(priv->workqueue, &priv->request_scan); + queue_delayed_work(priv->workqueue, &priv->request_scan, 0); return 0; } @@ -10556,11 +10577,12 @@ static void ipw_rf_kill(void *adapter) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_rf_kill(void *data) +static void ipw_bg_rf_kill(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, rf_kill.work); mutex_lock(&priv->mutex); - ipw_rf_kill(data); + ipw_rf_kill(priv); mutex_unlock(&priv->mutex); } @@ -10591,11 +10613,12 @@ static void ipw_link_up(struct ipw_priv *priv) queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); } -static void ipw_bg_link_up(void *data) +static void ipw_bg_link_up(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, link_up); mutex_lock(&priv->mutex); - ipw_link_up(data); + ipw_link_up(priv); mutex_unlock(&priv->mutex); } @@ -10615,15 +10638,16 @@ static void ipw_link_down(struct ipw_priv *priv) if (!(priv->status & STATUS_EXIT_PENDING)) { /* Queue up another scan... */ - queue_work(priv->workqueue, &priv->request_scan); + queue_delayed_work(priv->workqueue, &priv->request_scan, 0); } } -static void ipw_bg_link_down(void *data) +static void ipw_bg_link_down(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, link_down); mutex_lock(&priv->mutex); - ipw_link_down(data); + ipw_link_down(priv); mutex_unlock(&priv->mutex); } @@ -10635,38 +10659,30 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) init_waitqueue_head(&priv->wait_command_queue); init_waitqueue_head(&priv->wait_state); - INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv); - INIT_WORK(&priv->associate, ipw_bg_associate, priv); - INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv); - INIT_WORK(&priv->system_config, ipw_system_config, priv); - INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv); - INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv); - INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv); - INIT_WORK(&priv->up, (void (*)(void *))ipw_bg_up, priv); - INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv); - INIT_WORK(&priv->request_scan, - (void (*)(void *))ipw_request_scan, priv); - INIT_WORK(&priv->request_passive_scan, - (void (*)(void *))ipw_request_passive_scan, priv); - INIT_WORK(&priv->gather_stats, - (void (*)(void *))ipw_bg_gather_stats, priv); - INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv); - INIT_WORK(&priv->roam, ipw_bg_roam, priv); - INIT_WORK(&priv->scan_check, ipw_bg_scan_check, priv); - INIT_WORK(&priv->link_up, (void (*)(void *))ipw_bg_link_up, priv); - INIT_WORK(&priv->link_down, (void (*)(void *))ipw_bg_link_down, priv); - INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_bg_led_link_on, - priv); - INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_bg_led_link_off, - priv); - INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_bg_led_activity_off, - priv); - INIT_WORK(&priv->merge_networks, - (void (*)(void *))ipw_merge_adhoc_network, priv); + INIT_DELAYED_WORK(&priv->adhoc_check, ipw_bg_adhoc_check); + INIT_WORK(&priv->associate, ipw_bg_associate); + INIT_WORK(&priv->disassociate, ipw_bg_disassociate); + INIT_WORK(&priv->system_config, ipw_system_config); + INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish); + INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart); + INIT_DELAYED_WORK(&priv->rf_kill, ipw_bg_rf_kill); + INIT_WORK(&priv->up, ipw_bg_up); + INIT_WORK(&priv->down, ipw_bg_down); + INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan); + INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan); + INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats); + INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan); + INIT_WORK(&priv->roam, ipw_bg_roam); + INIT_DELAYED_WORK(&priv->scan_check, ipw_bg_scan_check); + INIT_WORK(&priv->link_up, ipw_bg_link_up); + INIT_WORK(&priv->link_down, ipw_bg_link_down); + INIT_DELAYED_WORK(&priv->led_link_on, ipw_bg_led_link_on); + INIT_DELAYED_WORK(&priv->led_link_off, ipw_bg_led_link_off); + INIT_DELAYED_WORK(&priv->led_act_off, ipw_bg_led_activity_off); + INIT_WORK(&priv->merge_networks, ipw_merge_adhoc_network); #ifdef CONFIG_IPW2200_QOS - INIT_WORK(&priv->qos_activate, (void (*)(void *))ipw_bg_qos_activate, - priv); + INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate); #endif /* CONFIG_IPW2200_QOS */ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) @@ -11198,7 +11214,8 @@ static int ipw_up(struct ipw_priv *priv) /* If configure to try and auto-associate, kick * off a scan. */ - queue_work(priv->workqueue, &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); return 0; } @@ -11219,11 +11236,12 @@ static int ipw_up(struct ipw_priv *priv) return -EIO; } -static void ipw_bg_up(void *data) +static void ipw_bg_up(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, up); mutex_lock(&priv->mutex); - ipw_up(data); + ipw_up(priv); mutex_unlock(&priv->mutex); } @@ -11290,11 +11308,12 @@ static void ipw_down(struct ipw_priv *priv) ipw_led_radio_off(priv); } -static void ipw_bg_down(void *data) +static void ipw_bg_down(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, down); mutex_lock(&priv->mutex); - ipw_down(data); + ipw_down(priv); mutex_unlock(&priv->mutex); } diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index dad5eedefbf..626a240a87d 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1290,21 +1290,21 @@ struct ipw_priv { struct workqueue_struct *workqueue; - struct work_struct adhoc_check; + struct delayed_work adhoc_check; struct work_struct associate; struct work_struct disassociate; struct work_struct system_config; struct work_struct rx_replenish; - struct work_struct request_scan; + struct delayed_work request_scan; struct work_struct request_passive_scan; struct work_struct adapter_restart; - struct work_struct rf_kill; + struct delayed_work rf_kill; struct work_struct up; struct work_struct down; - struct work_struct gather_stats; + struct delayed_work gather_stats; struct work_struct abort_scan; struct work_struct roam; - struct work_struct scan_check; + struct delayed_work scan_check; struct work_struct link_up; struct work_struct link_down; @@ -1319,9 +1319,9 @@ struct ipw_priv { u32 led_ofdm_on; u32 led_ofdm_off; - struct work_struct led_link_on; - struct work_struct led_link_off; - struct work_struct led_act_off; + struct delayed_work led_link_on; + struct delayed_work led_link_off; + struct delayed_work led_act_off; struct work_struct merge_networks; struct ipw_cmd_log *cmdlog; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 6714e0dfa8d..644b4741ef7 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -735,10 +735,7 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int netwave_pcmcia_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; netwave_private *priv = netdev_priv(dev); - tuple_t tuple; - cisparse_t parse; int i, j, last_ret, last_fn; - u_char buf[64]; win_req_t req; memreq_t mem; u_char __iomem *ramBase = NULL; @@ -746,21 +743,6 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.Attributes = 0; - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* * Try allocating IO ports. This tries a few fixed addresses. * If you want, you can also read the card's config table to * pick addresses -- see the serial driver for an example. diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 336cabac13b..936c888e03e 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -980,9 +980,11 @@ static void print_linkstatus(struct net_device *dev, u16 status) } /* Search scan results for requested BSSID, join it if found */ -static void orinoco_join_ap(struct net_device *dev) +static void orinoco_join_ap(struct work_struct *work) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = + container_of(work, struct orinoco_private, join_work); + struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; int err; unsigned long flags; @@ -1055,9 +1057,11 @@ static void orinoco_join_ap(struct net_device *dev) } /* Send new BSSID to userspace */ -static void orinoco_send_wevents(struct net_device *dev) +static void orinoco_send_wevents(struct work_struct *work) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = + container_of(work, struct orinoco_private, wevent_work); + struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; union iwreq_data wrqu; int err; @@ -1864,9 +1868,11 @@ __orinoco_set_multicast_list(struct net_device *dev) /* This must be called from user context, without locks held - use * schedule_work() */ -static void orinoco_reset(struct net_device *dev) +static void orinoco_reset(struct work_struct *work) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = + container_of(work, struct orinoco_private, reset_work); + struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; int err; unsigned long flags; @@ -2434,9 +2440,9 @@ struct net_device *alloc_orinocodev(int sizeof_card, priv->hw_unavailable = 1; /* orinoco_init() must clear this * before anything else touches the * hardware */ - INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); - INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev); - INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev); + INIT_WORK(&priv->reset_work, orinoco_reset); + INIT_WORK(&priv->join_work, orinoco_join_ap); + INIT_WORK(&priv->wevent_work, orinoco_send_wevents); netif_carrier_off(dev); priv->last_linkstatus = 0xffff; @@ -3608,7 +3614,7 @@ static int orinoco_ioctl_reset(struct net_device *dev, printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); /* Firmware reset */ - orinoco_reset(dev); + orinoco_reset(&priv->reset_work); } else { printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); @@ -4154,7 +4160,7 @@ static int orinoco_ioctl_commit(struct net_device *dev, return 0; if (priv->broken_disableport) { - orinoco_reset(dev); + orinoco_reset(&priv->reset_work); return 0; } diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index bc14689cbf2..d08ae8d2726 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -178,21 +178,6 @@ orinoco_cs_config(struct pcmcia_device *link) cisparse_t parse; void __iomem *mem; - /* - * This reads the card's CONFIG tuple to find its - * configuration registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf)); @@ -211,6 +196,10 @@ orinoco_cs_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index a48edd131d7..96606ed1007 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -157,8 +157,9 @@ prism54_mib_init(islpci_private *priv) * schedule_work(), thus we can as well use sleeping semaphore * locking */ void -prism54_update_stats(islpci_private *priv) +prism54_update_stats(struct work_struct *work) { + islpci_private *priv = container_of(work, islpci_private, stats_work); char *data; int j; struct obj_bss bss, *bss2; @@ -2491,9 +2492,10 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, * interrupt context, no locks held. */ void -prism54_process_trap(void *data) +prism54_process_trap(struct work_struct *work) { - struct islpci_mgmtframe *frame = data; + struct islpci_mgmtframe *frame = + container_of(work, struct islpci_mgmtframe, ws); struct net_device *ndev = frame->ndev; enum oid_num_t n = mgt_oidtonum(frame->header->oid); diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h index e8183d30c52..bcfbfb9281d 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.h +++ b/drivers/net/wireless/prism54/isl_ioctl.h @@ -31,12 +31,12 @@ void prism54_mib_init(islpci_private *); struct iw_statistics *prism54_get_wireless_stats(struct net_device *); -void prism54_update_stats(islpci_private *); +void prism54_update_stats(struct work_struct *); void prism54_acl_init(struct islpci_acl *); void prism54_acl_clean(struct islpci_acl *); -void prism54_process_trap(void *); +void prism54_process_trap(struct work_struct *); void prism54_wpa_bss_ie_init(islpci_private *priv); void prism54_wpa_bss_ie_clean(islpci_private *priv); diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 1e0603ca436..f057fd9fcd7 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -860,11 +860,10 @@ islpci_setup(struct pci_dev *pdev) priv->state_off = 1; /* initialize workqueue's */ - INIT_WORK(&priv->stats_work, - (void (*)(void *)) prism54_update_stats, priv); + INIT_WORK(&priv->stats_work, prism54_update_stats); priv->stats_timestamp = 0; - INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake, priv); + INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake); priv->reset_task_pending = 0; /* allocate various memory areas */ diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 676d83813dc..b1122912ee2 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -480,9 +480,9 @@ islpci_eth_receive(islpci_private *priv) } void -islpci_do_reset_and_wake(void *data) +islpci_do_reset_and_wake(struct work_struct *work) { - islpci_private *priv = data; + islpci_private *priv = container_of(work, islpci_private, reset_task); islpci_reset(priv, 1); priv->reset_task_pending = 0; diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h index 26789454067..5bf820defbd 100644 --- a/drivers/net/wireless/prism54/islpci_eth.h +++ b/drivers/net/wireless/prism54/islpci_eth.h @@ -67,6 +67,6 @@ void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); int islpci_eth_transmit(struct sk_buff *, struct net_device *); int islpci_eth_receive(islpci_private *); void islpci_eth_tx_timeout(struct net_device *); -void islpci_do_reset_and_wake(void *data); +void islpci_do_reset_and_wake(struct work_struct *); #endif /* _ISL_GEN_H */ diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c index 036a875054c..2246f7930b4 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.c +++ b/drivers/net/wireless/prism54/islpci_mgt.c @@ -386,7 +386,7 @@ islpci_mgt_receive(struct net_device *ndev) /* Create work to handle trap out of interrupt * context. */ - INIT_WORK(&frame->ws, prism54_process_trap, frame); + INIT_WORK(&frame->ws, prism54_process_trap); schedule_work(&frame->ws); } else { diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 7fbfc9e41d0..88e10c9bc4a 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -408,11 +408,8 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) #define MAX_TUPLE_SIZE 128 static int ray_config(struct pcmcia_device *link) { - tuple_t tuple; - cisparse_t parse; int last_fn = 0, last_ret = 0; int i; - u_char buf[MAX_TUPLE_SIZE]; win_req_t req; memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; @@ -420,29 +417,12 @@ static int ray_config(struct pcmcia_device *link) DEBUG(1, "ray_config(0x%p)\n", link); - /* This reads the card's CONFIG tuple to find its configuration regs */ - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - tuple.TupleData = buf; - tuple.TupleDataMax = MAX_TUPLE_SIZE; - tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - /* Determine card type and firmware version */ - buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0; - tuple.DesiredTuple = CISTPL_VERS_1; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - tuple.TupleData = buf; - tuple.TupleDataMax = MAX_TUPLE_SIZE; - tuple.TupleOffset = 2; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - - for (i=0; i<tuple.TupleDataLen - 4; i++) - if (buf[i] == 0) buf[i] = ' '; - printk(KERN_INFO "ray_cs Detected: %s\n",buf); + printk(KERN_INFO "ray_cs Detected: %s%s%s%s\n", + link->prod_id[0] ? link->prod_id[0] : " ", + link->prod_id[1] ? link->prod_id[1] : " ", + link->prod_id[2] ? link->prod_id[2] : " ", + link->prod_id[3] ? link->prod_id[3] : " "); /* Now allocate an interrupt line. Note that this does not actually assign a handler to the interrupt. diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index bcc7038130f..cf2d1486b01 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -647,21 +647,6 @@ spectrum_cs_config(struct pcmcia_device *link) cisparse_t parse; void __iomem *mem; - /* - * This reads the card's CONFIG tuple to find its - * configuration registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf)); @@ -681,6 +666,10 @@ spectrum_cs_config(struct pcmcia_device *link) * implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index aafb301041b..233d906c08f 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3939,11 +3939,8 @@ wv_hw_reset(struct net_device * dev) static inline int wv_pcmcia_config(struct pcmcia_device * link) { - tuple_t tuple; - cisparse_t parse; struct net_device * dev = (struct net_device *) link->priv; int i; - u_char buf[64]; win_req_t req; memreq_t mem; net_local * lp = netdev_priv(dev); @@ -3953,36 +3950,6 @@ wv_pcmcia_config(struct pcmcia_device * link) printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); #endif - /* - * This reads the card's CONFIG tuple to find its configuration - * registers. - */ - do - { - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - i = pcmcia_get_first_tuple(link, &tuple); - if(i != CS_SUCCESS) - break; - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - i = pcmcia_get_tuple_data(link, &tuple); - if(i != CS_SUCCESS) - break; - i = pcmcia_parse_tuple(link, &tuple, &parse); - if(i != CS_SUCCESS) - break; - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - } - while(0); - if(i != CS_SUCCESS) - { - cs_error(link, ParseTuple, i); - return FALSE; - } - do { i = pcmcia_request_io(link, &link->io); diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 5b98a787698..583e0d655a9 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1966,25 +1966,10 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) */ static int wl3501_config(struct pcmcia_device *link) { - tuple_t tuple; - cisparse_t parse; struct net_device *dev = link->priv; int i = 0, j, last_fn, last_ret; - unsigned char bf[64]; struct wl3501_card *this; - /* This reads the card's CONFIG tuple to find its config registers. */ - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - tuple.TupleData = bf; - tuple.TupleDataMax = sizeof(bf); - tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - /* Try allocating IO ports. This tries a few fixed addresses. If you * want, you can also read the card's config table to pick addresses -- * see the serial driver for an example. */ diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 1dd3f766ff4..61c7916b765 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -32,8 +32,8 @@ static void ieee_init(struct ieee80211_device *ieee); static void softmac_init(struct ieee80211softmac_device *sm); -static void set_rts_cts_work(void *d); -static void set_basic_rates_work(void *d); +static void set_rts_cts_work(struct work_struct *work); +static void set_basic_rates_work(struct work_struct *work); static void housekeeping_init(struct zd_mac *mac); static void housekeeping_enable(struct zd_mac *mac); @@ -50,8 +50,8 @@ int zd_mac_init(struct zd_mac *mac, memset(mac, 0, sizeof(*mac)); spin_lock_init(&mac->lock); mac->netdev = netdev; - INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work, mac); - INIT_WORK(&mac->set_basic_rates_work, set_basic_rates_work, mac); + INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work); + INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work); ieee_init(ieee); softmac_init(ieee80211_priv(netdev)); @@ -407,9 +407,10 @@ static void try_enable_tx(struct zd_mac *mac) spin_unlock_irqrestore(&mac->lock, flags); } -static void set_rts_cts_work(void *d) +static void set_rts_cts_work(struct work_struct *work) { - struct zd_mac *mac = d; + struct zd_mac *mac = + container_of(work, struct zd_mac, set_rts_cts_work.work); unsigned long flags; u8 rts_rate; unsigned int short_preamble; @@ -428,9 +429,10 @@ static void set_rts_cts_work(void *d) try_enable_tx(mac); } -static void set_basic_rates_work(void *d) +static void set_basic_rates_work(struct work_struct *work) { - struct zd_mac *mac = d; + struct zd_mac *mac = + container_of(work, struct zd_mac, set_basic_rates_work.work); unsigned long flags; u16 basic_rates; @@ -508,12 +510,13 @@ static void bssinfo_change(struct net_device *netdev, u32 changes) if (need_set_rts_cts && !mac->updating_rts_rate) { mac->updating_rts_rate = 1; netif_stop_queue(mac->netdev); - queue_work(zd_workqueue, &mac->set_rts_cts_work); + queue_delayed_work(zd_workqueue, &mac->set_rts_cts_work, 0); } if (need_set_rates && !mac->updating_basic_rates) { mac->updating_basic_rates = 1; netif_stop_queue(mac->netdev); - queue_work(zd_workqueue, &mac->set_basic_rates_work); + queue_delayed_work(zd_workqueue, &mac->set_basic_rates_work, + 0); } spin_unlock_irqrestore(&mac->lock, flags); } @@ -1225,9 +1228,10 @@ struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev) #define LINK_LED_WORK_DELAY HZ -static void link_led_handler(void *p) +static void link_led_handler(struct work_struct *work) { - struct zd_mac *mac = p; + struct zd_mac *mac = + container_of(work, struct zd_mac, housekeeping.link_led_work.work); struct zd_chip *chip = &mac->chip; struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev); int is_associated; @@ -1248,7 +1252,7 @@ static void link_led_handler(void *p) static void housekeeping_init(struct zd_mac *mac) { - INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac); + INIT_DELAYED_WORK(&mac->housekeeping.link_led_work, link_led_handler); } static void housekeeping_enable(struct zd_mac *mac) diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 77f1268080e..f0cf05dc7d3 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -119,7 +119,7 @@ struct rx_status { #define ZD_RX_ERROR 0x80 struct housekeeping { - struct work_struct link_led_work; + struct delayed_work link_led_work; }; #define ZD_MAC_STATS_BUFFER_SIZE 16 @@ -135,8 +135,8 @@ struct zd_mac { struct housekeeping housekeeping; struct work_struct set_multicast_hash_work; struct zd_mc_hash multicast_hash; - struct work_struct set_rts_cts_work; - struct work_struct set_basic_rates_work; + struct delayed_work set_rts_cts_work; + struct delayed_work set_basic_rates_work; unsigned int stats_count; u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE]; diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index fc4bc9b94c7..a83c3db7d18 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -29,7 +29,7 @@ struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned; -static void wq_sync_buffer(void *); +static void wq_sync_buffer(struct work_struct *work); #define DEFAULT_TIMER_EXPIRE (HZ / 10) static int work_enabled; @@ -65,7 +65,7 @@ int alloc_cpu_buffers(void) b->sample_received = 0; b->sample_lost_overflow = 0; b->cpu = i; - INIT_WORK(&b->work, wq_sync_buffer, b); + INIT_DELAYED_WORK(&b->work, wq_sync_buffer); } return 0; @@ -282,9 +282,10 @@ void oprofile_add_trace(unsigned long pc) * By using schedule_delayed_work_on and then schedule_delayed_work * we guarantee this will stay on the correct cpu */ -static void wq_sync_buffer(void * data) +static void wq_sync_buffer(struct work_struct *work) { - struct oprofile_cpu_buffer * b = data; + struct oprofile_cpu_buffer * b = + container_of(work, struct oprofile_cpu_buffer, work.work); if (b->cpu != smp_processor_id()) { printk("WQ on CPU%d, prefer CPU%d\n", smp_processor_id(), b->cpu); diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 09abb80e057..49900d9e323 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -43,7 +43,7 @@ struct oprofile_cpu_buffer { unsigned long sample_lost_overflow; unsigned long backtrace_aborted; int cpu; - struct work_struct work; + struct delayed_work work; } ____cacheline_aligned; extern struct oprofile_cpu_buffer cpu_buffer[]; diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index b953d5907c0..e60b4bf6bae 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -166,14 +166,6 @@ static int parport_config(struct pcmcia_device *link) tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); @@ -263,6 +255,7 @@ void parport_cs_release(struct pcmcia_device *link) static struct pcmcia_device_id parport_ids[] = { PCMCIA_DEVICE_FUNC_ID(3), + PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc), PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003), PCMCIA_DEVICE_NULL }; diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index ea2087c3414..50757695844 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -70,7 +70,7 @@ struct slot { struct hotplug_slot *hotplug_slot; struct list_head slot_list; char name[SLOT_NAME_SIZE]; - struct work_struct work; /* work for button event */ + struct delayed_work work; /* work for button event */ struct mutex lock; }; @@ -187,7 +187,7 @@ extern int shpchp_configure_device(struct slot *p_slot); extern int shpchp_unconfigure_device(struct slot *p_slot); extern void shpchp_remove_ctrl_files(struct controller *ctrl); extern void cleanup_slots(struct controller *ctrl); -extern void queue_pushbutton_work(void *data); +extern void queue_pushbutton_work(struct work_struct *work); #ifdef CONFIG_ACPI diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 235c18a2239..4eac85b3d90 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -159,7 +159,7 @@ static int init_slots(struct controller *ctrl) goto error_info; slot->number = sun; - INIT_WORK(&slot->work, queue_pushbutton_work, slot); + INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work); /* register this slot with the hotplug pci core */ hotplug_slot->private = slot; diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index c39901dbff2..158ac783609 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -36,7 +36,7 @@ #include "../pci.h" #include "shpchp.h" -static void interrupt_event_handler(void *data); +static void interrupt_event_handler(struct work_struct *work); static int shpchp_enable_slot(struct slot *p_slot); static int shpchp_disable_slot(struct slot *p_slot); @@ -50,7 +50,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) info->event_type = event_type; info->p_slot = p_slot; - INIT_WORK(&info->work, interrupt_event_handler, info); + INIT_WORK(&info->work, interrupt_event_handler); schedule_work(&info->work); @@ -408,9 +408,10 @@ struct pushbutton_work_info { * Handles all pending events and exits. * */ -static void shpchp_pushbutton_thread(void *data) +static void shpchp_pushbutton_thread(struct work_struct *work) { - struct pushbutton_work_info *info = data; + struct pushbutton_work_info *info = + container_of(work, struct pushbutton_work_info, work); struct slot *p_slot = info->p_slot; mutex_lock(&p_slot->lock); @@ -436,9 +437,9 @@ static void shpchp_pushbutton_thread(void *data) kfree(info); } -void queue_pushbutton_work(void *data) +void queue_pushbutton_work(struct work_struct *work) { - struct slot *p_slot = data; + struct slot *p_slot = container_of(work, struct slot, work.work); struct pushbutton_work_info *info; info = kmalloc(sizeof(*info), GFP_KERNEL); @@ -447,7 +448,7 @@ void queue_pushbutton_work(void *data) return; } info->p_slot = p_slot; - INIT_WORK(&info->work, shpchp_pushbutton_thread, info); + INIT_WORK(&info->work, shpchp_pushbutton_thread); mutex_lock(&p_slot->lock); switch (p_slot->state) { @@ -541,9 +542,9 @@ static void handle_button_press_event(struct slot *p_slot) } } -static void interrupt_event_handler(void *data) +static void interrupt_event_handler(struct work_struct *work) { - struct event_info *info = data; + struct event_info *info = container_of(work, struct event_info, work); struct slot *p_slot = info->p_slot; mutex_lock(&p_slot->lock); diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 04c43ef529a..55866b6b26f 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -160,7 +160,7 @@ static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev) rpc->e_lock = SPIN_LOCK_UNLOCKED; rpc->rpd = dev; - INIT_WORK(&rpc->dpc_handler, aer_isr, (void *)dev); + INIT_WORK(&rpc->dpc_handler, aer_isr); rpc->prod_idx = rpc->cons_idx = 0; mutex_init(&rpc->rpc_mutex); init_waitqueue_head(&rpc->wait_release); diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index daf0cad88fc..3c0a58f64dd 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -118,7 +118,7 @@ extern struct bus_type pcie_port_bus_type; extern void aer_enable_rootport(struct aer_rpc *rpc); extern void aer_delete_rootport(struct aer_rpc *rpc); extern int aer_init(struct pcie_device *dev); -extern void aer_isr(void *context); +extern void aer_isr(struct work_struct *work); extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); extern int aer_osc_setup(struct pci_dev *dev); diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 1c7e660d653..08e13033ced 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -690,14 +690,14 @@ static void aer_isr_one_error(struct pcie_device *p_device, /** * aer_isr - consume errors detected by root port - * @context: pointer to a private data of pcie device + * @work: definition of this work item * * Invoked, as DPC, when root port records new detected error **/ -void aer_isr(void *context) +void aer_isr(struct work_struct *work) { - struct pcie_device *p_device = (struct pcie_device *) context; - struct aer_rpc *rpc = get_service_data(p_device); + struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler); + struct pcie_device *p_device = rpc->rpd; struct aer_err_source *e_src; mutex_lock(&rpc->rpc_mutex); diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index 3bcb7dc3299..b6746301d9a 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -32,10 +32,11 @@ * A0..A10 work in each range; A23 indicates I/O space; A25 is CFRNW; * some other bit in {A24,A22..A11} is nREG to flag memory access * (vs attributes). So more than 2KB/region would just be waste. + * Note: These are offsets from the physical base address. */ -#define CF_ATTR_PHYS (AT91_CF_BASE) -#define CF_IO_PHYS (AT91_CF_BASE + (1 << 23)) -#define CF_MEM_PHYS (AT91_CF_BASE + 0x017ff800) +#define CF_ATTR_PHYS (0) +#define CF_IO_PHYS (1 << 23) +#define CF_MEM_PHYS (0x017ff800) /*--------------------------------------------------------------------------*/ @@ -48,6 +49,8 @@ struct at91_cf_socket { struct platform_device *pdev; struct at91_cf_data *board; + + unsigned long phys_baseaddr; }; #define SZ_2K (2 * SZ_1K) @@ -154,9 +157,8 @@ static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) /* * Use 16 bit accesses unless/until we need 8-bit i/o space. - * Always set CSR4 ... PCMCIA won't always unmap things. */ - csr = at91_sys_read(AT91_SMC_CSR(4)) & ~AT91_SMC_DBW; + csr = at91_sys_read(AT91_SMC_CSR(cf->board->chipselect)) & ~AT91_SMC_DBW; /* * NOTE: this CF controller ignores IOIS16, so we can't really do @@ -168,14 +170,14 @@ static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) * some cards only like that way to get at the odd byte, despite * CF 3.0 spec table 35 also giving the D8-D15 option. */ - if (!(io->flags & (MAP_16BIT|MAP_AUTOSZ))) { + if (!(io->flags & (MAP_16BIT | MAP_AUTOSZ))) { csr |= AT91_SMC_DBW_8; pr_debug("%s: 8bit i/o bus\n", driver_name); } else { csr |= AT91_SMC_DBW_16; pr_debug("%s: 16bit i/o bus\n", driver_name); } - at91_sys_write(AT91_SMC_CSR(4), csr); + at91_sys_write(AT91_SMC_CSR(cf->board->chipselect), csr); io->start = cf->socket.io_offset; io->stop = io->start + SZ_2K - 1; @@ -194,11 +196,11 @@ at91_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map) cf = container_of(s, struct at91_cf_socket, socket); - map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT; + map->flags &= (MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT); if (map->flags & MAP_ATTRIB) - map->static_start = CF_ATTR_PHYS; + map->static_start = cf->phys_baseaddr + CF_ATTR_PHYS; else - map->static_start = CF_MEM_PHYS; + map->static_start = cf->phys_baseaddr + CF_MEM_PHYS; return 0; } @@ -219,7 +221,6 @@ static int __init at91_cf_probe(struct platform_device *pdev) struct at91_cf_socket *cf; struct at91_cf_data *board = pdev->dev.platform_data; struct resource *io; - unsigned int csa; int status; if (!board || !board->det_pin || !board->rst_pin) @@ -235,33 +236,11 @@ static int __init at91_cf_probe(struct platform_device *pdev) cf->board = board; cf->pdev = pdev; + cf->phys_baseaddr = io->start; platform_set_drvdata(pdev, cf); - /* CF takes over CS4, CS5, CS6 */ - csa = at91_sys_read(AT91_EBI_CSA); - at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH); - - /* nWAIT is _not_ a default setting */ - (void) at91_set_A_periph(AT91_PIN_PC6, 1); /* nWAIT */ - - /* - * Static memory controller timing adjustments. - * REVISIT: these timings are in terms of MCK cycles, so - * when MCK changes (cpufreq etc) so must these values... - */ - at91_sys_write(AT91_SMC_CSR(4), - AT91_SMC_ACSS_STD - | AT91_SMC_DBW_16 - | AT91_SMC_BAT - | AT91_SMC_WSEN - | AT91_SMC_NWS_(32) /* wait states */ - | AT91_SMC_RWSETUP_(6) /* setup time */ - | AT91_SMC_RWHOLD_(4) /* hold time */ - ); - /* must be a GPIO; ergo must trigger on both edges */ - status = request_irq(board->det_pin, at91_cf_irq, - IRQF_SAMPLE_RANDOM, driver_name, cf); + status = request_irq(board->det_pin, at91_cf_irq, 0, driver_name, cf); if (status < 0) goto fail0; device_init_wakeup(&pdev->dev, 1); @@ -282,14 +261,18 @@ static int __init at91_cf_probe(struct platform_device *pdev) cf->socket.pci_irq = NR_IRQS + 1; /* pcmcia layer only remaps "real" memory not iospace */ - cf->socket.io_offset = (unsigned long) ioremap(CF_IO_PHYS, SZ_2K); - if (!cf->socket.io_offset) + cf->socket.io_offset = (unsigned long) ioremap(cf->phys_baseaddr + CF_IO_PHYS, SZ_2K); + if (!cf->socket.io_offset) { + status = -ENXIO; goto fail1; + } - /* reserve CS4, CS5, and CS6 regions; but use just CS4 */ + /* reserve chip-select regions */ if (!request_mem_region(io->start, io->end + 1 - io->start, - driver_name)) + driver_name)) { + status = -ENXIO; goto fail1; + } pr_info("%s: irqs det #%d, io #%d\n", driver_name, board->det_pin, board->irq_pin); @@ -319,9 +302,7 @@ fail1: fail0a: device_init_wakeup(&pdev->dev, 0); free_irq(board->det_pin, cf); - device_init_wakeup(&pdev->dev, 0); fail0: - at91_sys_write(AT91_EBI_CSA, csa); kfree(cf); return status; } @@ -331,19 +312,15 @@ static int __exit at91_cf_remove(struct platform_device *pdev) struct at91_cf_socket *cf = platform_get_drvdata(pdev); struct at91_cf_data *board = cf->board; struct resource *io = cf->socket.io[0].res; - unsigned int csa; pcmcia_unregister_socket(&cf->socket); if (board->irq_pin) free_irq(board->irq_pin, cf); - free_irq(board->det_pin, cf); device_init_wakeup(&pdev->dev, 0); + free_irq(board->det_pin, cf); iounmap((void __iomem *) cf->socket.io_offset); release_mem_region(io->start, io->end + 1 - io->start); - csa = at91_sys_read(AT91_EBI_CSA); - at91_sys_write(AT91_EBI_CSA, csa & ~AT91_EBI_CS4A); - kfree(cf); return 0; } diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index d6164cd583f..f573ea04db6 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -135,7 +135,7 @@ int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev, cs_s struct pcmcia_callback{ struct module *owner; int (*event) (struct pcmcia_socket *s, event_t event, int priority); - void (*requery) (struct pcmcia_socket *s); + void (*requery) (struct pcmcia_socket *s, int new_cis); int (*suspend) (struct pcmcia_socket *s); int (*resume) (struct pcmcia_socket *s); }; diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 21d83a895b2..7355eb455a8 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -231,65 +231,6 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) } -#ifdef CONFIG_PCMCIA_LOAD_CIS - -/** - * pcmcia_load_firmware - load CIS from userspace if device-provided is broken - * @dev - the pcmcia device which needs a CIS override - * @filename - requested filename in /lib/firmware/ - * - * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if - * the one provided by the card is broken. The firmware files reside in - * /lib/firmware/ in userspace. - */ -static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) -{ - struct pcmcia_socket *s = dev->socket; - const struct firmware *fw; - char path[20]; - int ret=-ENOMEM; - cisdump_t *cis; - - if (!filename) - return -EINVAL; - - ds_dbg(1, "trying to load firmware %s\n", filename); - - if (strlen(filename) > 14) - return -EINVAL; - - snprintf(path, 20, "%s", filename); - - if (request_firmware(&fw, path, &dev->dev) == 0) { - if (fw->size >= CISTPL_MAX_CIS_SIZE) - goto release; - - cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL); - if (!cis) - goto release; - - cis->Length = fw->size + 1; - memcpy(cis->Data, fw->data, fw->size); - - if (!pcmcia_replace_cis(s, cis)) - ret = 0; - } - release: - release_firmware(fw); - - return (ret); -} - -#else /* !CONFIG_PCMCIA_LOAD_CIS */ - -static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) -{ - return -ENODEV; -} - -#endif - - /*======================================================================*/ @@ -309,6 +250,8 @@ int pcmcia_register_driver(struct pcmcia_driver *driver) driver->drv.bus = &pcmcia_bus_type; driver->drv.owner = driver->owner; + ds_dbg(3, "registering driver %s\n", driver->drv.name); + return driver_register(&driver->drv); } EXPORT_SYMBOL(pcmcia_register_driver); @@ -318,6 +261,7 @@ EXPORT_SYMBOL(pcmcia_register_driver); */ void pcmcia_unregister_driver(struct pcmcia_driver *driver) { + ds_dbg(3, "unregistering driver %s\n", driver->drv.name); driver_unregister(&driver->drv); } EXPORT_SYMBOL(pcmcia_unregister_driver); @@ -343,23 +287,27 @@ void pcmcia_put_dev(struct pcmcia_device *p_dev) static void pcmcia_release_function(struct kref *ref) { struct config_t *c = container_of(ref, struct config_t, ref); + ds_dbg(1, "releasing config_t\n"); kfree(c); } static void pcmcia_release_dev(struct device *dev) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); - ds_dbg(1, "releasing dev %p\n", p_dev); + ds_dbg(1, "releasing device %s\n", p_dev->dev.bus_id); pcmcia_put_socket(p_dev->socket); kfree(p_dev->devname); kref_put(&p_dev->function_config->ref, pcmcia_release_function); kfree(p_dev); } -static void pcmcia_add_pseudo_device(struct pcmcia_socket *s) +static void pcmcia_add_device_later(struct pcmcia_socket *s, int mfc) { if (!s->pcmcia_state.device_add_pending) { + ds_dbg(1, "scheduling to add %s secondary" + " device to %d\n", mfc ? "mfc" : "pfc", s->sock); s->pcmcia_state.device_add_pending = 1; + s->pcmcia_state.mfc_pfc = mfc; schedule_work(&s->device_add); } return; @@ -371,6 +319,7 @@ static int pcmcia_device_probe(struct device * dev) struct pcmcia_driver *p_drv; struct pcmcia_device_id *did; struct pcmcia_socket *s; + cistpl_config_t cis_config; int ret = 0; dev = get_device(dev); @@ -381,15 +330,33 @@ static int pcmcia_device_probe(struct device * dev) p_drv = to_pcmcia_drv(dev->driver); s = p_dev->socket; + ds_dbg(1, "trying to bind %s to %s\n", p_dev->dev.bus_id, + p_drv->drv.name); + if ((!p_drv->probe) || (!p_dev->function_config) || (!try_module_get(p_drv->owner))) { ret = -EINVAL; goto put_dev; } + /* set up some more device information */ + ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG, + &cis_config); + if (!ret) { + p_dev->conf.ConfigBase = cis_config.base; + p_dev->conf.Present = cis_config.rmask[0]; + } else { + printk(KERN_INFO "pcmcia: could not parse base and rmask0 of CIS\n"); + p_dev->conf.ConfigBase = 0; + p_dev->conf.Present = 0; + } + ret = p_drv->probe(p_dev); - if (ret) + if (ret) { + ds_dbg(1, "binding %s to %s failed with %d\n", + p_dev->dev.bus_id, p_drv->drv.name, ret); goto put_module; + } /* handle pseudo multifunction devices: * there are at most two pseudo multifunction devices. @@ -400,7 +367,7 @@ static int pcmcia_device_probe(struct device * dev) did = p_dev->dev.driver_data; if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && (p_dev->socket->device_count == 1) && (p_dev->device_no == 0)) - pcmcia_add_pseudo_device(p_dev->socket); + pcmcia_add_device_later(p_dev->socket, 0); put_module: if (ret) @@ -421,8 +388,8 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le struct pcmcia_device *tmp; unsigned long flags; - ds_dbg(2, "unbind_request(%d)\n", s->sock); - + ds_dbg(2, "pcmcia_card_remove(%d) %s\n", s->sock, + leftover ? leftover->devname : ""); if (!leftover) s->device_count = 0; @@ -439,6 +406,7 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le p_dev->_removed=1; spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + ds_dbg(2, "unregistering device %s\n", p_dev->dev.bus_id); device_unregister(&p_dev->dev); } @@ -455,6 +423,8 @@ static int pcmcia_device_remove(struct device * dev) p_dev = to_pcmcia_dev(dev); p_drv = to_pcmcia_drv(dev->driver); + ds_dbg(1, "removing device %s\n", p_dev->dev.bus_id); + /* If we're removing the primary module driving a * pseudo multi-function card, we need to unbind * all devices @@ -587,8 +557,10 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f mutex_lock(&device_add_lock); - /* max of 2 devices per card */ - if (s->device_count == 2) + ds_dbg(3, "adding device to %d, function %d\n", s->sock, function); + + /* max of 4 devices per card */ + if (s->device_count == 4) goto err_put; p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL); @@ -598,8 +570,6 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f p_dev->socket = s; p_dev->device_no = (s->device_count++); p_dev->func = function; - if (s->functions <= function) - s->functions = function + 1; p_dev->dev.bus = &pcmcia_bus_type; p_dev->dev.parent = s->dev.dev; @@ -610,8 +580,8 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f if (!p_dev->devname) goto err_free; sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id); + ds_dbg(3, "devname is %s\n", p_dev->devname); - /* compat */ spin_lock_irqsave(&pcmcia_dev_list_lock, flags); /* @@ -631,6 +601,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); if (!p_dev->function_config) { + ds_dbg(3, "creating config_t for %s\n", p_dev->dev.bus_id); p_dev->function_config = kzalloc(sizeof(struct config_t), GFP_KERNEL); if (!p_dev->function_config) @@ -674,11 +645,16 @@ static int pcmcia_card_add(struct pcmcia_socket *s) unsigned int no_funcs, i; int ret = 0; - if (!(s->resource_setup_done)) + if (!(s->resource_setup_done)) { + ds_dbg(3, "no resources available, delaying card_add\n"); return -EAGAIN; /* try again, but later... */ + } - if (pcmcia_validate_mem(s)) + if (pcmcia_validate_mem(s)) { + ds_dbg(3, "validating mem resources failed, " + "delaying card_add\n"); return -EAGAIN; /* try again, but later... */ + } ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); if (ret || !cisinfo.Chains) { @@ -690,6 +666,7 @@ static int pcmcia_card_add(struct pcmcia_socket *s) no_funcs = mfc.nfn; else no_funcs = 1; + s->functions = no_funcs; for (i=0; i < no_funcs; i++) pcmcia_device_add(s, i); @@ -698,38 +675,50 @@ static int pcmcia_card_add(struct pcmcia_socket *s) } -static void pcmcia_delayed_add_pseudo_device(void *data) +static void pcmcia_delayed_add_device(struct work_struct *work) { - struct pcmcia_socket *s = data; - pcmcia_device_add(s, 0); + struct pcmcia_socket *s = + container_of(work, struct pcmcia_socket, device_add); + ds_dbg(1, "adding additional device to %d\n", s->sock); + pcmcia_device_add(s, s->pcmcia_state.mfc_pfc); s->pcmcia_state.device_add_pending = 0; + s->pcmcia_state.mfc_pfc = 0; } static int pcmcia_requery(struct device *dev, void * _data) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); - if (!p_dev->dev.driver) + if (!p_dev->dev.driver) { + ds_dbg(1, "update device information for %s\n", + p_dev->dev.bus_id); pcmcia_device_query(p_dev); + } return 0; } -static void pcmcia_bus_rescan(struct pcmcia_socket *skt) +static void pcmcia_bus_rescan(struct pcmcia_socket *skt, int new_cis) { - int no_devices=0; + int no_devices = 0; int ret = 0; unsigned long flags; /* must be called with skt_mutex held */ + ds_dbg(0, "re-scanning socket %d\n", skt->sock); + spin_lock_irqsave(&pcmcia_dev_list_lock, flags); if (list_empty(&skt->devices_list)) - no_devices=1; + no_devices = 1; spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + /* If this is because of a CIS override, start over */ + if (new_cis && !no_devices) + pcmcia_card_remove(skt, NULL); + /* if no devices were added for this socket yet because of * missing resource information or other trouble, we need to * do this now. */ - if (no_devices) { + if (no_devices || new_cis) { ret = pcmcia_card_add(skt); if (ret) return; @@ -747,6 +736,97 @@ static void pcmcia_bus_rescan(struct pcmcia_socket *skt) printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n"); } +#ifdef CONFIG_PCMCIA_LOAD_CIS + +/** + * pcmcia_load_firmware - load CIS from userspace if device-provided is broken + * @dev - the pcmcia device which needs a CIS override + * @filename - requested filename in /lib/firmware/ + * + * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if + * the one provided by the card is broken. The firmware files reside in + * /lib/firmware/ in userspace. + */ +static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) +{ + struct pcmcia_socket *s = dev->socket; + const struct firmware *fw; + char path[20]; + int ret = -ENOMEM; + int no_funcs; + int old_funcs; + cisdump_t *cis; + cistpl_longlink_mfc_t mfc; + + if (!filename) + return -EINVAL; + + ds_dbg(1, "trying to load CIS file %s\n", filename); + + if (strlen(filename) > 14) { + printk(KERN_WARNING "pcmcia: CIS filename is too long\n"); + return -EINVAL; + } + + snprintf(path, 20, "%s", filename); + + if (request_firmware(&fw, path, &dev->dev) == 0) { + if (fw->size >= CISTPL_MAX_CIS_SIZE) { + ret = -EINVAL; + printk(KERN_ERR "pcmcia: CIS override is too big\n"); + goto release; + } + + cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL); + if (!cis) { + ret = -ENOMEM; + goto release; + } + + cis->Length = fw->size + 1; + memcpy(cis->Data, fw->data, fw->size); + + if (!pcmcia_replace_cis(s, cis)) + ret = 0; + else { + printk(KERN_ERR "pcmcia: CIS override failed\n"); + goto release; + } + + + /* update information */ + pcmcia_device_query(dev); + + /* does this cis override add or remove functions? */ + old_funcs = s->functions; + + if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc)) + no_funcs = mfc.nfn; + else + no_funcs = 1; + s->functions = no_funcs; + + if (old_funcs > no_funcs) + pcmcia_card_remove(s, dev); + else if (no_funcs > old_funcs) + pcmcia_add_device_later(s, 1); + } + release: + release_firmware(fw); + + return (ret); +} + +#else /* !CONFIG_PCMCIA_LOAD_CIS */ + +static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) +{ + return -ENODEV; +} + +#endif + + static inline int pcmcia_devmatch(struct pcmcia_device *dev, struct pcmcia_device_id *did) { @@ -813,11 +893,14 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev, * after it has re-checked that there is no possible module * with a prod_id/manf_id/card_id match. */ + ds_dbg(0, "skipping FUNC_ID match for %s until userspace " + "interaction\n", dev->dev.bus_id); if (!dev->allow_func_id_match) return 0; } if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) { + ds_dbg(0, "device %s needs a fake CIS\n", dev->dev.bus_id); if (!dev->socket->fake_cis) pcmcia_load_firmware(dev, did->cisfile); @@ -847,13 +930,21 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { #ifdef CONFIG_PCMCIA_IOCTL /* matching by cardmgr */ - if (p_dev->cardmgr == p_drv) + if (p_dev->cardmgr == p_drv) { + ds_dbg(0, "cardmgr matched %s to %s\n", dev->bus_id, + drv->name); return 1; + } #endif while (did && did->match_flags) { - if (pcmcia_devmatch(p_dev, did)) + ds_dbg(3, "trying to match %s to %s\n", dev->bus_id, + drv->name); + if (pcmcia_devmatch(p_dev, did)) { + ds_dbg(0, "matched %s to %s\n", dev->bus_id, + drv->name); return 1; + } did++; } @@ -1044,6 +1135,8 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) struct pcmcia_driver *p_drv = NULL; int ret = 0; + ds_dbg(2, "suspending %s\n", dev->bus_id); + if (dev->driver) p_drv = to_pcmcia_drv(dev->driver); @@ -1052,12 +1145,18 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) if (p_drv->suspend) { ret = p_drv->suspend(p_dev); - if (ret) + if (ret) { + printk(KERN_ERR "pcmcia: device %s (driver %s) did " + "not want to go to sleep (%d)\n", + p_dev->devname, p_drv->drv.name, ret); goto out; + } } - if (p_dev->device_no == p_dev->func) + if (p_dev->device_no == p_dev->func) { + ds_dbg(2, "releasing configuration for %s\n", dev->bus_id); pcmcia_release_configuration(p_dev); + } out: if (!ret) @@ -1072,6 +1171,8 @@ static int pcmcia_dev_resume(struct device * dev) struct pcmcia_driver *p_drv = NULL; int ret = 0; + ds_dbg(2, "resuming %s\n", dev->bus_id); + if (dev->driver) p_drv = to_pcmcia_drv(dev->driver); @@ -1079,6 +1180,7 @@ static int pcmcia_dev_resume(struct device * dev) goto out; if (p_dev->device_no == p_dev->func) { + ds_dbg(2, "requesting configuration for %s\n", dev->bus_id); ret = pcmcia_request_configuration(p_dev, &p_dev->conf); if (ret) goto out; @@ -1120,12 +1222,14 @@ static int pcmcia_bus_resume_callback(struct device *dev, void * _data) static int pcmcia_bus_resume(struct pcmcia_socket *skt) { + ds_dbg(2, "resuming socket %d\n", skt->sock); bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback); return 0; } static int pcmcia_bus_suspend(struct pcmcia_socket *skt) { + ds_dbg(2, "suspending socket %d\n", skt->sock); if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_suspend_callback)) { pcmcia_bus_resume(skt); @@ -1246,7 +1350,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, init_waitqueue_head(&socket->queue); #endif INIT_LIST_HEAD(&socket->devices_list); - INIT_WORK(&socket->device_add, pcmcia_delayed_add_pseudo_device, socket); + INIT_WORK(&socket->device_add, pcmcia_delayed_add_device); memset(&socket->pcmcia_state, 0, sizeof(u8)); socket->device_count = 0; diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 36fdaa58458..3c22ac4625c 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -398,7 +398,7 @@ static irqreturn_t pcc_interrupt(int irq, void *dev) static void pcc_interrupt_wrapper(u_long data) { debug(3, "m32r_cfc: pcc_interrupt_wrapper:\n"); - pcc_interrupt(0, NULL, NULL); + pcc_interrupt(0, NULL); init_timer(&poll_timer); poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer); diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 310ede575ca..d077870c673 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -594,7 +594,12 @@ static int ds_ioctl(struct inode * inode, struct file * file, err = ret = 0; - if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size); + if (cmd & IOC_IN) { + if (__copy_from_user((char *)buf, uarg, size)) { + err = -EFAULT; + goto free_out; + } + } switch (cmd) { case DS_ADJUST_RESOURCE_INFO: diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index a70f97fdbbd..360c2489654 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -581,10 +581,10 @@ static irqreturn_t pd6729_test(int irq, void *dev) return IRQ_HANDLED; } -static int pd6729_check_irq(int irq, int flags) +static int pd6729_check_irq(int irq) { - if (request_irq(irq, pd6729_test, flags, "x", pd6729_test) != 0) - return -1; + if (request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x", pd6729_test) + != 0) return -1; free_irq(irq, pd6729_test); return 0; } @@ -610,7 +610,7 @@ static u_int __devinit pd6729_isa_scan(void) /* just find interrupts that aren't in use */ for (i = 0; i < 16; i++) - if ((mask0 & (1 << i)) && (pd6729_check_irq(i, 0) == 0)) + if ((mask0 & (1 << i)) && (pd6729_check_irq(i) == 0)) mask |= (1 << i); printk(KERN_INFO "pd6729: ISA irqs = "); diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index 933cd864a5c..b005602d6b5 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -188,7 +188,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, (s->state & SOCKET_PRESENT) && !(s->state & SOCKET_CARDBUS)) { if (try_module_get(s->callback->owner)) { - s->callback->requery(s); + s->callback->requery(s, 0); module_put(s->callback->owner); } } @@ -325,7 +325,7 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz if ((s->callback) && (s->state & SOCKET_PRESENT) && !(s->state & SOCKET_CARDBUS)) { if (try_module_get(s->callback->owner)) { - s->callback->requery(s); + s->callback->requery(s, 1); module_put(s->callback->owner); } } diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 814b9e1873f..828b329e08e 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -53,9 +53,10 @@ static int rtc_dev_open(struct inode *inode, struct file *file) * Routine to poll RTC seconds field for change as often as possible, * after first RTC_UIE use timer to reduce polling */ -static void rtc_uie_task(void *data) +static void rtc_uie_task(struct work_struct *work) { - struct rtc_device *rtc = data; + struct rtc_device *rtc = + container_of(work, struct rtc_device, uie_task); struct rtc_time tm; int num = 0; int err; @@ -411,7 +412,7 @@ static int rtc_dev_add_device(struct class_device *class_dev, spin_lock_init(&rtc->irq_lock); init_waitqueue_head(&rtc->irq_queue); #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL - INIT_WORK(&rtc->uie_task, rtc_uie_task, rtc); + INIT_WORK(&rtc->uie_task, rtc_uie_task); setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); #endif diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index a2cef57d7bc..2af2d9b53d1 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -54,7 +54,7 @@ static void dasd_flush_request_queue(struct dasd_device *); static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); static int dasd_flush_ccw_queue(struct dasd_device *, int); static void dasd_tasklet(struct dasd_device *); -static void do_kick_device(void *data); +static void do_kick_device(struct work_struct *); /* * SECTION: Operations on the device structure. @@ -100,7 +100,7 @@ dasd_alloc_device(void) (unsigned long) device); INIT_LIST_HEAD(&device->ccw_queue); init_timer(&device->timer); - INIT_WORK(&device->kick_work, do_kick_device, device); + INIT_WORK(&device->kick_work, do_kick_device); device->state = DASD_STATE_NEW; device->target = DASD_STATE_NEW; @@ -407,11 +407,9 @@ dasd_change_state(struct dasd_device *device) * event daemon. */ static void -do_kick_device(void *data) +do_kick_device(struct work_struct *work) { - struct dasd_device *device; - - device = (struct dasd_device *) data; + struct dasd_device *device = container_of(work, struct dasd_device, kick_work); dasd_change_state(device); dasd_schedule_bh(device); dasd_put_device(device); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index ad7f7e1c016..26cf2f5ae2e 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -334,7 +334,7 @@ static LIST_HEAD(slow_subchannels_head); static DEFINE_SPINLOCK(slow_subchannel_lock); static void -css_trigger_slow_path(void) +css_trigger_slow_path(struct work_struct *unused) { CIO_TRACE_EVENT(4, "slowpath"); @@ -359,8 +359,7 @@ css_trigger_slow_path(void) spin_unlock_irq(&slow_subchannel_lock); } -typedef void (*workfunc)(void *); -DECLARE_WORK(slow_path_work, (workfunc)css_trigger_slow_path, NULL); +DECLARE_WORK(slow_path_work, css_trigger_slow_path); struct workqueue_struct *slow_path_wq; /* Reprobe subchannel if unregistered. */ @@ -397,7 +396,7 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data) } /* Work function used to reprobe all unregistered subchannels. */ -static void reprobe_all(void *data) +static void reprobe_all(struct work_struct *unused) { int ret; @@ -413,7 +412,7 @@ static void reprobe_all(void *data) need_reprobe); } -DECLARE_WORK(css_reprobe_work, reprobe_all, NULL); +DECLARE_WORK(css_reprobe_work, reprobe_all); /* Schedule reprobing of all unregistered subchannels. */ void css_schedule_reprobe(void) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 6a54334ffe0..e4dc947e74e 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -37,7 +37,7 @@ #include "ap_bus.h" /* Some prototypes. */ -static void ap_scan_bus(void *); +static void ap_scan_bus(struct work_struct *); static void ap_poll_all(unsigned long); static void ap_poll_timeout(unsigned long); static int ap_poll_thread_start(void); @@ -71,7 +71,7 @@ static struct device *ap_root_device = NULL; static struct workqueue_struct *ap_work_queue; static struct timer_list ap_config_timer; static int ap_config_time = AP_CONFIG_TIME; -static DECLARE_WORK(ap_config_work, ap_scan_bus, NULL); +static DECLARE_WORK(ap_config_work, ap_scan_bus); /** * Tasklet & timer for AP request polling. @@ -732,7 +732,7 @@ static void ap_device_release(struct device *dev) kfree(ap_dev); } -static void ap_scan_bus(void *data) +static void ap_scan_bus(struct work_struct *unused) { struct ap_device *ap_dev; struct device *dev; diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 08d4e47070b..e5665b6743a 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -67,7 +67,7 @@ static char debug_buffer[255]; * Some prototypes. */ static void lcs_tasklet(unsigned long); -static void lcs_start_kernel_thread(struct lcs_card *card); +static void lcs_start_kernel_thread(struct work_struct *); static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *); static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *); static int lcs_recovery(void *ptr); @@ -1724,8 +1724,9 @@ lcs_stopcard(struct lcs_card *card) * Kernel Thread helper functions for LGW initiated commands */ static void -lcs_start_kernel_thread(struct lcs_card *card) +lcs_start_kernel_thread(struct work_struct *work) { + struct lcs_card *card = container_of(work, struct lcs_card, kernel_thread_starter); LCS_DBF_TEXT(5, trace, "krnthrd"); if (lcs_do_start_thread(card, LCS_RECOVERY_THREAD)) kernel_thread(lcs_recovery, (void *) card, SIGCHLD); @@ -2053,8 +2054,7 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev) ccwgdev->cdev[0]->handler = lcs_irq; ccwgdev->cdev[1]->handler = lcs_irq; card->gdev = ccwgdev; - INIT_WORK(&card->kernel_thread_starter, - (void *) lcs_start_kernel_thread, card); + INIT_WORK(&card->kernel_thread_starter, lcs_start_kernel_thread); card->thread_start_mask = 0; card->thread_allowed_mask = 0; card->thread_running_mask = 0; diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 7fdc5272c44..2bde4f1fb9c 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -1039,8 +1039,9 @@ qeth_do_start_thread(struct qeth_card *card, unsigned long thread) } static void -qeth_start_kernel_thread(struct qeth_card *card) +qeth_start_kernel_thread(struct work_struct *work) { + struct qeth_card *card = container_of(work, struct qeth_card, kernel_thread_starter); QETH_DBF_TEXT(trace , 2, "strthrd"); if (card->read.state != CH_STATE_UP && @@ -1103,8 +1104,7 @@ qeth_setup_card(struct qeth_card *card) card->thread_start_mask = 0; card->thread_allowed_mask = 0; card->thread_running_mask = 0; - INIT_WORK(&card->kernel_thread_starter, - (void *)qeth_start_kernel_thread,card); + INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread); INIT_LIST_HEAD(&card->ip_list); card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); if (!card->ip_tbd_list) { diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 562432d017b..335a25540c0 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -622,8 +622,10 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, dma_unmap_single(hostdata->dev, slot->dma_handle, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE); /* restore the old result if the request sense was * successful */ - if(result == 0) + if (result == 0) result = cmnd[7]; + /* restore the original length */ + SCp->cmd_len = cmnd[8]; } else NCR_700_unmap(hostdata, SCp, slot); @@ -1007,6 +1009,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, * of the command */ cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; cmnd[7] = hostdata->status[0]; + cmnd[8] = SCp->cmd_len; + SCp->cmd_len = 6; /* command length for + * REQUEST_SENSE */ slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE); slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE); slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer)); diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index cdd03372478..3075204915c 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -2186,21 +2186,21 @@ static int __init BusLogic_init(void) if (BusLogic_ProbeOptions.NoProbe) return -ENODEV; - BusLogic_ProbeInfoList = (struct BusLogic_ProbeInfo *) - kmalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), GFP_ATOMIC); + BusLogic_ProbeInfoList = + kzalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), GFP_KERNEL); if (BusLogic_ProbeInfoList == NULL) { BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL); return -ENOMEM; } - memset(BusLogic_ProbeInfoList, 0, BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo)); - PrototypeHostAdapter = (struct BusLogic_HostAdapter *) - kmalloc(sizeof(struct BusLogic_HostAdapter), GFP_ATOMIC); + + PrototypeHostAdapter = + kzalloc(sizeof(struct BusLogic_HostAdapter), GFP_KERNEL); if (PrototypeHostAdapter == NULL) { kfree(BusLogic_ProbeInfoList); BusLogic_Error("BusLogic: Unable to allocate Prototype " "Host Adapter\n", NULL); return -ENOMEM; } - memset(PrototypeHostAdapter, 0, sizeof(struct BusLogic_HostAdapter)); + #ifdef MODULE if (BusLogic != NULL) BusLogic_Setup(BusLogic); diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 9540eb8efdc..69569096dae 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -29,6 +29,13 @@ config SCSI However, do not compile this as a module if your root file system (the one containing the directory /) is located on a SCSI device. +config SCSI_TGT + tristate "SCSI target support" + depends on SCSI && EXPERIMENTAL + ---help--- + If you want to use SCSI target mode drivers enable this option. + If you choose M, the module will be called scsi_tgt. + config SCSI_NETLINK bool default n @@ -216,6 +223,23 @@ config SCSI_LOGGING there should be no noticeable performance impact as long as you have logging turned off. +config SCSI_SCAN_ASYNC + bool "Asynchronous SCSI scanning" + depends on SCSI + help + The SCSI subsystem can probe for devices while the rest of the + system continues booting, and even probe devices on different + busses in parallel, leading to a significant speed-up. + If you have built SCSI as modules, enabling this option can + be a problem as the devices may not have been found by the + time your system expects them to have been. You can load the + scsi_wait_scan module to ensure that all scans have completed. + If you build your SCSI drivers into the kernel, then everything + will work fine if you say Y here. + + You can override this choice by specifying scsi_mod.scan="sync" + or "async" on the kernel's command line. + menu "SCSI Transports" depends on SCSI @@ -797,6 +821,20 @@ config SCSI_IBMVSCSI To compile this driver as a module, choose M here: the module will be called ibmvscsic. +config SCSI_IBMVSCSIS + tristate "IBM Virtual SCSI Server support" + depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP + help + This is the SRP target driver for IBM pSeries virtual environments. + + The userspace component needed to initialize the driver and + documentation can be found: + + http://stgt.berlios.de/ + + To compile this driver as a module, choose M here: the + module will be called ibmvstgt. + config SCSI_INITIO tristate "Initio 9100U(W) support" depends on PCI && SCSI @@ -944,8 +982,13 @@ config SCSI_STEX tristate "Promise SuperTrak EX Series support" depends on PCI && SCSI ---help--- - This driver supports Promise SuperTrak EX8350/8300/16350/16300 - Storage controllers. + This driver supports Promise SuperTrak EX series storage controllers. + + Promise provides Linux RAID configuration utility for these + controllers. Please visit <http://www.promise.com> to download. + + To compile this driver as a module, choose M here: the + module will be called stex. config SCSI_SYM53C8XX_2 tristate "SYM53C8XX Version 2 SCSI support" @@ -1026,6 +1069,7 @@ config SCSI_IPR config SCSI_IPR_TRACE bool "enable driver internal trace" depends on SCSI_IPR + default y help If you say Y here, the driver will trace all commands issued to the adapter. Performance impact is minimal. Trace can be @@ -1034,6 +1078,7 @@ config SCSI_IPR_TRACE config SCSI_IPR_DUMP bool "enable adapter dump support" depends on SCSI_IPR + default y help If you say Y here, the driver will support adapter crash dump. If you enable this support, the iprdump daemon can be used @@ -1734,6 +1779,16 @@ config ZFCP called zfcp. If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. +config SCSI_SRP + tristate "SCSI RDMA Protocol helper library" + depends on SCSI && PCI + select SCSI_TGT + help + If you wish to use SRP target drivers, say Y. + + To compile this driver as a module, choose M here: the + module will be called libsrp. + endmenu source "drivers/scsi/pcmcia/Kconfig" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index bcca39c3bcb..bd7c9888f7f 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -21,6 +21,7 @@ CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM subdir-$(CONFIG_PCMCIA) += pcmcia obj-$(CONFIG_SCSI) += scsi_mod.o +obj-$(CONFIG_SCSI_TGT) += scsi_tgt.o obj-$(CONFIG_RAID_ATTRS) += raid_class.o @@ -125,7 +126,9 @@ obj-$(CONFIG_SCSI_FCAL) += fcal.o obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o obj-$(CONFIG_SCSI_IPR) += ipr.o +obj-$(CONFIG_SCSI_SRP) += libsrp.o obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ +obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/ obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o obj-$(CONFIG_SCSI_STEX) += stex.o @@ -141,6 +144,8 @@ obj-$(CONFIG_CHR_DEV_SCH) += ch.o # This goes last, so that "real" scsi devices probe earlier obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o +obj-$(CONFIG_SCSI) += scsi_wait_scan.o + scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ scsicam.o scsi_error.o scsi_lib.o \ scsi_scan.o scsi_sysfs.o \ @@ -149,6 +154,8 @@ scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o +scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o + sd_mod-objs := sd.o sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \ diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index a6aa9107288..bb3cb336054 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -849,7 +849,7 @@ static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags) hostdata->issue_queue = NULL; hostdata->disconnected_queue = NULL; - INIT_WORK(&hostdata->coroutine, NCR5380_main, hostdata); + INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main); #ifdef NCR5380_STATS for (i = 0; i < 8; ++i) { @@ -1016,7 +1016,7 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) /* Run the coroutine if it isn't already running. */ /* Kick off command processing */ - schedule_work(&hostdata->coroutine); + schedule_delayed_work(&hostdata->coroutine, 0); return 0; } @@ -1033,9 +1033,10 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) * host lock and called routines may take the isa dma lock. */ -static void NCR5380_main(void *p) +static void NCR5380_main(struct work_struct *work) { - struct NCR5380_hostdata *hostdata = p; + struct NCR5380_hostdata *hostdata = + container_of(work, struct NCR5380_hostdata, coroutine.work); struct Scsi_Host *instance = hostdata->host; Scsi_Cmnd *tmp, *prev; int done; @@ -1221,7 +1222,7 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id) } /* if BASR_IRQ */ spin_unlock_irqrestore(instance->host_lock, flags); if(!done) - schedule_work(&hostdata->coroutine); + schedule_delayed_work(&hostdata->coroutine, 0); } while (!done); return IRQ_HANDLED; } diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 1bc73de496b..713a108c02e 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -271,7 +271,7 @@ struct NCR5380_hostdata { unsigned long time_expires; /* in jiffies, set prior to sleeping */ int select_time; /* timer in select for target response */ volatile Scsi_Cmnd *selecting; - struct work_struct coroutine; /* our co-routine */ + struct delayed_work coroutine; /* our co-routine */ #ifdef NCR5380_STATS unsigned timebase; /* Base for time calcs */ long time_read[8]; /* time to do reads */ @@ -298,7 +298,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance); #ifndef DONT_USE_INTR static irqreturn_t NCR5380_intr(int irq, void *dev_id); #endif -static void NCR5380_main(void *ptr); +static void NCR5380_main(struct work_struct *work); static void NCR5380_print_options(struct Scsi_Host *instance); #ifdef NDEBUG static void NCR5380_print_phase(struct Scsi_Host *instance); diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index d4613815f68..8578555d58f 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -220,9 +220,11 @@ static void *addresses[] = { static unsigned short ports[] = { 0x230, 0x330, 0x280, 0x290, 0x330, 0x340, 0x300, 0x310, 0x348, 0x350 }; #define PORT_COUNT ARRAY_SIZE(ports) +#ifndef MODULE /* possible interrupt channels */ static unsigned short intrs[] = { 10, 11, 12, 15 }; #define INTR_COUNT ARRAY_SIZE(intrs) +#endif /* !MODULE */ /* signatures for NCR 53c406a based controllers */ #if USE_BIOS @@ -605,6 +607,7 @@ static int NCR53c406a_release(struct Scsi_Host *shost) return 0; } +#ifndef MODULE /* called from init/main.c */ static int __init NCR53c406a_setup(char *str) { @@ -661,6 +664,8 @@ static int __init NCR53c406a_setup(char *str) __setup("ncr53c406a=", NCR53c406a_setup); +#endif /* !MODULE */ + static const char *NCR53c406a_info(struct Scsi_Host *SChost) { DEB(printk("NCR53c406a_info called\n")); diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index eb3ed91bac7..4f8b4c53d43 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -11,8 +11,8 @@ *----------------------------------------------------------------------------*/ #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 2409 -# define AAC_DRIVER_BRANCH "-mh2" +# define AAC_DRIVER_BUILD 2423 +# define AAC_DRIVER_BRANCH "-mh3" #endif #define MAXIMUM_NUM_CONTAINERS 32 diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 19e42ac07cb..4893a6d06a3 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -518,6 +518,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, */ unsigned long count = 36000000L; /* 3 minutes */ while (down_trylock(&fibptr->event_wait)) { + int blink; if (--count == 0) { spin_lock_irqsave(q->lock, qflags); q->numpending--; @@ -530,6 +531,14 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, } return -ETIMEDOUT; } + if ((blink = aac_adapter_check_health(dev)) > 0) { + if (wait == -1) { + printk(KERN_ERR "aacraid: aac_fib_send: adapter blinkLED 0x%x.\n" + "Usually a result of a serious unrecoverable hardware problem\n", + blink); + } + return -EFAULT; + } udelay(5); } } else if (down_interruptible(&fibptr->event_wait)) { @@ -1093,6 +1102,20 @@ static int _aac_reset_adapter(struct aac_dev *aac) goto out; } + /* + * Loop through the fibs, close the synchronous FIBS + */ + for (index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) { + struct fib *fib = &aac->fibs[index]; + if (!(fib->hw_fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) && + (fib->hw_fib->header.XferState & cpu_to_le32(ResponseExpected))) { + unsigned long flagv; + spin_lock_irqsave(&fib->event_lock, flagv); + up(&fib->event_wait); + spin_unlock_irqrestore(&fib->event_lock, flagv); + schedule(); + } + } index = aac->cardtype; /* diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 306f46b85a5..0cec742d12e 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -1443,7 +1443,7 @@ static struct work_struct aha152x_tq; * Run service completions on the card with interrupts enabled. * */ -static void run(void) +static void run(struct work_struct *work) { struct aha152x_hostdata *hd; @@ -1499,7 +1499,7 @@ static irqreturn_t intr(int irqno, void *dev_id) HOSTDATA(shpnt)->service=1; /* Poke the BH handler */ - INIT_WORK(&aha152x_tq, (void *) run, NULL); + INIT_WORK(&aha152x_tq, run); schedule_work(&aha152x_tq); } DO_UNLOCK(flags); diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index c3c38a7e8d3..d7af9c63a04 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -586,7 +586,7 @@ static struct scsi_host_template aha1740_template = { static int aha1740_probe (struct device *dev) { - int slotbase; + int slotbase, rc; unsigned int irq_level, irq_type, translation; struct Scsi_Host *shpnt; struct aha1740_hostdata *host; @@ -641,10 +641,16 @@ static int aha1740_probe (struct device *dev) } eisa_set_drvdata (edev, shpnt); - scsi_add_host (shpnt, dev); /* XXX handle failure */ + + rc = scsi_add_host (shpnt, dev); + if (rc) + goto err_irq; + scsi_scan_host (shpnt); return 0; + err_irq: + free_irq(irq_level, shpnt); err_unmap: dma_unmap_single (&edev->dev, host->ecb_dma_addr, sizeof (host->ecb), DMA_BIDIRECTIONAL); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 2001fe890e7..1a3ab6aa856 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -62,6 +62,7 @@ static struct pci_device_id ahd_linux_pci_id_table[] = { /* aic7901 based controllers */ ID(ID_AHA_29320A), ID(ID_AHA_29320ALP), + ID(ID_AHA_29320LPE), /* aic7902 based controllers */ ID(ID_AHA_29320), ID(ID_AHA_29320B), diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index c07735819cd..2cf7bb3123f 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -109,7 +109,13 @@ static struct ahd_pci_identity ahd_pci_ident_table [] = { ID_AHA_29320ALP, ID_ALL_MASK, - "Adaptec 29320ALP Ultra320 SCSI adapter", + "Adaptec 29320ALP PCIx Ultra320 SCSI adapter", + ahd_aic7901_setup + }, + { + ID_AHA_29320LPE, + ID_ALL_MASK, + "Adaptec 29320LPE PCIe Ultra320 SCSI adapter", ahd_aic7901_setup }, /* aic7901A based controllers */ diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.h b/drivers/scsi/aic7xxx/aic79xx_pci.h index da45153668c..16b7c70a673 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.h +++ b/drivers/scsi/aic7xxx/aic79xx_pci.h @@ -51,6 +51,7 @@ #define ID_AIC7901 0x800F9005FFFF9005ull #define ID_AHA_29320A 0x8000900500609005ull #define ID_AHA_29320ALP 0x8017900500449005ull +#define ID_AHA_29320LPE 0x8017900500459005ull #define ID_AIC7901A 0x801E9005FFFF9005ull #define ID_AHA_29320LP 0x8014900500449005ull diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 57c5ba4043f..42302ef05ee 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -724,6 +724,15 @@ static void asd_free_queues(struct asd_ha_struct *asd_ha) list_for_each_safe(pos, n, &pending) { struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list); + /* + * Delete unexpired ascb timers. This may happen if we issue + * a CONTROL PHY scb to an adapter and rmmod before the scb + * times out. Apparently we don't wait for the CONTROL PHY + * to complete, so it doesn't matter if we kill the timer. + */ + del_timer_sync(&ascb->timer); + WARN_ON(ascb->scb->header.opcode != CONTROL_PHY); + list_del_init(pos); ASD_DPRINTK("freeing from pending\n"); asd_ascb_free(ascb); diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index b15caf1c8fa..75ed6b0569d 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -25,6 +25,7 @@ */ #include <linux/pci.h> +#include <scsi/scsi_host.h> #include "aic94xx.h" #include "aic94xx_reg.h" @@ -412,6 +413,40 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id) } } +/* hard reset a phy later */ +static void do_phy_reset_later(struct work_struct *work) +{ + struct sas_phy *sas_phy = + container_of(work, struct sas_phy, reset_work); + int error; + + ASD_DPRINTK("%s: About to hard reset phy %d\n", __FUNCTION__, + sas_phy->identify.phy_identifier); + /* Reset device port */ + error = sas_phy_reset(sas_phy, 1); + if (error) + ASD_DPRINTK("%s: Hard reset of phy %d failed (%d).\n", + __FUNCTION__, sas_phy->identify.phy_identifier, error); +} + +static void phy_reset_later(struct sas_phy *sas_phy, struct Scsi_Host *shost) +{ + INIT_WORK(&sas_phy->reset_work, do_phy_reset_later); + queue_work(shost->work_q, &sas_phy->reset_work); +} + +/* start up the ABORT TASK tmf... */ +static void task_kill_later(struct asd_ascb *ascb) +{ + struct asd_ha_struct *asd_ha = ascb->ha; + struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; + struct Scsi_Host *shost = sas_ha->core.shost; + struct sas_task *task = ascb->uldd_task; + + INIT_WORK(&task->abort_work, sas_task_abort); + queue_work(shost->work_q, &task->abort_work); +} + static void escb_tasklet_complete(struct asd_ascb *ascb, struct done_list_struct *dl) { @@ -439,6 +474,74 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, ascb->scb->header.opcode); } + /* Catch these before we mask off the sb_opcode bits */ + switch (sb_opcode) { + case REQ_TASK_ABORT: { + struct asd_ascb *a, *b; + u16 tc_abort; + + tc_abort = *((u16*)(&dl->status_block[1])); + tc_abort = le16_to_cpu(tc_abort); + + ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n", + __FUNCTION__, dl->status_block[3]); + + /* Find the pending task and abort it. */ + list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) + if (a->tc_index == tc_abort) { + task_kill_later(a); + break; + } + goto out; + } + case REQ_DEVICE_RESET: { + struct Scsi_Host *shost = sas_ha->core.shost; + struct sas_phy *dev_phy; + struct asd_ascb *a; + u16 conn_handle; + + conn_handle = *((u16*)(&dl->status_block[1])); + conn_handle = le16_to_cpu(conn_handle); + + ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__, + dl->status_block[3]); + + /* Kill all pending tasks and reset the device */ + dev_phy = NULL; + list_for_each_entry(a, &asd_ha->seq.pend_q, list) { + struct sas_task *task; + struct domain_device *dev; + u16 x; + + task = a->uldd_task; + if (!task) + continue; + dev = task->dev; + + x = (unsigned long)dev->lldd_dev; + if (x == conn_handle) { + dev_phy = dev->port->phy; + task_kill_later(a); + } + } + + /* Reset device port */ + if (!dev_phy) { + ASD_DPRINTK("%s: No pending commands; can't reset.\n", + __FUNCTION__); + goto out; + } + phy_reset_later(dev_phy, shost); + goto out; + } + case SIGNAL_NCQ_ERROR: + ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __FUNCTION__); + goto out; + case CLEAR_NCQ_ERROR: + ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __FUNCTION__); + goto out; + } + sb_opcode &= ~DL_PHY_MASK; switch (sb_opcode) { @@ -469,22 +572,6 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, asd_deform_port(asd_ha, phy); sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT); break; - case REQ_TASK_ABORT: - ASD_DPRINTK("%s: phy%d: REQ_TASK_ABORT\n", __FUNCTION__, - phy_id); - break; - case REQ_DEVICE_RESET: - ASD_DPRINTK("%s: phy%d: REQ_DEVICE_RESET\n", __FUNCTION__, - phy_id); - break; - case SIGNAL_NCQ_ERROR: - ASD_DPRINTK("%s: phy%d: SIGNAL_NCQ_ERROR\n", __FUNCTION__, - phy_id); - break; - case CLEAR_NCQ_ERROR: - ASD_DPRINTK("%s: phy%d: CLEAR_NCQ_ERROR\n", __FUNCTION__, - phy_id); - break; default: ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__, phy_id, sb_opcode); @@ -504,7 +591,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, break; } - +out: asd_invalidate_edb(ascb, edb); } diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c index ef8285c326e..668569e8856 100644 --- a/drivers/scsi/fd_mcs.c +++ b/drivers/scsi/fd_mcs.c @@ -294,6 +294,7 @@ static struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL }; static int user_fifo_count = 0; static int user_fifo_size = 0; +#ifndef MODULE static int __init fd_mcs_setup(char *str) { static int done_setup = 0; @@ -311,6 +312,7 @@ static int __init fd_mcs_setup(char *str) } __setup("fd_mcs=", fd_mcs_setup); +#endif /* !MODULE */ static void print_banner(struct Scsi_Host *shpnt) { diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 68ef1636678..38c3a291efa 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -263,6 +263,10 @@ static void scsi_host_dev_release(struct device *dev) kthread_stop(shost->ehandler); if (shost->work_q) destroy_workqueue(shost->work_q); + if (shost->uspace_req_q) { + kfree(shost->uspace_req_q->queuedata); + scsi_free_queue(shost->uspace_req_q); + } scsi_destroy_command_freelist(shost); if (shost->bqt) @@ -301,8 +305,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) if (!shost) return NULL; - spin_lock_init(&shost->default_lock); - scsi_assign_lock(shost, &shost->default_lock); + shost->host_lock = &shost->default_lock; + spin_lock_init(shost->host_lock); shost->shost_state = SHOST_CREATED; INIT_LIST_HEAD(&shost->__devices); INIT_LIST_HEAD(&shost->__targets); diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile index 4e247b6b870..6ac0633d545 100644 --- a/drivers/scsi/ibmvscsi/Makefile +++ b/drivers/scsi/ibmvscsi/Makefile @@ -3,3 +3,5 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o ibmvscsic-y += ibmvscsi.o ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o + +obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c new file mode 100644 index 00000000000..e28260f05d6 --- /dev/null +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -0,0 +1,960 @@ +/* + * IBM eServer i/pSeries Virtual SCSI Target Driver + * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp. + * Santiago Leon (santil@us.ibm.com) IBM Corp. + * Linda Xie (lxie@us.ibm.com) IBM Corp. + * + * Copyright (C) 2005-2006 FUJITA Tomonori <tomof@acm.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +#include <linux/interrupt.h> +#include <linux/module.h> +#include <scsi/scsi.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_tgt.h> +#include <scsi/libsrp.h> +#include <asm/hvcall.h> +#include <asm/iommu.h> +#include <asm/prom.h> +#include <asm/vio.h> + +#include "ibmvscsi.h" + +#define INITIAL_SRP_LIMIT 16 +#define DEFAULT_MAX_SECTORS 512 + +#define TGT_NAME "ibmvstgt" + +/* + * Hypervisor calls. + */ +#define h_copy_rdma(l, sa, sb, da, db) \ + plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db) +#define h_send_crq(ua, l, h) \ + plpar_hcall_norets(H_SEND_CRQ, ua, l, h) +#define h_reg_crq(ua, tok, sz)\ + plpar_hcall_norets(H_REG_CRQ, ua, tok, sz); +#define h_free_crq(ua) \ + plpar_hcall_norets(H_FREE_CRQ, ua); + +/* tmp - will replace with SCSI logging stuff */ +#define eprintk(fmt, args...) \ +do { \ + printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \ +} while (0) +/* #define dprintk eprintk */ +#define dprintk(fmt, args...) + +struct vio_port { + struct vio_dev *dma_dev; + + struct crq_queue crq_queue; + struct work_struct crq_work; + + unsigned long liobn; + unsigned long riobn; + struct srp_target *target; +}; + +static struct workqueue_struct *vtgtd; + +/* + * These are fixed for the system and come from the Open Firmware device tree. + * We just store them here to save getting them every time. + */ +static char system_id[64] = ""; +static char partition_name[97] = "UNKNOWN"; +static unsigned int partition_number = -1; + +static struct vio_port *target_to_port(struct srp_target *target) +{ + return (struct vio_port *) target->ldata; +} + +static inline union viosrp_iu *vio_iu(struct iu_entry *iue) +{ + return (union viosrp_iu *) (iue->sbuf->buf); +} + +static int send_iu(struct iu_entry *iue, uint64_t length, uint8_t format) +{ + struct srp_target *target = iue->target; + struct vio_port *vport = target_to_port(target); + long rc, rc1; + union { + struct viosrp_crq cooked; + uint64_t raw[2]; + } crq; + + /* First copy the SRP */ + rc = h_copy_rdma(length, vport->liobn, iue->sbuf->dma, + vport->riobn, iue->remote_token); + + if (rc) + eprintk("Error %ld transferring data\n", rc); + + crq.cooked.valid = 0x80; + crq.cooked.format = format; + crq.cooked.reserved = 0x00; + crq.cooked.timeout = 0x00; + crq.cooked.IU_length = length; + crq.cooked.IU_data_ptr = vio_iu(iue)->srp.rsp.tag; + + if (rc == 0) + crq.cooked.status = 0x99; /* Just needs to be non-zero */ + else + crq.cooked.status = 0x00; + + rc1 = h_send_crq(vport->dma_dev->unit_address, crq.raw[0], crq.raw[1]); + + if (rc1) { + eprintk("%ld sending response\n", rc1); + return rc1; + } + + return rc; +} + +#define SRP_RSP_SENSE_DATA_LEN 18 + +static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc, + unsigned char status, unsigned char asc) +{ + union viosrp_iu *iu = vio_iu(iue); + uint64_t tag = iu->srp.rsp.tag; + + /* If the linked bit is on and status is good */ + if (test_bit(V_LINKED, &iue->flags) && (status == NO_SENSE)) + status = 0x10; + + memset(iu, 0, sizeof(struct srp_rsp)); + iu->srp.rsp.opcode = SRP_RSP; + iu->srp.rsp.req_lim_delta = 1; + iu->srp.rsp.tag = tag; + + if (test_bit(V_DIOVER, &iue->flags)) + iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER; + + iu->srp.rsp.data_in_res_cnt = 0; + iu->srp.rsp.data_out_res_cnt = 0; + + iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; + + iu->srp.rsp.resp_data_len = 0; + iu->srp.rsp.status = status; + if (status) { + uint8_t *sense = iu->srp.rsp.data; + + if (sc) { + iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; + iu->srp.rsp.sense_data_len = SCSI_SENSE_BUFFERSIZE; + memcpy(sense, sc->sense_buffer, SCSI_SENSE_BUFFERSIZE); + } else { + iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION; + iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; + iu->srp.rsp.sense_data_len = SRP_RSP_SENSE_DATA_LEN; + + /* Valid bit and 'current errors' */ + sense[0] = (0x1 << 7 | 0x70); + /* Sense key */ + sense[2] = status; + /* Additional sense length */ + sense[7] = 0xa; /* 10 bytes */ + /* Additional sense code */ + sense[12] = asc; + } + } + + send_iu(iue, sizeof(iu->srp.rsp) + SRP_RSP_SENSE_DATA_LEN, + VIOSRP_SRP_FORMAT); + + return 0; +} + +static void handle_cmd_queue(struct srp_target *target) +{ + struct Scsi_Host *shost = target->shost; + struct iu_entry *iue; + struct srp_cmd *cmd; + unsigned long flags; + int err; + +retry: + spin_lock_irqsave(&target->lock, flags); + + list_for_each_entry(iue, &target->cmd_queue, ilist) { + if (!test_and_set_bit(V_FLYING, &iue->flags)) { + spin_unlock_irqrestore(&target->lock, flags); + cmd = iue->sbuf->buf; + err = srp_cmd_queue(shost, cmd, iue, 0); + if (err) { + eprintk("cannot queue cmd %p %d\n", cmd, err); + srp_iu_put(iue); + } + goto retry; + } + } + + spin_unlock_irqrestore(&target->lock, flags); +} + +static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg, + struct srp_direct_buf *md, int nmd, + enum dma_data_direction dir, unsigned int rest) +{ + struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; + struct srp_target *target = iue->target; + struct vio_port *vport = target_to_port(target); + dma_addr_t token; + long err; + unsigned int done = 0; + int i, sidx, soff; + + sidx = soff = 0; + token = sg_dma_address(sg + sidx); + + for (i = 0; i < nmd && rest; i++) { + unsigned int mdone, mlen; + + mlen = min(rest, md[i].len); + for (mdone = 0; mlen;) { + int slen = min(sg_dma_len(sg + sidx) - soff, mlen); + + if (dir == DMA_TO_DEVICE) + err = h_copy_rdma(slen, + vport->riobn, + md[i].va + mdone, + vport->liobn, + token + soff); + else + err = h_copy_rdma(slen, + vport->liobn, + token + soff, + vport->riobn, + md[i].va + mdone); + + if (err != H_SUCCESS) { + eprintk("rdma error %d %d\n", dir, slen); + goto out; + } + + mlen -= slen; + mdone += slen; + soff += slen; + done += slen; + + if (soff == sg_dma_len(sg + sidx)) { + sidx++; + soff = 0; + token = sg_dma_address(sg + sidx); + + if (sidx > nsg) { + eprintk("out of sg %p %d %d\n", + iue, sidx, nsg); + goto out; + } + } + }; + + rest -= mlen; + } +out: + + return 0; +} + +static int ibmvstgt_transfer_data(struct scsi_cmnd *sc, + void (*done)(struct scsi_cmnd *)) +{ + struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; + int err; + + err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); + + done(sc); + + return err; +} + +static int ibmvstgt_cmd_done(struct scsi_cmnd *sc, + void (*done)(struct scsi_cmnd *)) +{ + unsigned long flags; + struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; + struct srp_target *target = iue->target; + + dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]); + + spin_lock_irqsave(&target->lock, flags); + list_del(&iue->ilist); + spin_unlock_irqrestore(&target->lock, flags); + + if (sc->result != SAM_STAT_GOOD) { + eprintk("operation failed %p %d %x\n", + iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]); + send_rsp(iue, sc, HARDWARE_ERROR, 0x00); + } else + send_rsp(iue, sc, NO_SENSE, 0x00); + + done(sc); + srp_iu_put(iue); + return 0; +} + +int send_adapter_info(struct iu_entry *iue, + dma_addr_t remote_buffer, uint16_t length) +{ + struct srp_target *target = iue->target; + struct vio_port *vport = target_to_port(target); + struct Scsi_Host *shost = target->shost; + dma_addr_t data_token; + struct mad_adapter_info_data *info; + int err; + + info = dma_alloc_coherent(target->dev, sizeof(*info), &data_token, + GFP_KERNEL); + if (!info) { + eprintk("bad dma_alloc_coherent %p\n", target); + return 1; + } + + /* Get remote info */ + err = h_copy_rdma(sizeof(*info), vport->riobn, remote_buffer, + vport->liobn, data_token); + if (err == H_SUCCESS) { + dprintk("Client connect: %s (%d)\n", + info->partition_name, info->partition_number); + } + + memset(info, 0, sizeof(*info)); + + strcpy(info->srp_version, "16.a"); + strncpy(info->partition_name, partition_name, + sizeof(info->partition_name)); + info->partition_number = partition_number; + info->mad_version = 1; + info->os_type = 2; + info->port_max_txu[0] = shost->hostt->max_sectors << 9; + + /* Send our info to remote */ + err = h_copy_rdma(sizeof(*info), vport->liobn, data_token, + vport->riobn, remote_buffer); + + dma_free_coherent(target->dev, sizeof(*info), info, data_token); + + if (err != H_SUCCESS) { + eprintk("Error sending adapter info %d\n", err); + return 1; + } + + return 0; +} + +static void process_login(struct iu_entry *iue) +{ + union viosrp_iu *iu = vio_iu(iue); + struct srp_login_rsp *rsp = &iu->srp.login_rsp; + uint64_t tag = iu->srp.rsp.tag; + + /* TODO handle case that requested size is wrong and + * buffer format is wrong + */ + memset(iu, 0, sizeof(struct srp_login_rsp)); + rsp->opcode = SRP_LOGIN_RSP; + rsp->req_lim_delta = INITIAL_SRP_LIMIT; + rsp->tag = tag; + rsp->max_it_iu_len = sizeof(union srp_iu); + rsp->max_ti_iu_len = sizeof(union srp_iu); + /* direct and indirect */ + rsp->buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT; + + send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT); +} + +static inline void queue_cmd(struct iu_entry *iue) +{ + struct srp_target *target = iue->target; + unsigned long flags; + + spin_lock_irqsave(&target->lock, flags); + list_add_tail(&iue->ilist, &target->cmd_queue); + spin_unlock_irqrestore(&target->lock, flags); +} + +static int process_tsk_mgmt(struct iu_entry *iue) +{ + union viosrp_iu *iu = vio_iu(iue); + int fn; + + dprintk("%p %u\n", iue, iu->srp.tsk_mgmt.tsk_mgmt_func); + + switch (iu->srp.tsk_mgmt.tsk_mgmt_func) { + case SRP_TSK_ABORT_TASK: + fn = ABORT_TASK; + break; + case SRP_TSK_ABORT_TASK_SET: + fn = ABORT_TASK_SET; + break; + case SRP_TSK_CLEAR_TASK_SET: + fn = CLEAR_TASK_SET; + break; + case SRP_TSK_LUN_RESET: + fn = LOGICAL_UNIT_RESET; + break; + case SRP_TSK_CLEAR_ACA: + fn = CLEAR_ACA; + break; + default: + fn = 0; + } + if (fn) + scsi_tgt_tsk_mgmt_request(iue->target->shost, fn, + iu->srp.tsk_mgmt.task_tag, + (struct scsi_lun *) &iu->srp.tsk_mgmt.lun, + iue); + else + send_rsp(iue, NULL, ILLEGAL_REQUEST, 0x20); + + return !fn; +} + +static int process_mad_iu(struct iu_entry *iue) +{ + union viosrp_iu *iu = vio_iu(iue); + struct viosrp_adapter_info *info; + struct viosrp_host_config *conf; + + switch (iu->mad.empty_iu.common.type) { + case VIOSRP_EMPTY_IU_TYPE: + eprintk("%s\n", "Unsupported EMPTY MAD IU"); + break; + case VIOSRP_ERROR_LOG_TYPE: + eprintk("%s\n", "Unsupported ERROR LOG MAD IU"); + iu->mad.error_log.common.status = 1; + send_iu(iue, sizeof(iu->mad.error_log), VIOSRP_MAD_FORMAT); + break; + case VIOSRP_ADAPTER_INFO_TYPE: + info = &iu->mad.adapter_info; + info->common.status = send_adapter_info(iue, info->buffer, + info->common.length); + send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT); + break; + case VIOSRP_HOST_CONFIG_TYPE: + conf = &iu->mad.host_config; + conf->common.status = 1; + send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT); + break; + default: + eprintk("Unknown type %u\n", iu->srp.rsp.opcode); + } + + return 1; +} + +static int process_srp_iu(struct iu_entry *iue) +{ + union viosrp_iu *iu = vio_iu(iue); + int done = 1; + u8 opcode = iu->srp.rsp.opcode; + + switch (opcode) { + case SRP_LOGIN_REQ: + process_login(iue); + break; + case SRP_TSK_MGMT: + done = process_tsk_mgmt(iue); + break; + case SRP_CMD: + queue_cmd(iue); + done = 0; + break; + case SRP_LOGIN_RSP: + case SRP_I_LOGOUT: + case SRP_T_LOGOUT: + case SRP_RSP: + case SRP_CRED_REQ: + case SRP_CRED_RSP: + case SRP_AER_REQ: + case SRP_AER_RSP: + eprintk("Unsupported type %u\n", opcode); + break; + default: + eprintk("Unknown type %u\n", opcode); + } + + return done; +} + +static void process_iu(struct viosrp_crq *crq, struct srp_target *target) +{ + struct vio_port *vport = target_to_port(target); + struct iu_entry *iue; + long err, done; + + iue = srp_iu_get(target); + if (!iue) { + eprintk("Error getting IU from pool, %p\n", target); + return; + } + + iue->remote_token = crq->IU_data_ptr; + + err = h_copy_rdma(crq->IU_length, vport->riobn, + iue->remote_token, vport->liobn, iue->sbuf->dma); + + if (err != H_SUCCESS) { + eprintk("%ld transferring data error %p\n", err, iue); + done = 1; + goto out; + } + + if (crq->format == VIOSRP_MAD_FORMAT) + done = process_mad_iu(iue); + else + done = process_srp_iu(iue); +out: + if (done) + srp_iu_put(iue); +} + +static irqreturn_t ibmvstgt_interrupt(int irq, void *data) +{ + struct srp_target *target = (struct srp_target *) data; + struct vio_port *vport = target_to_port(target); + + vio_disable_interrupts(vport->dma_dev); + queue_work(vtgtd, &vport->crq_work); + + return IRQ_HANDLED; +} + +static int crq_queue_create(struct crq_queue *queue, struct srp_target *target) +{ + int err; + struct vio_port *vport = target_to_port(target); + + queue->msgs = (struct viosrp_crq *) get_zeroed_page(GFP_KERNEL); + if (!queue->msgs) + goto malloc_failed; + queue->size = PAGE_SIZE / sizeof(*queue->msgs); + + queue->msg_token = dma_map_single(target->dev, queue->msgs, + queue->size * sizeof(*queue->msgs), + DMA_BIDIRECTIONAL); + + if (dma_mapping_error(queue->msg_token)) + goto map_failed; + + err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token, + PAGE_SIZE); + + /* If the adapter was left active for some reason (like kexec) + * try freeing and re-registering + */ + if (err == H_RESOURCE) { + do { + err = h_free_crq(vport->dma_dev->unit_address); + } while (err == H_BUSY || H_IS_LONG_BUSY(err)); + + err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token, + PAGE_SIZE); + } + + if (err != H_SUCCESS && err != 2) { + eprintk("Error 0x%x opening virtual adapter\n", err); + goto reg_crq_failed; + } + + err = request_irq(vport->dma_dev->irq, &ibmvstgt_interrupt, + SA_INTERRUPT, "ibmvstgt", target); + if (err) + goto req_irq_failed; + + vio_enable_interrupts(vport->dma_dev); + + h_send_crq(vport->dma_dev->unit_address, 0xC001000000000000, 0); + + queue->cur = 0; + spin_lock_init(&queue->lock); + + return 0; + +req_irq_failed: + do { + err = h_free_crq(vport->dma_dev->unit_address); + } while (err == H_BUSY || H_IS_LONG_BUSY(err)); + +reg_crq_failed: + dma_unmap_single(target->dev, queue->msg_token, + queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); +map_failed: + free_page((unsigned long) queue->msgs); + +malloc_failed: + return -ENOMEM; +} + +static void crq_queue_destroy(struct srp_target *target) +{ + struct vio_port *vport = target_to_port(target); + struct crq_queue *queue = &vport->crq_queue; + int err; + + free_irq(vport->dma_dev->irq, target); + do { + err = h_free_crq(vport->dma_dev->unit_address); + } while (err == H_BUSY || H_IS_LONG_BUSY(err)); + + dma_unmap_single(target->dev, queue->msg_token, + queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); + + free_page((unsigned long) queue->msgs); +} + +static void process_crq(struct viosrp_crq *crq, struct srp_target *target) +{ + struct vio_port *vport = target_to_port(target); + dprintk("%x %x\n", crq->valid, crq->format); + + switch (crq->valid) { + case 0xC0: + /* initialization */ + switch (crq->format) { + case 0x01: + h_send_crq(vport->dma_dev->unit_address, + 0xC002000000000000, 0); + break; + case 0x02: + break; + default: + eprintk("Unknown format %u\n", crq->format); + } + break; + case 0xFF: + /* transport event */ + break; + case 0x80: + /* real payload */ + switch (crq->format) { + case VIOSRP_SRP_FORMAT: + case VIOSRP_MAD_FORMAT: + process_iu(crq, target); + break; + case VIOSRP_OS400_FORMAT: + case VIOSRP_AIX_FORMAT: + case VIOSRP_LINUX_FORMAT: + case VIOSRP_INLINE_FORMAT: + eprintk("Unsupported format %u\n", crq->format); + break; + default: + eprintk("Unknown format %u\n", crq->format); + } + break; + default: + eprintk("unknown message type 0x%02x!?\n", crq->valid); + } +} + +static inline struct viosrp_crq *next_crq(struct crq_queue *queue) +{ + struct viosrp_crq *crq; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + crq = &queue->msgs[queue->cur]; + if (crq->valid & 0x80) { + if (++queue->cur == queue->size) + queue->cur = 0; + } else + crq = NULL; + spin_unlock_irqrestore(&queue->lock, flags); + + return crq; +} + +static void handle_crq(struct work_struct *work) +{ + struct vio_port *vport = container_of(work, struct vio_port, crq_work); + struct srp_target *target = vport->target; + struct viosrp_crq *crq; + int done = 0; + + while (!done) { + while ((crq = next_crq(&vport->crq_queue)) != NULL) { + process_crq(crq, target); + crq->valid = 0x00; + } + + vio_enable_interrupts(vport->dma_dev); + + crq = next_crq(&vport->crq_queue); + if (crq) { + vio_disable_interrupts(vport->dma_dev); + process_crq(crq, target); + crq->valid = 0x00; + } else + done = 1; + } + + handle_cmd_queue(target); +} + + +static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *sc) +{ + unsigned long flags; + struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; + struct srp_target *target = iue->target; + + dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]); + + spin_lock_irqsave(&target->lock, flags); + list_del(&iue->ilist); + spin_unlock_irqrestore(&target->lock, flags); + + srp_iu_put(iue); + + return 0; +} + +static int ibmvstgt_tsk_mgmt_response(u64 mid, int result) +{ + struct iu_entry *iue = (struct iu_entry *) ((void *) mid); + union viosrp_iu *iu = vio_iu(iue); + unsigned char status, asc; + + eprintk("%p %d\n", iue, result); + status = NO_SENSE; + asc = 0; + + switch (iu->srp.tsk_mgmt.tsk_mgmt_func) { + case SRP_TSK_ABORT_TASK: + asc = 0x14; + if (result) + status = ABORTED_COMMAND; + break; + default: + break; + } + + send_rsp(iue, NULL, status, asc); + srp_iu_put(iue); + + return 0; +} + +static ssize_t system_id_show(struct class_device *cdev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", system_id); +} + +static ssize_t partition_number_show(struct class_device *cdev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%x\n", partition_number); +} + +static ssize_t unit_address_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct srp_target *target = host_to_srp_target(shost); + struct vio_port *vport = target_to_port(target); + return snprintf(buf, PAGE_SIZE, "%x\n", vport->dma_dev->unit_address); +} + +static CLASS_DEVICE_ATTR(system_id, S_IRUGO, system_id_show, NULL); +static CLASS_DEVICE_ATTR(partition_number, S_IRUGO, partition_number_show, NULL); +static CLASS_DEVICE_ATTR(unit_address, S_IRUGO, unit_address_show, NULL); + +static struct class_device_attribute *ibmvstgt_attrs[] = { + &class_device_attr_system_id, + &class_device_attr_partition_number, + &class_device_attr_unit_address, + NULL, +}; + +static struct scsi_host_template ibmvstgt_sht = { + .name = TGT_NAME, + .module = THIS_MODULE, + .can_queue = INITIAL_SRP_LIMIT, + .sg_tablesize = SG_ALL, + .use_clustering = DISABLE_CLUSTERING, + .max_sectors = DEFAULT_MAX_SECTORS, + .transfer_response = ibmvstgt_cmd_done, + .transfer_data = ibmvstgt_transfer_data, + .eh_abort_handler = ibmvstgt_eh_abort_handler, + .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response, + .shost_attrs = ibmvstgt_attrs, + .proc_name = TGT_NAME, +}; + +static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) +{ + struct Scsi_Host *shost; + struct srp_target *target; + struct vio_port *vport; + unsigned int *dma, dma_size; + int err = -ENOMEM; + + vport = kzalloc(sizeof(struct vio_port), GFP_KERNEL); + if (!vport) + return err; + shost = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target)); + if (!shost) + goto free_vport; + err = scsi_tgt_alloc_queue(shost); + if (err) + goto put_host; + + target = host_to_srp_target(shost); + target->shost = shost; + vport->dma_dev = dev; + target->ldata = vport; + vport->target = target; + err = srp_target_alloc(target, &dev->dev, INITIAL_SRP_LIMIT, + SRP_MAX_IU_LEN); + if (err) + goto put_host; + + dma = (unsigned int *) vio_get_attribute(dev, "ibm,my-dma-window", + &dma_size); + if (!dma || dma_size != 40) { + eprintk("Couldn't get window property %d\n", dma_size); + err = -EIO; + goto free_srp_target; + } + vport->liobn = dma[0]; + vport->riobn = dma[5]; + + INIT_WORK(&vport->crq_work, handle_crq); + + err = crq_queue_create(&vport->crq_queue, target); + if (err) + goto free_srp_target; + + err = scsi_add_host(shost, target->dev); + if (err) + goto destroy_queue; + return 0; + +destroy_queue: + crq_queue_destroy(target); +free_srp_target: + srp_target_free(target); +put_host: + scsi_host_put(shost); +free_vport: + kfree(vport); + return err; +} + +static int ibmvstgt_remove(struct vio_dev *dev) +{ + struct srp_target *target = (struct srp_target *) dev->dev.driver_data; + struct Scsi_Host *shost = target->shost; + struct vio_port *vport = target->ldata; + + crq_queue_destroy(target); + scsi_remove_host(shost); + scsi_tgt_free_queue(shost); + srp_target_free(target); + kfree(vport); + scsi_host_put(shost); + return 0; +} + +static struct vio_device_id ibmvstgt_device_table[] __devinitdata = { + {"v-scsi-host", "IBM,v-scsi-host"}, + {"",""} +}; + +MODULE_DEVICE_TABLE(vio, ibmvstgt_device_table); + +static struct vio_driver ibmvstgt_driver = { + .id_table = ibmvstgt_device_table, + .probe = ibmvstgt_probe, + .remove = ibmvstgt_remove, + .driver = { + .name = "ibmvscsis", + .owner = THIS_MODULE, + } +}; + +static int get_system_info(void) +{ + struct device_node *rootdn; + const char *id, *model, *name; + unsigned int *num; + + rootdn = find_path_device("/"); + if (!rootdn) + return -ENOENT; + + model = get_property(rootdn, "model", NULL); + id = get_property(rootdn, "system-id", NULL); + if (model && id) + snprintf(system_id, sizeof(system_id), "%s-%s", model, id); + + name = get_property(rootdn, "ibm,partition-name", NULL); + if (name) + strncpy(partition_name, name, sizeof(partition_name)); + + num = (unsigned int *) get_property(rootdn, "ibm,partition-no", NULL); + if (num) + partition_number = *num; + + return 0; +} + +static int ibmvstgt_init(void) +{ + int err = -ENOMEM; + + printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n"); + + vtgtd = create_workqueue("ibmvtgtd"); + if (!vtgtd) + return err; + + err = get_system_info(); + if (err) + goto destroy_wq; + + err = vio_register_driver(&ibmvstgt_driver); + if (err) + goto destroy_wq; + + return 0; + +destroy_wq: + destroy_workqueue(vtgtd); + return err; +} + +static void ibmvstgt_exit(void) +{ + printk("Unregister IBM virtual SCSI driver\n"); + + destroy_workqueue(vtgtd); + vio_unregister_driver(&ibmvstgt_driver); +} + +MODULE_DESCRIPTION("IBM Virtual SCSI Target"); +MODULE_AUTHOR("Santiago Leon"); +MODULE_LICENSE("GPL"); + +module_init(ibmvstgt_init); +module_exit(ibmvstgt_exit); diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index e31f6122106..0464c182c57 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -36,7 +36,7 @@ typedef struct { int base_hi; /* Hi Base address for ECP-ISA chipset */ int mode; /* Transfer mode */ struct scsi_cmnd *cur_cmd; /* Current queued command */ - struct work_struct imm_tq; /* Polling interrupt stuff */ + struct delayed_work imm_tq; /* Polling interrupt stuff */ unsigned long jstart; /* Jiffies at start */ unsigned failed:1; /* Failure flag */ unsigned dp:1; /* Data phase present */ @@ -733,9 +733,9 @@ static int imm_completion(struct scsi_cmnd *cmd) * the scheduler's task queue to generate a stream of call-backs and * complete the request when the drive is ready. */ -static void imm_interrupt(void *data) +static void imm_interrupt(struct work_struct *work) { - imm_struct *dev = (imm_struct *) data; + imm_struct *dev = container_of(work, imm_struct, imm_tq.work); struct scsi_cmnd *cmd = dev->cur_cmd; struct Scsi_Host *host = cmd->device->host; unsigned long flags; @@ -745,7 +745,6 @@ static void imm_interrupt(void *data) return; } if (imm_engine(dev, cmd)) { - INIT_WORK(&dev->imm_tq, imm_interrupt, (void *) dev); schedule_delayed_work(&dev->imm_tq, 1); return; } @@ -953,8 +952,7 @@ static int imm_queuecommand(struct scsi_cmnd *cmd, cmd->result = DID_ERROR << 16; /* default return code */ cmd->SCp.phase = 0; /* bus free */ - INIT_WORK(&dev->imm_tq, imm_interrupt, dev); - schedule_work(&dev->imm_tq); + schedule_delayed_work(&dev->imm_tq, 0); imm_pb_claim(dev); @@ -1225,7 +1223,7 @@ static int __imm_attach(struct parport *pb) else ports = 8; - INIT_WORK(&dev->imm_tq, imm_interrupt, dev); + INIT_DELAYED_WORK(&dev->imm_tq, imm_interrupt); err = -ENOMEM; host = scsi_host_alloc(&imm_template, sizeof(imm_struct *)); diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index afed293dd7b..f160357e37a 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -170,7 +170,7 @@ static int setup_debug = 0; static void i91uSCBPost(BYTE * pHcb, BYTE * pScb); /* PCI Devices supported by this driver */ -static struct pci_device_id i91u_pci_devices[] __devinitdata = { +static struct pci_device_id i91u_pci_devices[] = { { PCI_VENDOR_ID_INIT, I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_INIT, I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_INIT, I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 2dde821025f..ccd4dafce8e 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -79,7 +79,6 @@ #include <scsi/scsi_tcq.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_cmnd.h> -#include <scsi/scsi_transport.h> #include "ipr.h" /* @@ -98,7 +97,7 @@ static DEFINE_SPINLOCK(ipr_driver_lock); /* This table describes the differences between DMA controller chips */ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { - { /* Gemstone, Citrine, and Obsidian */ + { /* Gemstone, Citrine, Obsidian, and Obsidian-E */ .mailbox = 0x0042C, .cache_line_size = 0x20, { @@ -135,6 +134,7 @@ static const struct ipr_chip_t ipr_chip[] = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, &ipr_chip_cfg[0] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, &ipr_chip_cfg[0] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] } }; @@ -1249,19 +1249,23 @@ static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg, /** * ipr_log_hex_data - Log additional hex IOA error data. + * @ioa_cfg: ioa config struct * @data: IOA error data * @len: data length * * Return value: * none **/ -static void ipr_log_hex_data(u32 *data, int len) +static void ipr_log_hex_data(struct ipr_ioa_cfg *ioa_cfg, u32 *data, int len) { int i; if (len == 0) return; + if (ioa_cfg->log_level <= IPR_DEFAULT_LOG_LEVEL) + len = min_t(int, len, IPR_DEFAULT_MAX_ERROR_DUMP); + for (i = 0; i < len / 4; i += 4) { ipr_err("%08X: %08X %08X %08X %08X\n", i*4, be32_to_cpu(data[i]), @@ -1290,7 +1294,7 @@ static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err("%s\n", error->failure_reason); ipr_err("Remote Adapter VPD:\n"); ipr_log_ext_vpd(&error->vpd); - ipr_log_hex_data(error->data, + ipr_log_hex_data(ioa_cfg, error->data, be32_to_cpu(hostrcb->hcam.length) - (offsetof(struct ipr_hostrcb_error, u) + offsetof(struct ipr_hostrcb_type_17_error, data))); @@ -1315,12 +1319,225 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err("%s\n", error->failure_reason); ipr_err("Remote Adapter VPD:\n"); ipr_log_vpd(&error->vpd); - ipr_log_hex_data(error->data, + ipr_log_hex_data(ioa_cfg, error->data, be32_to_cpu(hostrcb->hcam.length) - (offsetof(struct ipr_hostrcb_error, u) + offsetof(struct ipr_hostrcb_type_07_error, data))); } +static const struct { + u8 active; + char *desc; +} path_active_desc[] = { + { IPR_PATH_NO_INFO, "Path" }, + { IPR_PATH_ACTIVE, "Active path" }, + { IPR_PATH_NOT_ACTIVE, "Inactive path" } +}; + +static const struct { + u8 state; + char *desc; +} path_state_desc[] = { + { IPR_PATH_STATE_NO_INFO, "has no path state information available" }, + { IPR_PATH_HEALTHY, "is healthy" }, + { IPR_PATH_DEGRADED, "is degraded" }, + { IPR_PATH_FAILED, "is failed" } +}; + +/** + * ipr_log_fabric_path - Log a fabric path error + * @hostrcb: hostrcb struct + * @fabric: fabric descriptor + * + * Return value: + * none + **/ +static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb, + struct ipr_hostrcb_fabric_desc *fabric) +{ + int i, j; + u8 path_state = fabric->path_state; + u8 active = path_state & IPR_PATH_ACTIVE_MASK; + u8 state = path_state & IPR_PATH_STATE_MASK; + + for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) { + if (path_active_desc[i].active != active) + continue; + + for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) { + if (path_state_desc[j].state != state) + continue; + + if (fabric->cascaded_expander == 0xff && fabric->phy == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d\n", + path_active_desc[i].desc, path_state_desc[j].desc, + fabric->ioa_port); + } else if (fabric->cascaded_expander == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Phy=%d\n", + path_active_desc[i].desc, path_state_desc[j].desc, + fabric->ioa_port, fabric->phy); + } else if (fabric->phy == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d\n", + path_active_desc[i].desc, path_state_desc[j].desc, + fabric->ioa_port, fabric->cascaded_expander); + } else { + ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d, Phy=%d\n", + path_active_desc[i].desc, path_state_desc[j].desc, + fabric->ioa_port, fabric->cascaded_expander, fabric->phy); + } + return; + } + } + + ipr_err("Path state=%02X IOA Port=%d Cascade=%d Phy=%d\n", path_state, + fabric->ioa_port, fabric->cascaded_expander, fabric->phy); +} + +static const struct { + u8 type; + char *desc; +} path_type_desc[] = { + { IPR_PATH_CFG_IOA_PORT, "IOA port" }, + { IPR_PATH_CFG_EXP_PORT, "Expander port" }, + { IPR_PATH_CFG_DEVICE_PORT, "Device port" }, + { IPR_PATH_CFG_DEVICE_LUN, "Device LUN" } +}; + +static const struct { + u8 status; + char *desc; +} path_status_desc[] = { + { IPR_PATH_CFG_NO_PROB, "Functional" }, + { IPR_PATH_CFG_DEGRADED, "Degraded" }, + { IPR_PATH_CFG_FAILED, "Failed" }, + { IPR_PATH_CFG_SUSPECT, "Suspect" }, + { IPR_PATH_NOT_DETECTED, "Missing" }, + { IPR_PATH_INCORRECT_CONN, "Incorrectly connected" } +}; + +static const char *link_rate[] = { + "unknown", + "disabled", + "phy reset problem", + "spinup hold", + "port selector", + "unknown", + "unknown", + "unknown", + "1.5Gbps", + "3.0Gbps", + "unknown", + "unknown", + "unknown", + "unknown", + "unknown", + "unknown" +}; + +/** + * ipr_log_path_elem - Log a fabric path element. + * @hostrcb: hostrcb struct + * @cfg: fabric path element struct + * + * Return value: + * none + **/ +static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb, + struct ipr_hostrcb_config_element *cfg) +{ + int i, j; + u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK; + u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK; + + if (type == IPR_PATH_CFG_NOT_EXIST) + return; + + for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) { + if (path_type_desc[i].type != type) + continue; + + for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) { + if (path_status_desc[j].status != status) + continue; + + if (type == IPR_PATH_CFG_IOA_PORT) { + ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, WWN=%08X%08X\n", + path_status_desc[j].desc, path_type_desc[i].desc, + cfg->phy, link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); + } else { + if (cfg->cascaded_expander == 0xff && cfg->phy == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: Link rate=%s, WWN=%08X%08X\n", + path_status_desc[j].desc, path_type_desc[i].desc, + link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); + } else if (cfg->cascaded_expander == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, " + "WWN=%08X%08X\n", path_status_desc[j].desc, + path_type_desc[i].desc, cfg->phy, + link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); + } else if (cfg->phy == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Link rate=%s, " + "WWN=%08X%08X\n", path_status_desc[j].desc, + path_type_desc[i].desc, cfg->cascaded_expander, + link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); + } else { + ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Phy=%d, Link rate=%s " + "WWN=%08X%08X\n", path_status_desc[j].desc, + path_type_desc[i].desc, cfg->cascaded_expander, cfg->phy, + link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); + } + } + return; + } + } + + ipr_hcam_err(hostrcb, "Path element=%02X: Cascade=%d Phy=%d Link rate=%s " + "WWN=%08X%08X\n", cfg->type_status, cfg->cascaded_expander, cfg->phy, + link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); +} + +/** + * ipr_log_fabric_error - Log a fabric error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + struct ipr_hostrcb_type_20_error *error; + struct ipr_hostrcb_fabric_desc *fabric; + struct ipr_hostrcb_config_element *cfg; + int i, add_len; + + error = &hostrcb->hcam.u.error.u.type_20_error; + error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; + ipr_hcam_err(hostrcb, "%s\n", error->failure_reason); + + add_len = be32_to_cpu(hostrcb->hcam.length) - + (offsetof(struct ipr_hostrcb_error, u) + + offsetof(struct ipr_hostrcb_type_20_error, desc)); + + for (i = 0, fabric = error->desc; i < error->num_entries; i++) { + ipr_log_fabric_path(hostrcb, fabric); + for_each_fabric_cfg(fabric, cfg) + ipr_log_path_elem(hostrcb, cfg); + + add_len -= be16_to_cpu(fabric->length); + fabric = (struct ipr_hostrcb_fabric_desc *) + ((unsigned long)fabric + be16_to_cpu(fabric->length)); + } + + ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len); +} + /** * ipr_log_generic_error - Log an adapter error. * @ioa_cfg: ioa config struct @@ -1332,7 +1549,7 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg, struct ipr_hostrcb *hostrcb) { - ipr_log_hex_data(hostrcb->hcam.u.raw.data, + ipr_log_hex_data(ioa_cfg, hostrcb->hcam.u.raw.data, be32_to_cpu(hostrcb->hcam.length)); } @@ -1394,13 +1611,7 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, if (!ipr_error_table[error_index].log_hcam) return; - if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) { - ipr_ra_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr, - "%s\n", ipr_error_table[error_index].error); - } else { - dev_err(&ioa_cfg->pdev->dev, "%s\n", - ipr_error_table[error_index].error); - } + ipr_hcam_err(hostrcb, "%s\n", ipr_error_table[error_index].error); /* Set indication we have logged an error */ ioa_cfg->errors_logged++; @@ -1437,6 +1648,9 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, case IPR_HOST_RCB_OVERLAY_ID_17: ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb); break; + case IPR_HOST_RCB_OVERLAY_ID_20: + ipr_log_fabric_error(ioa_cfg, hostrcb); + break; case IPR_HOST_RCB_OVERLAY_ID_1: case IPR_HOST_RCB_OVERLAY_ID_DEFAULT: default: @@ -2093,7 +2307,7 @@ static void ipr_release_dump(struct kref *kref) /** * ipr_worker_thread - Worker thread - * @data: ioa config struct + * @work: ioa config struct * * Called at task level from a work thread. This function takes care * of adding and removing device from the mid-layer as configuration @@ -2102,13 +2316,14 @@ static void ipr_release_dump(struct kref *kref) * Return value: * nothing **/ -static void ipr_worker_thread(void *data) +static void ipr_worker_thread(struct work_struct *work) { unsigned long lock_flags; struct ipr_resource_entry *res; struct scsi_device *sdev; struct ipr_dump *dump; - struct ipr_ioa_cfg *ioa_cfg = data; + struct ipr_ioa_cfg *ioa_cfg = + container_of(work, struct ipr_ioa_cfg, work_q); u8 bus, target, lun; int did_work; @@ -2969,7 +3184,6 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) struct ipr_dump *dump; unsigned long lock_flags = 0; - ENTER; dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL); if (!dump) { @@ -2996,7 +3210,6 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - LEAVE; return 0; } @@ -3573,6 +3786,12 @@ static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes) ENTER; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + } + res = sata_port->res; if (res) { rc = ipr_device_reset(ioa_cfg, res); @@ -3636,6 +3855,10 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) { if (ipr_cmd->scsi_cmd) ipr_cmd->done = ipr_scsi_eh_done; + if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) { + ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; + ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED; + } } } @@ -3770,7 +3993,7 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) */ if (ioa_cfg->in_reset_reload || ioa_cfg->ioa_is_dead) return FAILED; - if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res))) + if (!res || !ipr_is_gscsi(res)) return FAILED; list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { @@ -4615,7 +4838,7 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd, * Return value: * 0 on success / other on failure **/ -int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) +static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) { struct ipr_resource_entry *res; @@ -4648,40 +4871,6 @@ static const char * ipr_ioa_info(struct Scsi_Host *host) return buffer; } -/** - * ipr_scsi_timed_out - Handle scsi command timeout - * @scsi_cmd: scsi command struct - * - * Return value: - * EH_NOT_HANDLED - **/ -enum scsi_eh_timer_return ipr_scsi_timed_out(struct scsi_cmnd *scsi_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg; - struct ipr_cmnd *ipr_cmd; - unsigned long flags; - - ENTER; - spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags); - ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata; - - list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { - if (ipr_cmd->qc && ipr_cmd->qc->scsicmd == scsi_cmd) { - ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; - ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED; - break; - } - } - - spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags); - LEAVE; - return EH_NOT_HANDLED; -} - -static struct scsi_transport_template ipr_transport_template = { - .eh_timed_out = ipr_scsi_timed_out -}; - static struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = "IPR", @@ -4776,6 +4965,12 @@ static void ipr_ata_post_internal(struct ata_queued_cmd *qc) unsigned long flags; spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + } + list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { if (ipr_cmd->qc == qc) { ipr_device_reset(ioa_cfg, sata_port->res); @@ -6832,6 +7027,7 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) ioa_cfg->hostrcb[i]->hostrcb_dma = ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam); + ioa_cfg->hostrcb[i]->ioa_cfg = ioa_cfg; list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); } @@ -6926,7 +7122,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q); INIT_LIST_HEAD(&ioa_cfg->free_res_q); INIT_LIST_HEAD(&ioa_cfg->used_res_q); - INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread, ioa_cfg); + INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); init_waitqueue_head(&ioa_cfg->reset_wait_q); ioa_cfg->sdt_state = INACTIVE; if (ipr_enable_cache) @@ -7017,7 +7213,6 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg)); - host->transportt = &ipr_transport_template; ata_host_init(&ioa_cfg->ata_host, &pdev->dev, sata_port_info.flags, &ipr_sata_ops); @@ -7351,12 +7546,24 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = { { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, @@ -7366,6 +7573,9 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = { { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, { } }; MODULE_DEVICE_TABLE(pci, ipr_pci_table); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 6d035283af0..9f62a1d4d51 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -37,8 +37,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.2.0" -#define IPR_DRIVER_DATE "(September 25, 2006)" +#define IPR_DRIVER_VERSION "2.3.0" +#define IPR_DRIVER_DATE "(November 8, 2006)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding @@ -54,6 +54,8 @@ */ #define IPR_NUM_BASE_CMD_BLKS 100 +#define PCI_DEVICE_ID_IBM_OBSIDIAN_E 0x0339 + #define IPR_SUBS_DEV_ID_2780 0x0264 #define IPR_SUBS_DEV_ID_5702 0x0266 #define IPR_SUBS_DEV_ID_5703 0x0278 @@ -66,7 +68,11 @@ #define IPR_SUBS_DEV_ID_571F 0x02D5 #define IPR_SUBS_DEV_ID_572A 0x02C1 #define IPR_SUBS_DEV_ID_572B 0x02C2 +#define IPR_SUBS_DEV_ID_572F 0x02C3 #define IPR_SUBS_DEV_ID_575B 0x030D +#define IPR_SUBS_DEV_ID_575C 0x0338 +#define IPR_SUBS_DEV_ID_57B7 0x0360 +#define IPR_SUBS_DEV_ID_57B8 0x02C2 #define IPR_NAME "ipr" @@ -98,6 +104,7 @@ #define IPR_IOASC_IOA_WAS_RESET 0x10000001 #define IPR_IOASC_PCI_ACCESS_ERROR 0x10000002 +#define IPR_DEFAULT_MAX_ERROR_DUMP 984 #define IPR_NUM_LOG_HCAMS 2 #define IPR_NUM_CFG_CHG_HCAMS 2 #define IPR_NUM_HCAMS (IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS) @@ -731,6 +738,64 @@ struct ipr_hostrcb_type_17_error { u32 data[476]; }__attribute__((packed, aligned (4))); +struct ipr_hostrcb_config_element { + u8 type_status; +#define IPR_PATH_CFG_TYPE_MASK 0xF0 +#define IPR_PATH_CFG_NOT_EXIST 0x00 +#define IPR_PATH_CFG_IOA_PORT 0x10 +#define IPR_PATH_CFG_EXP_PORT 0x20 +#define IPR_PATH_CFG_DEVICE_PORT 0x30 +#define IPR_PATH_CFG_DEVICE_LUN 0x40 + +#define IPR_PATH_CFG_STATUS_MASK 0x0F +#define IPR_PATH_CFG_NO_PROB 0x00 +#define IPR_PATH_CFG_DEGRADED 0x01 +#define IPR_PATH_CFG_FAILED 0x02 +#define IPR_PATH_CFG_SUSPECT 0x03 +#define IPR_PATH_NOT_DETECTED 0x04 +#define IPR_PATH_INCORRECT_CONN 0x05 + + u8 cascaded_expander; + u8 phy; + u8 link_rate; +#define IPR_PHY_LINK_RATE_MASK 0x0F + + __be32 wwid[2]; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb_fabric_desc { + __be16 length; + u8 ioa_port; + u8 cascaded_expander; + u8 phy; + u8 path_state; +#define IPR_PATH_ACTIVE_MASK 0xC0 +#define IPR_PATH_NO_INFO 0x00 +#define IPR_PATH_ACTIVE 0x40 +#define IPR_PATH_NOT_ACTIVE 0x80 + +#define IPR_PATH_STATE_MASK 0x0F +#define IPR_PATH_STATE_NO_INFO 0x00 +#define IPR_PATH_HEALTHY 0x01 +#define IPR_PATH_DEGRADED 0x02 +#define IPR_PATH_FAILED 0x03 + + __be16 num_entries; + struct ipr_hostrcb_config_element elem[1]; +}__attribute__((packed, aligned (4))); + +#define for_each_fabric_cfg(fabric, cfg) \ + for (cfg = (fabric)->elem; \ + cfg < ((fabric)->elem + be16_to_cpu((fabric)->num_entries)); \ + cfg++) + +struct ipr_hostrcb_type_20_error { + u8 failure_reason[64]; + u8 reserved[3]; + u8 num_entries; + struct ipr_hostrcb_fabric_desc desc[1]; +}__attribute__((packed, aligned (4))); + struct ipr_hostrcb_error { __be32 failing_dev_ioasc; struct ipr_res_addr failing_dev_res_addr; @@ -747,6 +812,7 @@ struct ipr_hostrcb_error { struct ipr_hostrcb_type_13_error type_13_error; struct ipr_hostrcb_type_14_error type_14_error; struct ipr_hostrcb_type_17_error type_17_error; + struct ipr_hostrcb_type_20_error type_20_error; } u; }__attribute__((packed, aligned (4))); @@ -786,6 +852,7 @@ struct ipr_hcam { #define IPR_HOST_RCB_OVERLAY_ID_14 0x14 #define IPR_HOST_RCB_OVERLAY_ID_16 0x16 #define IPR_HOST_RCB_OVERLAY_ID_17 0x17 +#define IPR_HOST_RCB_OVERLAY_ID_20 0x20 #define IPR_HOST_RCB_OVERLAY_ID_DEFAULT 0xFF u8 reserved1[3]; @@ -805,6 +872,7 @@ struct ipr_hostrcb { struct ipr_hcam hcam; dma_addr_t hostrcb_dma; struct list_head queue; + struct ipr_ioa_cfg *ioa_cfg; }; /* IPR smart dump table structures */ @@ -1283,6 +1351,17 @@ struct ipr_ucode_image_header { } \ } +#define ipr_hcam_err(hostrcb, fmt, ...) \ +{ \ + if (ipr_is_device(&(hostrcb)->hcam.u.error.failing_dev_res_addr)) { \ + ipr_ra_err((hostrcb)->ioa_cfg, \ + (hostrcb)->hcam.u.error.failing_dev_res_addr, \ + fmt, ##__VA_ARGS__); \ + } else { \ + dev_err(&(hostrcb)->ioa_cfg->pdev->dev, fmt, ##__VA_ARGS__); \ + } \ +} + #define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\ __FILE__, __FUNCTION__, __LINE__) diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index f06a06ae609..8b704f73055 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -5001,7 +5001,7 @@ ips_init_copperhead(ips_ha_t * ha) break; /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); } if (j >= 45) @@ -5027,7 +5027,7 @@ ips_init_copperhead(ips_ha_t * ha) break; /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); } if (j >= 240) @@ -5045,7 +5045,7 @@ ips_init_copperhead(ips_ha_t * ha) break; /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); } if (i >= 240) @@ -5095,7 +5095,7 @@ ips_init_copperhead_memio(ips_ha_t * ha) break; /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); } if (j >= 45) @@ -5121,7 +5121,7 @@ ips_init_copperhead_memio(ips_ha_t * ha) break; /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); } if (j >= 240) @@ -5139,7 +5139,7 @@ ips_init_copperhead_memio(ips_ha_t * ha) break; /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); } if (i >= 240) @@ -5191,7 +5191,7 @@ ips_init_morpheus(ips_ha_t * ha) break; /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); } if (i >= 45) { @@ -5217,7 +5217,7 @@ ips_init_morpheus(ips_ha_t * ha) if (Post != 0x4F00) break; /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); } if (i >= 120) { @@ -5247,7 +5247,7 @@ ips_init_morpheus(ips_ha_t * ha) break; /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); } if (i >= 240) { @@ -5307,12 +5307,12 @@ ips_reset_copperhead(ips_ha_t * ha) outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR); /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); outb(0, ha->io_addr + IPS_REG_SCPR); /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); if ((*ha->func.init) (ha)) break; @@ -5352,12 +5352,12 @@ ips_reset_copperhead_memio(ips_ha_t * ha) writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR); /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); writeb(0, ha->mem_ptr + IPS_REG_SCPR); /* Delay for 1 Second */ - msleep(IPS_ONE_SEC); + MDELAY(IPS_ONE_SEC); if ((*ha->func.init) (ha)) break; @@ -5398,7 +5398,7 @@ ips_reset_morpheus(ips_ha_t * ha) writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR); /* Delay for 5 Seconds */ - msleep(5 * IPS_ONE_SEC); + MDELAY(5 * IPS_ONE_SEC); /* Do a PCI config read to wait for adapter */ pci_read_config_byte(ha->pcidev, 4, &junk); diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index 34680f3dd45..b726dcc424b 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -51,6 +51,7 @@ #define _IPS_H_ #include <linux/version.h> +#include <linux/nmi.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -116,9 +117,11 @@ dev_printk(level , &((pcidev)->dev) , format , ## arg) #endif - #ifndef MDELAY - #define MDELAY mdelay - #endif + #define MDELAY(n) \ + do { \ + mdelay(n); \ + touch_nmi_watchdog(); \ + } while (0) #ifndef min #define min(x,y) ((x) < (y) ? x : y) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 5d886218948..e11b23c641e 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -719,9 +719,10 @@ again: return rc; } -static void iscsi_xmitworker(void *data) +static void iscsi_xmitworker(struct work_struct *work) { - struct iscsi_conn *conn = data; + struct iscsi_conn *conn = + container_of(work, struct iscsi_conn, xmitwork); int rc; /* * serialize Xmit worker on a per-connection basis. @@ -1512,7 +1513,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) if (conn->mgmtqueue == ERR_PTR(-ENOMEM)) goto mgmtqueue_alloc_fail; - INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn); + INIT_WORK(&conn->xmitwork, iscsi_xmitworker); /* allocate login_mtask used for the login/text sequences */ spin_lock_bh(&session->lock); diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index d977bd492d8..fb7df7b7581 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -647,10 +647,12 @@ void sas_unregister_domain_devices(struct asd_sas_port *port) * Discover process only interrogates devices in order to discover the * domain. */ -static void sas_discover_domain(void *data) +static void sas_discover_domain(struct work_struct *work) { int error = 0; - struct asd_sas_port *port = data; + struct sas_discovery_event *ev = + container_of(work, struct sas_discovery_event, work); + struct asd_sas_port *port = ev->port; sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock, &port->disc.pending); @@ -692,10 +694,12 @@ static void sas_discover_domain(void *data) current->pid, error); } -static void sas_revalidate_domain(void *data) +static void sas_revalidate_domain(struct work_struct *work) { int res = 0; - struct asd_sas_port *port = data; + struct sas_discovery_event *ev = + container_of(work, struct sas_discovery_event, work); + struct asd_sas_port *port = ev->port; sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock, &port->disc.pending); @@ -722,7 +726,7 @@ int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) BUG_ON(ev >= DISC_NUM_EVENTS); sas_queue_event(ev, &disc->disc_event_lock, &disc->pending, - &disc->disc_work[ev], port->ha->core.shost); + &disc->disc_work[ev].work, port->ha->core.shost); return 0; } @@ -737,13 +741,15 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port) { int i; - static void (*sas_event_fns[DISC_NUM_EVENTS])(void *) = { + static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, }; spin_lock_init(&disc->disc_event_lock); disc->pending = 0; - for (i = 0; i < DISC_NUM_EVENTS; i++) - INIT_WORK(&disc->disc_work[i], sas_event_fns[i], port); + for (i = 0; i < DISC_NUM_EVENTS; i++) { + INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]); + disc->disc_work[i].port = port; + } } diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index 19110ed1c89..d83392ee682 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -31,7 +31,7 @@ static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event) BUG_ON(event >= HA_NUM_EVENTS); sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending, - &sas_ha->ha_events[event], sas_ha->core.shost); + &sas_ha->ha_events[event].work, sas_ha->core.shost); } static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) @@ -41,7 +41,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) BUG_ON(event >= PORT_NUM_EVENTS); sas_queue_event(event, &ha->event_lock, &phy->port_events_pending, - &phy->port_events[event], ha->core.shost); + &phy->port_events[event].work, ha->core.shost); } static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) @@ -51,12 +51,12 @@ static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) BUG_ON(event >= PHY_NUM_EVENTS); sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending, - &phy->phy_events[event], ha->core.shost); + &phy->phy_events[event].work, ha->core.shost); } int sas_init_events(struct sas_ha_struct *sas_ha) { - static void (*sas_ha_event_fns[HA_NUM_EVENTS])(void *) = { + static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = { [HAE_RESET] = sas_hae_reset, }; @@ -64,8 +64,10 @@ int sas_init_events(struct sas_ha_struct *sas_ha) spin_lock_init(&sas_ha->event_lock); - for (i = 0; i < HA_NUM_EVENTS; i++) - INIT_WORK(&sas_ha->ha_events[i], sas_ha_event_fns[i], sas_ha); + for (i = 0; i < HA_NUM_EVENTS; i++) { + INIT_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]); + sas_ha->ha_events[i].ha = sas_ha; + } sas_ha->notify_ha_event = notify_ha_event; sas_ha->notify_port_event = notify_port_event; diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index e34a9343549..d31e6fa466f 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -597,10 +597,15 @@ static struct domain_device *sas_ex_discover_end_dev( child->iproto = phy->attached_iproto; memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); sas_hash_addr(child->hashed_sas_addr, child->sas_addr); - phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); - BUG_ON(!phy->port); - /* FIXME: better error handling*/ - BUG_ON(sas_port_add(phy->port) != 0); + if (!phy->port) { + phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); + if (unlikely(!phy->port)) + goto out_err; + if (unlikely(sas_port_add(phy->port) != 0)) { + sas_port_free(phy->port); + goto out_err; + } + } sas_ex_get_linkrate(parent, child, phy); if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) { @@ -615,8 +620,7 @@ static struct domain_device *sas_ex_discover_end_dev( SAS_DPRINTK("report phy sata to %016llx:0x%x returned " "0x%x\n", SAS_ADDR(parent->sas_addr), phy_id, res); - kfree(child); - return NULL; + goto out_free; } memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis, sizeof(struct dev_to_host_fis)); @@ -627,14 +631,14 @@ static struct domain_device *sas_ex_discover_end_dev( "%016llx:0x%x returned 0x%x\n", SAS_ADDR(child->sas_addr), SAS_ADDR(parent->sas_addr), phy_id, res); - kfree(child); - return NULL; + goto out_free; } } else if (phy->attached_tproto & SAS_PROTO_SSP) { child->dev_type = SAS_END_DEV; rphy = sas_end_device_alloc(phy->port); /* FIXME: error handling */ - BUG_ON(!rphy); + if (unlikely(!rphy)) + goto out_free; child->tproto = phy->attached_tproto; sas_init_dev(child); @@ -651,9 +655,7 @@ static struct domain_device *sas_ex_discover_end_dev( "at %016llx:0x%x returned 0x%x\n", SAS_ADDR(child->sas_addr), SAS_ADDR(parent->sas_addr), phy_id, res); - /* FIXME: this kfrees list elements without removing them */ - //kfree(child); - return NULL; + goto out_list_del; } } else { SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n", @@ -663,6 +665,16 @@ static struct domain_device *sas_ex_discover_end_dev( list_add_tail(&child->siblings, &parent_ex->children); return child; + + out_list_del: + list_del(&child->dev_list_node); + sas_rphy_free(rphy); + out_free: + sas_port_delete(phy->port); + out_err: + phy->port = NULL; + kfree(child); + return NULL; } static struct domain_device *sas_ex_discover_expander( diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index c836a237fb7..d65bc4e0f21 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -65,9 +65,11 @@ void sas_hash_addr(u8 *hashed, const u8 *sas_addr) /* ---------- HA events ---------- */ -void sas_hae_reset(void *data) +void sas_hae_reset(struct work_struct *work) { - struct sas_ha_struct *ha = data; + struct sas_ha_event *ev = + container_of(work, struct sas_ha_event, work); + struct sas_ha_struct *ha = ev->ha; sas_begin_event(HAE_RESET, &ha->event_lock, &ha->pending); @@ -112,6 +114,8 @@ int sas_register_ha(struct sas_ha_struct *sas_ha) } } + INIT_LIST_HEAD(&sas_ha->eh_done_q); + return 0; Undo_ports: @@ -142,7 +146,7 @@ static int sas_get_linkerrors(struct sas_phy *phy) return sas_smp_get_phy_events(phy); } -static int sas_phy_reset(struct sas_phy *phy, int hard_reset) +int sas_phy_reset(struct sas_phy *phy, int hard_reset) { int ret; enum phy_func reset_type; diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index bffcee47492..137d7e496b6 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -60,11 +60,11 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha); void sas_deform_port(struct asd_sas_phy *phy); -void sas_porte_bytes_dmaed(void *); -void sas_porte_broadcast_rcvd(void *); -void sas_porte_link_reset_err(void *); -void sas_porte_timer_event(void *); -void sas_porte_hard_reset(void *); +void sas_porte_bytes_dmaed(struct work_struct *work); +void sas_porte_broadcast_rcvd(struct work_struct *work); +void sas_porte_link_reset_err(struct work_struct *work); +void sas_porte_timer_event(struct work_struct *work); +void sas_porte_hard_reset(struct work_struct *work); int sas_notify_lldd_dev_found(struct domain_device *); void sas_notify_lldd_dev_gone(struct domain_device *); @@ -75,7 +75,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy); struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); -void sas_hae_reset(void *); +void sas_hae_reset(struct work_struct *work); static inline void sas_queue_event(int event, spinlock_t *lock, unsigned long *pending, diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c index 9340cdbae4a..b459c4b635b 100644 --- a/drivers/scsi/libsas/sas_phy.c +++ b/drivers/scsi/libsas/sas_phy.c @@ -30,9 +30,11 @@ /* ---------- Phy events ---------- */ -static void sas_phye_loss_of_signal(void *data) +static void sas_phye_loss_of_signal(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock, &phy->phy_events_pending); @@ -40,18 +42,22 @@ static void sas_phye_loss_of_signal(void *data) sas_deform_port(phy); } -static void sas_phye_oob_done(void *data) +static void sas_phye_oob_done(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock, &phy->phy_events_pending); phy->error = 0; } -static void sas_phye_oob_error(void *data) +static void sas_phye_oob_error(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; struct sas_ha_struct *sas_ha = phy->ha; struct asd_sas_port *port = phy->port; struct sas_internal *i = @@ -80,9 +86,11 @@ static void sas_phye_oob_error(void *data) } } -static void sas_phye_spinup_hold(void *data) +static void sas_phye_spinup_hold(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; struct sas_ha_struct *sas_ha = phy->ha; struct sas_internal *i = to_sas_internal(sas_ha->core.shost->transportt); @@ -100,14 +108,14 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) { int i; - static void (*sas_phy_event_fns[PHY_NUM_EVENTS])(void *) = { + static const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = { [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal, [PHYE_OOB_DONE] = sas_phye_oob_done, [PHYE_OOB_ERROR] = sas_phye_oob_error, [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold, }; - static void (*sas_port_event_fns[PORT_NUM_EVENTS])(void *) = { + static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = { [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed, [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd, [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err, @@ -122,13 +130,18 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) phy->error = 0; INIT_LIST_HEAD(&phy->port_phy_el); - for (k = 0; k < PORT_NUM_EVENTS; k++) - INIT_WORK(&phy->port_events[k], sas_port_event_fns[k], - phy); + for (k = 0; k < PORT_NUM_EVENTS; k++) { + INIT_WORK(&phy->port_events[k].work, + sas_port_event_fns[k]); + phy->port_events[k].phy = phy; + } + + for (k = 0; k < PHY_NUM_EVENTS; k++) { + INIT_WORK(&phy->phy_events[k].work, + sas_phy_event_fns[k]); + phy->phy_events[k].phy = phy; + } - for (k = 0; k < PHY_NUM_EVENTS; k++) - INIT_WORK(&phy->phy_events[k], sas_phy_event_fns[k], - phy); phy->port = NULL; phy->ha = sas_ha; spin_lock_init(&phy->frame_rcvd_lock); diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 253cdcf306a..971c37ceecb 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -181,9 +181,11 @@ void sas_deform_port(struct asd_sas_phy *phy) /* ---------- SAS port events ---------- */ -void sas_porte_bytes_dmaed(void *data) +void sas_porte_bytes_dmaed(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock, &phy->port_events_pending); @@ -191,11 +193,13 @@ void sas_porte_bytes_dmaed(void *data) sas_form_port(phy); } -void sas_porte_broadcast_rcvd(void *data) +void sas_porte_broadcast_rcvd(struct work_struct *work) { + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; unsigned long flags; u32 prim; - struct asd_sas_phy *phy = data; sas_begin_event(PORTE_BROADCAST_RCVD, &phy->ha->event_lock, &phy->port_events_pending); @@ -208,9 +212,11 @@ void sas_porte_broadcast_rcvd(void *data) sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN); } -void sas_porte_link_reset_err(void *data) +void sas_porte_link_reset_err(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock, &phy->port_events_pending); @@ -218,9 +224,11 @@ void sas_porte_link_reset_err(void *data) sas_deform_port(phy); } -void sas_porte_timer_event(void *data) +void sas_porte_timer_event(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock, &phy->port_events_pending); @@ -228,9 +236,11 @@ void sas_porte_timer_event(void *data) sas_deform_port(phy); } -void sas_porte_hard_reset(void *data) +void sas_porte_hard_reset(struct work_struct *work) { - struct asd_sas_phy *phy = data; + struct asd_sas_event *ev = + container_of(work, struct asd_sas_event, work); + struct asd_sas_phy *phy = ev->phy; sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock, &phy->port_events_pending); diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index e46e79355b7..22672d54aa2 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -29,9 +29,11 @@ #include <scsi/scsi_device.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi.h> +#include <scsi/scsi_eh.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_sas.h> #include "../scsi_sas_internal.h" +#include "../scsi_transport_api.h" #include <linux/err.h> #include <linux/blkdev.h> @@ -46,6 +48,7 @@ static void sas_scsi_task_done(struct sas_task *task) { struct task_status_struct *ts = &task->task_status; struct scsi_cmnd *sc = task->uldd_task; + struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(sc->device->host); unsigned ts_flags = task->task_state_flags; int hs = 0, stat = 0; @@ -116,7 +119,7 @@ static void sas_scsi_task_done(struct sas_task *task) sas_free_task(task); /* This is very ugly but this is how SCSI Core works. */ if (ts_flags & SAS_TASK_STATE_ABORTED) - scsi_finish_command(sc); + scsi_eh_finish_cmd(sc, &sas_ha->eh_done_q); else sc->scsi_done(sc); } @@ -307,6 +310,15 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) spin_unlock_irqrestore(&core->task_queue_lock, flags); } + spin_lock_irqsave(&task->task_state_lock, flags); + if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { + spin_unlock_irqrestore(&task->task_state_lock, flags); + SAS_DPRINTK("%s: task 0x%p already aborted\n", + __FUNCTION__, task); + return TASK_IS_ABORTED; + } + spin_unlock_irqrestore(&task->task_state_lock, flags); + for (i = 0; i < 5; i++) { SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); res = si->dft->lldd_abort_task(task); @@ -409,13 +421,16 @@ Again: SAS_DPRINTK("going over list...\n"); list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { struct sas_task *task = TO_SAS_TASK(cmd); + list_del_init(&cmd->eh_entry); + if (!task) { + SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__); + continue; + } SAS_DPRINTK("trying to find task 0x%p\n", task); - list_del_init(&cmd->eh_entry); res = sas_scsi_find_task(task); cmd->eh_eflags = 0; - shost->host_failed--; switch (res) { case TASK_IS_DONE: @@ -491,6 +506,7 @@ Again: } } out: + scsi_eh_flush_done_q(&ha->eh_done_q); SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); return; clear_q: @@ -508,12 +524,18 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) unsigned long flags; if (!task) { - SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", + SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n", cmd, task); return EH_HANDLED; } spin_lock_irqsave(&task->task_state_lock, flags); + if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { + spin_unlock_irqrestore(&task->task_state_lock, flags); + SAS_DPRINTK("command 0x%p, task 0x%p, aborted by initiator: " + "EH_NOT_HANDLED\n", cmd, task); + return EH_NOT_HANDLED; + } if (task->task_state_flags & SAS_TASK_STATE_DONE) { spin_unlock_irqrestore(&task->task_state_lock, flags); SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", @@ -777,6 +799,66 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha) spin_unlock_irqrestore(&core->task_queue_lock, flags); } +static int do_sas_task_abort(struct sas_task *task) +{ + struct scsi_cmnd *sc = task->uldd_task; + struct sas_internal *si = + to_sas_internal(task->dev->port->ha->core.shost->transportt); + unsigned long flags; + int res; + + spin_lock_irqsave(&task->task_state_lock, flags); + if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { + spin_unlock_irqrestore(&task->task_state_lock, flags); + SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__, + task); + return 0; + } + + task->task_state_flags |= SAS_TASK_INITIATOR_ABORTED; + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) + task->task_state_flags |= SAS_TASK_STATE_ABORTED; + spin_unlock_irqrestore(&task->task_state_lock, flags); + + if (!si->dft->lldd_abort_task) + return -ENODEV; + + res = si->dft->lldd_abort_task(task); + if ((task->task_state_flags & SAS_TASK_STATE_DONE) || + (res == TMF_RESP_FUNC_COMPLETE)) + { + /* SMP commands don't have scsi_cmds(?) */ + if (!sc) { + task->task_done(task); + return 0; + } + scsi_req_abort_cmd(sc); + scsi_schedule_eh(sc->device->host); + return 0; + } + + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags &= ~SAS_TASK_INITIATOR_ABORTED; + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) + task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; + spin_unlock_irqrestore(&task->task_state_lock, flags); + + return -EAGAIN; +} + +void sas_task_abort(struct work_struct *work) +{ + struct sas_task *task = + container_of(work, struct sas_task, abort_work); + int i; + + for (i = 0; i < 5; i++) + if (!do_sas_task_abort(task)) + return; + + SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__); +} + EXPORT_SYMBOL_GPL(sas_queuecommand); EXPORT_SYMBOL_GPL(sas_target_alloc); EXPORT_SYMBOL_GPL(sas_slave_configure); @@ -784,3 +866,5 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy); EXPORT_SYMBOL_GPL(sas_change_queue_depth); EXPORT_SYMBOL_GPL(sas_change_queue_type); EXPORT_SYMBOL_GPL(sas_bios_param); +EXPORT_SYMBOL_GPL(sas_task_abort); +EXPORT_SYMBOL_GPL(sas_phy_reset); diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c new file mode 100644 index 00000000000..89403b00e04 --- /dev/null +++ b/drivers/scsi/libsrp.c @@ -0,0 +1,441 @@ +/* + * SCSI RDAM Protocol lib functions + * + * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#include <linux/err.h> +#include <linux/kfifo.h> +#include <linux/scatterlist.h> +#include <linux/dma-mapping.h> +#include <linux/pci.h> +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_tcq.h> +#include <scsi/scsi_tgt.h> +#include <scsi/srp.h> +#include <scsi/libsrp.h> + +enum srp_task_attributes { + SRP_SIMPLE_TASK = 0, + SRP_HEAD_TASK = 1, + SRP_ORDERED_TASK = 2, + SRP_ACA_TASK = 4 +}; + +/* tmp - will replace with SCSI logging stuff */ +#define eprintk(fmt, args...) \ +do { \ + printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \ +} while (0) +/* #define dprintk eprintk */ +#define dprintk(fmt, args...) + +static int srp_iu_pool_alloc(struct srp_queue *q, size_t max, + struct srp_buf **ring) +{ + int i; + struct iu_entry *iue; + + q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL); + if (!q->pool) + return -ENOMEM; + q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL); + if (!q->items) + goto free_pool; + + spin_lock_init(&q->lock); + q->queue = kfifo_init((void *) q->pool, max * sizeof(void *), + GFP_KERNEL, &q->lock); + if (IS_ERR(q->queue)) + goto free_item; + + for (i = 0, iue = q->items; i < max; i++) { + __kfifo_put(q->queue, (void *) &iue, sizeof(void *)); + iue->sbuf = ring[i]; + iue++; + } + return 0; + +free_item: + kfree(q->items); +free_pool: + kfree(q->pool); + return -ENOMEM; +} + +static void srp_iu_pool_free(struct srp_queue *q) +{ + kfree(q->items); + kfree(q->pool); +} + +static struct srp_buf **srp_ring_alloc(struct device *dev, + size_t max, size_t size) +{ + int i; + struct srp_buf **ring; + + ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL); + if (!ring) + return NULL; + + for (i = 0; i < max; i++) { + ring[i] = kzalloc(sizeof(struct srp_buf), GFP_KERNEL); + if (!ring[i]) + goto out; + ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma, + GFP_KERNEL); + if (!ring[i]->buf) + goto out; + } + return ring; + +out: + for (i = 0; i < max && ring[i]; i++) { + if (ring[i]->buf) + dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma); + kfree(ring[i]); + } + kfree(ring); + + return NULL; +} + +static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t max, + size_t size) +{ + int i; + + for (i = 0; i < max; i++) { + dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma); + kfree(ring[i]); + } +} + +int srp_target_alloc(struct srp_target *target, struct device *dev, + size_t nr, size_t iu_size) +{ + int err; + + spin_lock_init(&target->lock); + INIT_LIST_HEAD(&target->cmd_queue); + + target->dev = dev; + target->dev->driver_data = target; + + target->srp_iu_size = iu_size; + target->rx_ring_size = nr; + target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size); + if (!target->rx_ring) + return -ENOMEM; + err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring); + if (err) + goto free_ring; + + return 0; + +free_ring: + srp_ring_free(target->dev, target->rx_ring, nr, iu_size); + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(srp_target_alloc); + +void srp_target_free(struct srp_target *target) +{ + srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size, + target->srp_iu_size); + srp_iu_pool_free(&target->iu_queue); +} +EXPORT_SYMBOL_GPL(srp_target_free); + +struct iu_entry *srp_iu_get(struct srp_target *target) +{ + struct iu_entry *iue = NULL; + + kfifo_get(target->iu_queue.queue, (void *) &iue, sizeof(void *)); + if (!iue) + return iue; + iue->target = target; + INIT_LIST_HEAD(&iue->ilist); + iue->flags = 0; + return iue; +} +EXPORT_SYMBOL_GPL(srp_iu_get); + +void srp_iu_put(struct iu_entry *iue) +{ + kfifo_put(iue->target->iu_queue.queue, (void *) &iue, sizeof(void *)); +} +EXPORT_SYMBOL_GPL(srp_iu_put); + +static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md, + enum dma_data_direction dir, srp_rdma_t rdma_io, + int dma_map, int ext_desc) +{ + struct iu_entry *iue = NULL; + struct scatterlist *sg = NULL; + int err, nsg = 0, len; + + if (dma_map) { + iue = (struct iu_entry *) sc->SCp.ptr; + sg = sc->request_buffer; + + dprintk("%p %u %u %d\n", iue, sc->request_bufflen, + md->len, sc->use_sg); + + nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, + DMA_BIDIRECTIONAL); + if (!nsg) { + printk("fail to map %p %d\n", iue, sc->use_sg); + return 0; + } + len = min(sc->request_bufflen, md->len); + } else + len = md->len; + + err = rdma_io(sc, sg, nsg, md, 1, dir, len); + + if (dma_map) + dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL); + + return err; +} + +static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, + struct srp_indirect_buf *id, + enum dma_data_direction dir, srp_rdma_t rdma_io, + int dma_map, int ext_desc) +{ + struct iu_entry *iue = NULL; + struct srp_direct_buf *md = NULL; + struct scatterlist dummy, *sg = NULL; + dma_addr_t token = 0; + long err; + unsigned int done = 0; + int nmd, nsg = 0, len; + + if (dma_map || ext_desc) { + iue = (struct iu_entry *) sc->SCp.ptr; + sg = sc->request_buffer; + + dprintk("%p %u %u %d %d\n", + iue, sc->request_bufflen, id->len, + cmd->data_in_desc_cnt, cmd->data_out_desc_cnt); + } + + nmd = id->table_desc.len / sizeof(struct srp_direct_buf); + + if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) || + (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) { + md = &id->desc_list[0]; + goto rdma; + } + + if (ext_desc && dma_map) { + md = dma_alloc_coherent(iue->target->dev, id->table_desc.len, + &token, GFP_KERNEL); + if (!md) { + eprintk("Can't get dma memory %u\n", id->table_desc.len); + return -ENOMEM; + } + + sg_init_one(&dummy, md, id->table_desc.len); + sg_dma_address(&dummy) = token; + err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE, + id->table_desc.len); + if (err < 0) { + eprintk("Error copying indirect table %ld\n", err); + goto free_mem; + } + } else { + eprintk("This command uses external indirect buffer\n"); + return -EINVAL; + } + +rdma: + if (dma_map) { + nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL); + if (!nsg) { + eprintk("fail to map %p %d\n", iue, sc->use_sg); + goto free_mem; + } + len = min(sc->request_bufflen, id->len); + } else + len = id->len; + + err = rdma_io(sc, sg, nsg, md, nmd, dir, len); + + if (dma_map) + dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL); + +free_mem: + if (token && dma_map) + dma_free_coherent(iue->target->dev, id->table_desc.len, md, token); + + return done; +} + +static int data_out_desc_size(struct srp_cmd *cmd) +{ + int size = 0; + u8 fmt = cmd->buf_fmt >> 4; + + switch (fmt) { + case SRP_NO_DATA_DESC: + break; + case SRP_DATA_DESC_DIRECT: + size = sizeof(struct srp_direct_buf); + break; + case SRP_DATA_DESC_INDIRECT: + size = sizeof(struct srp_indirect_buf) + + sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt; + break; + default: + eprintk("client error. Invalid data_out_format %x\n", fmt); + break; + } + return size; +} + +/* + * TODO: this can be called multiple times for a single command if it + * has very long data. + */ +int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, + srp_rdma_t rdma_io, int dma_map, int ext_desc) +{ + struct srp_direct_buf *md; + struct srp_indirect_buf *id; + enum dma_data_direction dir; + int offset, err = 0; + u8 format; + + offset = cmd->add_cdb_len * 4; + + dir = srp_cmd_direction(cmd); + if (dir == DMA_FROM_DEVICE) + offset += data_out_desc_size(cmd); + + if (dir == DMA_TO_DEVICE) + format = cmd->buf_fmt >> 4; + else + format = cmd->buf_fmt & ((1U << 4) - 1); + + switch (format) { + case SRP_NO_DATA_DESC: + break; + case SRP_DATA_DESC_DIRECT: + md = (struct srp_direct_buf *) + (cmd->add_data + offset); + err = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc); + break; + case SRP_DATA_DESC_INDIRECT: + id = (struct srp_indirect_buf *) + (cmd->add_data + offset); + err = srp_indirect_data(sc, cmd, id, dir, rdma_io, dma_map, + ext_desc); + break; + default: + eprintk("Unknown format %d %x\n", dir, format); + break; + } + + return err; +} +EXPORT_SYMBOL_GPL(srp_transfer_data); + +static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir) +{ + struct srp_direct_buf *md; + struct srp_indirect_buf *id; + int len = 0, offset = cmd->add_cdb_len * 4; + u8 fmt; + + if (dir == DMA_TO_DEVICE) + fmt = cmd->buf_fmt >> 4; + else { + fmt = cmd->buf_fmt & ((1U << 4) - 1); + offset += data_out_desc_size(cmd); + } + + switch (fmt) { + case SRP_NO_DATA_DESC: + break; + case SRP_DATA_DESC_DIRECT: + md = (struct srp_direct_buf *) (cmd->add_data + offset); + len = md->len; + break; + case SRP_DATA_DESC_INDIRECT: + id = (struct srp_indirect_buf *) (cmd->add_data + offset); + len = id->len; + break; + default: + eprintk("invalid data format %x\n", fmt); + break; + } + return len; +} + +int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info, + u64 addr) +{ + enum dma_data_direction dir; + struct scsi_cmnd *sc; + int tag, len, err; + + switch (cmd->task_attr) { + case SRP_SIMPLE_TASK: + tag = MSG_SIMPLE_TAG; + break; + case SRP_ORDERED_TASK: + tag = MSG_ORDERED_TAG; + break; + case SRP_HEAD_TASK: + tag = MSG_HEAD_TAG; + break; + default: + eprintk("Task attribute %d not supported\n", cmd->task_attr); + tag = MSG_ORDERED_TAG; + } + + dir = srp_cmd_direction(cmd); + len = vscsis_data_length(cmd, dir); + + dprintk("%p %x %lx %d %d %d %llx\n", info, cmd->cdb[0], + cmd->lun, dir, len, tag, (unsigned long long) cmd->tag); + + sc = scsi_host_get_command(shost, dir, GFP_KERNEL); + if (!sc) + return -ENOMEM; + + sc->SCp.ptr = info; + memcpy(sc->cmnd, cmd->cdb, MAX_COMMAND_SIZE); + sc->request_bufflen = len; + sc->request_buffer = (void *) (unsigned long) addr; + sc->tag = tag; + err = scsi_tgt_queue_command(sc, (struct scsi_lun *) &cmd->lun, cmd->tag); + if (err) + scsi_host_put_command(shost, sc); + + return err; +} +EXPORT_SYMBOL_GPL(srp_cmd_queue); + +MODULE_DESCRIPTION("SCSI RDAM Protocol lib functions"); +MODULE_AUTHOR("FUJITA Tomonori"); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 3f7f5f8abd7..a7de0bca5bd 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -296,13 +296,17 @@ struct lpfc_hba { uint32_t cfg_cr_delay; uint32_t cfg_cr_count; uint32_t cfg_multi_ring_support; + uint32_t cfg_multi_ring_rctl; + uint32_t cfg_multi_ring_type; uint32_t cfg_fdmi_on; uint32_t cfg_discovery_threads; uint32_t cfg_max_luns; uint32_t cfg_poll; uint32_t cfg_poll_tmo; + uint32_t cfg_use_msi; uint32_t cfg_sg_seg_cnt; uint32_t cfg_sg_dma_buf_size; + uint64_t cfg_soft_wwnn; uint64_t cfg_soft_wwpn; uint32_t dev_loss_tmo_changed; @@ -355,7 +359,7 @@ struct lpfc_hba { #define VPD_PORT 0x8 /* valid vpd port data */ #define VPD_MASK 0xf /* mask for any vpd data */ - uint8_t soft_wwpn_enable; + uint8_t soft_wwn_enable; struct timer_list fcp_poll_timer; struct timer_list els_tmofunc; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 2a4e02e7a39..f247e786af9 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -552,10 +552,10 @@ static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset); -static char *lpfc_soft_wwpn_key = "C99G71SL8032A"; +static char *lpfc_soft_wwn_key = "C99G71SL8032A"; static ssize_t -lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf, +lpfc_soft_wwn_enable_store(struct class_device *cdev, const char *buf, size_t count) { struct Scsi_Host *host = class_to_shost(cdev); @@ -579,15 +579,15 @@ lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf, if (buf[cnt-1] == '\n') cnt--; - if ((cnt != strlen(lpfc_soft_wwpn_key)) || - (strncmp(buf, lpfc_soft_wwpn_key, strlen(lpfc_soft_wwpn_key)) != 0)) + if ((cnt != strlen(lpfc_soft_wwn_key)) || + (strncmp(buf, lpfc_soft_wwn_key, strlen(lpfc_soft_wwn_key)) != 0)) return -EINVAL; - phba->soft_wwpn_enable = 1; + phba->soft_wwn_enable = 1; return count; } -static CLASS_DEVICE_ATTR(lpfc_soft_wwpn_enable, S_IWUSR, NULL, - lpfc_soft_wwpn_enable_store); +static CLASS_DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL, + lpfc_soft_wwn_enable_store); static ssize_t lpfc_soft_wwpn_show(struct class_device *cdev, char *buf) @@ -613,12 +613,12 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count) if (buf[cnt-1] == '\n') cnt--; - if (!phba->soft_wwpn_enable || (cnt < 16) || (cnt > 18) || + if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) || ((cnt == 17) && (*buf++ != 'x')) || ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x')))) return -EINVAL; - phba->soft_wwpn_enable = 0; + phba->soft_wwn_enable = 0; memset(wwpn, 0, sizeof(wwpn)); @@ -639,6 +639,8 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count) } phba->cfg_soft_wwpn = wwn_to_u64(wwpn); fc_host_port_name(host) = phba->cfg_soft_wwpn; + if (phba->cfg_soft_wwnn) + fc_host_node_name(host) = phba->cfg_soft_wwnn; dev_printk(KERN_NOTICE, &phba->pcidev->dev, "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no); @@ -664,6 +666,66 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count) static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\ lpfc_soft_wwpn_show, lpfc_soft_wwpn_store); +static ssize_t +lpfc_soft_wwnn_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; + return snprintf(buf, PAGE_SIZE, "0x%llx\n", + (unsigned long long)phba->cfg_soft_wwnn); +} + + +static ssize_t +lpfc_soft_wwnn_store(struct class_device *cdev, const char *buf, size_t count) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; + unsigned int i, j, cnt=count; + u8 wwnn[8]; + + /* count may include a LF at end of string */ + if (buf[cnt-1] == '\n') + cnt--; + + if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) || + ((cnt == 17) && (*buf++ != 'x')) || + ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x')))) + return -EINVAL; + + /* + * Allow wwnn to be set many times, as long as the enable is set. + * However, once the wwpn is set, everything locks. + */ + + memset(wwnn, 0, sizeof(wwnn)); + + /* Validate and store the new name */ + for (i=0, j=0; i < 16; i++) { + if ((*buf >= 'a') && (*buf <= 'f')) + j = ((j << 4) | ((*buf++ -'a') + 10)); + else if ((*buf >= 'A') && (*buf <= 'F')) + j = ((j << 4) | ((*buf++ -'A') + 10)); + else if ((*buf >= '0') && (*buf <= '9')) + j = ((j << 4) | (*buf++ -'0')); + else + return -EINVAL; + if (i % 2) { + wwnn[i/2] = j & 0xff; + j = 0; + } + } + phba->cfg_soft_wwnn = wwn_to_u64(wwnn); + + dev_printk(KERN_NOTICE, &phba->pcidev->dev, + "lpfc%d: soft_wwnn set. Value will take effect upon " + "setting of the soft_wwpn\n", phba->brd_no); + + return count; +} +static CLASS_DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,\ + lpfc_soft_wwnn_show, lpfc_soft_wwnn_store); + static int lpfc_poll = 0; module_param(lpfc_poll, int, 0); @@ -802,12 +864,11 @@ static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR, # LOG_MBOX 0x4 Mailbox events # LOG_INIT 0x8 Initialization events # LOG_LINK_EVENT 0x10 Link events -# LOG_IP 0x20 IP traffic history # LOG_FCP 0x40 FCP traffic history # LOG_NODE 0x80 Node table events # LOG_MISC 0x400 Miscellaneous events # LOG_SLI 0x800 SLI events -# LOG_CHK_COND 0x1000 FCP Check condition flag +# LOG_FCP_ERROR 0x1000 Only log FCP errors # LOG_LIBDFC 0x2000 LIBDFC events # LOG_ALL_MSG 0xffff LOG all messages */ @@ -916,6 +977,22 @@ LPFC_ATTR_R(multi_ring_support, 1, 1, 2, "Determines number of primary " "SLI rings to spread IOCB entries across"); /* +# lpfc_multi_ring_rctl: If lpfc_multi_ring_support is enabled, this +# identifies what rctl value to configure the additional ring for. +# Value range is [1,0xff]. Default value is 4 (Unsolicated Data). +*/ +LPFC_ATTR_R(multi_ring_rctl, FC_UNSOL_DATA, 1, + 255, "Identifies RCTL for additional ring configuration"); + +/* +# lpfc_multi_ring_type: If lpfc_multi_ring_support is enabled, this +# identifies what type value to configure the additional ring for. +# Value range is [1,0xff]. Default value is 5 (LLC/SNAP). +*/ +LPFC_ATTR_R(multi_ring_type, FC_LLC_SNAP, 1, + 255, "Identifies TYPE for additional ring configuration"); + +/* # lpfc_fdmi_on: controls FDMI support. # 0 = no FDMI support # 1 = support FDMI without attribute of hostname @@ -946,6 +1023,15 @@ LPFC_ATTR_R(max_luns, 255, 0, 65535, LPFC_ATTR_RW(poll_tmo, 10, 1, 255, "Milliseconds driver will wait between polling FCP ring"); +/* +# lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that +# support this feature +# 0 = MSI disabled (default) +# 1 = MSI enabled +# Value range is [0,1]. Default value is 0. +*/ +LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible"); + struct class_device_attribute *lpfc_host_attrs[] = { &class_device_attr_info, @@ -974,6 +1060,8 @@ struct class_device_attribute *lpfc_host_attrs[] = { &class_device_attr_lpfc_cr_delay, &class_device_attr_lpfc_cr_count, &class_device_attr_lpfc_multi_ring_support, + &class_device_attr_lpfc_multi_ring_rctl, + &class_device_attr_lpfc_multi_ring_type, &class_device_attr_lpfc_fdmi_on, &class_device_attr_lpfc_max_luns, &class_device_attr_nport_evt_cnt, @@ -982,8 +1070,10 @@ struct class_device_attribute *lpfc_host_attrs[] = { &class_device_attr_issue_reset, &class_device_attr_lpfc_poll, &class_device_attr_lpfc_poll_tmo, + &class_device_attr_lpfc_use_msi, + &class_device_attr_lpfc_soft_wwnn, &class_device_attr_lpfc_soft_wwpn, - &class_device_attr_lpfc_soft_wwpn_enable, + &class_device_attr_lpfc_soft_wwn_enable, NULL, }; @@ -1771,6 +1861,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_cr_delay_init(phba, lpfc_cr_delay); lpfc_cr_count_init(phba, lpfc_cr_count); lpfc_multi_ring_support_init(phba, lpfc_multi_ring_support); + lpfc_multi_ring_rctl_init(phba, lpfc_multi_ring_rctl); + lpfc_multi_ring_type_init(phba, lpfc_multi_ring_type); lpfc_lun_queue_depth_init(phba, lpfc_lun_queue_depth); lpfc_fcp_class_init(phba, lpfc_fcp_class); lpfc_use_adisc_init(phba, lpfc_use_adisc); @@ -1782,9 +1874,11 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_discovery_threads_init(phba, lpfc_discovery_threads); lpfc_max_luns_init(phba, lpfc_max_luns); lpfc_poll_tmo_init(phba, lpfc_poll_tmo); + lpfc_use_msi_init(phba, lpfc_use_msi); lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo); lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo); phba->cfg_poll = lpfc_poll; + phba->cfg_soft_wwnn = 0L; phba->cfg_soft_wwpn = 0L; /* diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 3add7c23785..a51a41b7f15 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -558,6 +558,14 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, return; } +static void +lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, + struct lpfc_iocbq * rspiocb) +{ + lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); + return; +} + void lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp) { @@ -629,6 +637,8 @@ lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode) bpl->tus.f.bdeSize = RNN_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RSNN_NN) bpl->tus.f.bdeSize = RSNN_REQUEST_SZ; + else if (cmdcode == SLI_CTNS_RFF_ID) + bpl->tus.f.bdeSize = RFF_REQUEST_SZ; else bpl->tus.f.bdeSize = 0; bpl->tus.w = le32_to_cpu(bpl->tus.w); @@ -660,6 +670,17 @@ lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode) cmpl = lpfc_cmpl_ct_cmd_rft_id; break; + case SLI_CTNS_RFF_ID: + CtReq->CommandResponse.bits.CmdRsp = + be16_to_cpu(SLI_CTNS_RFF_ID); + CtReq->un.rff.PortId = be32_to_cpu(phba->fc_myDID); + CtReq->un.rff.feature_res = 0; + CtReq->un.rff.feature_tgt = 0; + CtReq->un.rff.type_code = FC_FCP_DATA; + CtReq->un.rff.feature_init = 1; + cmpl = lpfc_cmpl_ct_cmd_rff_id; + break; + case SLI_CTNS_RNN_ID: CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RNN_ID); @@ -934,7 +955,8 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode) ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION); sprintf(ae->un.OsNameVersion, "%s %s %s", - init_utsname()->sysname, init_utsname()->release, + init_utsname()->sysname, + init_utsname()->release, init_utsname()->version); len = strlen(ae->un.OsNameVersion); len += (len & 3) ? (4 - (len & 3)) : 4; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 71864cdc6c7..a5f33a0dd4e 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -243,6 +243,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct serv_parm *sp, IOCB_t *irsp) { LPFC_MBOXQ_t *mbox; + struct lpfc_dmabuf *mp; int rc; spin_lock_irq(phba->host->host_lock); @@ -307,10 +308,14 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); if (rc == MBX_NOT_FINISHED) - goto fail_free_mbox; + goto fail_issue_reg_login; return 0; + fail_issue_reg_login: + mp = (struct lpfc_dmabuf *) mbox->context1; + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); fail_free_mbox: mempool_free(mbox, phba->mbox_mem_pool); fail: @@ -657,6 +662,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp, uint8_t name[sizeof (struct lpfc_name)]; uint32_t rc; + /* Fabric nodes can have the same WWPN so we don't bother searching + * by WWPN. Just return the ndlp that was given to us. + */ + if (ndlp->nlp_type & NLP_FABRIC) + return ndlp; + lp = (uint32_t *) prsp->virt; sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); memset(name, 0, sizeof (struct lpfc_name)); @@ -1122,7 +1133,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, mempool_free(mbox, phba->mbox_mem_pool); lpfc_disc_flush_list(phba); - psli->ring[(psli->ip_ring)]. + psli->ring[(psli->extra_ring)]. flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)]. @@ -1851,6 +1862,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, IOCB_t *irsp; struct lpfc_nodelist *ndlp; LPFC_MBOXQ_t *mbox = NULL; + struct lpfc_dmabuf *mp; irsp = &rspiocb->iocb; @@ -1862,6 +1874,11 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, /* Check to see if link went down during discovery */ if ((lpfc_els_chk_latt(phba)) || !ndlp) { if (mbox) { + mp = (struct lpfc_dmabuf *) mbox->context1; + if (mp) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } mempool_free( mbox, phba->mbox_mem_pool); } goto out; @@ -1893,9 +1910,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, } /* NOTE: we should have messages for unsuccessful reglogin */ - mempool_free( mbox, phba->mbox_mem_pool); } else { - mempool_free( mbox, phba->mbox_mem_pool); /* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */ if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) || @@ -1907,6 +1922,12 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, } } } + mp = (struct lpfc_dmabuf *) mbox->context1; + if (mp) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + mempool_free(mbox, phba->mbox_mem_pool); } out: if (ndlp) { @@ -2644,6 +2665,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba) ndlp->nlp_type |= NLP_FABRIC; ndlp->nlp_prev_state = ndlp->nlp_state; ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; + lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); lpfc_issue_els_plogi(phba, NameServer_DID, 0); /* Wait for NameServer login cmpl before we can continue */ @@ -3039,7 +3061,7 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba, /* FARP-REQ received from DID <did> */ lpfc_printf_log(phba, KERN_INFO, - LOG_IP, + LOG_ELS, "%d:0601 FARP-REQ received from DID x%x\n", phba->brd_no, did); @@ -3101,7 +3123,7 @@ lpfc_els_rcv_farpr(struct lpfc_hba * phba, /* FARP-RSP received from DID <did> */ lpfc_printf_log(phba, KERN_INFO, - LOG_IP, + LOG_ELS, "%d:0600 FARP-RSP received from DID x%x\n", phba->brd_no, did); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 19c79a0549a..c39564e85e9 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -525,7 +525,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) psli = &phba->sli; mb = &pmb->mb; /* Since we don't do discovery right now, turn these off here */ - psli->ring[psli->ip_ring].flag &= ~LPFC_STOP_IOCB_EVENT; + psli->ring[psli->extra_ring].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[psli->fcp_ring].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[psli->next_ring].flag &= ~LPFC_STOP_IOCB_EVENT; @@ -641,7 +641,7 @@ out: if (rc == MBX_NOT_FINISHED) { mempool_free(pmb, phba->mbox_mem_pool); lpfc_disc_flush_list(phba); - psli->ring[(psli->ip_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; + psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; phba->hba_state = LPFC_HBA_READY; @@ -672,6 +672,8 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt, sizeof (struct serv_parm)); + if (phba->cfg_soft_wwnn) + u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn); if (phba->cfg_soft_wwpn) u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn); memcpy((uint8_t *) & phba->fc_nodename, @@ -696,7 +698,7 @@ out: == MBX_NOT_FINISHED) { mempool_free( pmb, phba->mbox_mem_pool); lpfc_disc_flush_list(phba); - psli->ring[(psli->ip_ring)].flag &= + psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; @@ -715,6 +717,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) { int i; LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox; + struct lpfc_dmabuf *mp; + int rc; + sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -793,16 +798,27 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) if (sparam_mbox) { lpfc_read_sparam(phba, sparam_mbox); sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; - lpfc_sli_issue_mbox(phba, sparam_mbox, + rc = lpfc_sli_issue_mbox(phba, sparam_mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + if (rc == MBX_NOT_FINISHED) { + mp = (struct lpfc_dmabuf *) sparam_mbox->context1; + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + mempool_free(sparam_mbox, phba->mbox_mem_pool); + if (cfglink_mbox) + mempool_free(cfglink_mbox, phba->mbox_mem_pool); + return; + } } if (cfglink_mbox) { phba->hba_state = LPFC_LOCAL_CFG_LINK; lpfc_config_link(phba, cfglink_mbox); cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; - lpfc_sli_issue_mbox(phba, cfglink_mbox, + rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + if (rc == MBX_NOT_FINISHED) + mempool_free(cfglink_mbox, phba->mbox_mem_pool); } } @@ -1067,6 +1083,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RNN_ID); lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RSNN_NN); lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFT_ID); + lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFF_ID); } phba->fc_ns_retry = 0; @@ -1423,7 +1440,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba, if (iocb->context1 == (uint8_t *) ndlp) return 1; } - } else if (pring->ringno == psli->ip_ring) { + } else if (pring->ringno == psli->extra_ring) { } else if (pring->ringno == psli->fcp_ring) { /* Skip match check if waiting to relogin to FCP target */ @@ -1680,112 +1697,38 @@ lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did) struct lpfc_nodelist * lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) { - struct lpfc_nodelist *ndlp, *next_ndlp; + struct lpfc_nodelist *ndlp; + struct list_head *lists[]={&phba->fc_nlpunmap_list, + &phba->fc_nlpmap_list, + &phba->fc_plogi_list, + &phba->fc_adisc_list, + &phba->fc_reglogin_list, + &phba->fc_prli_list, + &phba->fc_npr_list, + &phba->fc_unused_list}; + uint32_t search[]={NLP_SEARCH_UNMAPPED, + NLP_SEARCH_MAPPED, + NLP_SEARCH_PLOGI, + NLP_SEARCH_ADISC, + NLP_SEARCH_REGLOGIN, + NLP_SEARCH_PRLI, + NLP_SEARCH_NPR, + NLP_SEARCH_UNUSED}; + int i; uint32_t data1; spin_lock_irq(phba->host->host_lock); - if (order & NLP_SEARCH_UNMAPPED) { - list_for_each_entry_safe(ndlp, next_ndlp, - &phba->fc_nlpunmap_list, nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* FIND node DID unmapped */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0929 FIND node DID unmapped" - " Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - spin_unlock_irq(phba->host->host_lock); - return ndlp; - } - } - } - - if (order & NLP_SEARCH_MAPPED) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* FIND node DID mapped */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0930 FIND node DID mapped " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - spin_unlock_irq(phba->host->host_lock); - return ndlp; - } - } - } - - if (order & NLP_SEARCH_PLOGI) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to PLOGI */ - /* FIND node DID plogi */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0908 FIND node DID plogi " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - spin_unlock_irq(phba->host->host_lock); - return ndlp; - } - } - } - - if (order & NLP_SEARCH_ADISC) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to ADISC */ - /* FIND node DID adisc */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID adisc " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - spin_unlock_irq(phba->host->host_lock); - return ndlp; - } - } - } - - if (order & NLP_SEARCH_REGLOGIN) { - list_for_each_entry_safe(ndlp, next_ndlp, - &phba->fc_reglogin_list, nlp_listp) { + for (i = 0; i < ARRAY_SIZE(lists); i++ ) { + if (!(order & search[i])) + continue; + list_for_each_entry(ndlp, lists[i], nlp_listp) { if (lpfc_matchdid(phba, ndlp, did)) { - data1 = (((uint32_t) ndlp->nlp_state << 24) | ((uint32_t) ndlp->nlp_xri << 16) | ((uint32_t) ndlp->nlp_type << 8) | ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to REGLOGIN */ - /* FIND node DID reglogin */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0901 FIND node DID reglogin" + "%d:0929 FIND node DID " " Data: x%p x%x x%x x%x\n", phba->brd_no, ndlp, ndlp->nlp_DID, @@ -1795,86 +1738,12 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) } } } - - if (order & NLP_SEARCH_PRLI) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to PRLI */ - /* FIND node DID prli */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0902 FIND node DID prli " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - spin_unlock_irq(phba->host->host_lock); - return ndlp; - } - } - } - - if (order & NLP_SEARCH_NPR) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to NPR */ - /* FIND node DID npr */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0903 FIND node DID npr " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - spin_unlock_irq(phba->host->host_lock); - return ndlp; - } - } - } - - if (order & NLP_SEARCH_UNUSED) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to UNUSED */ - /* FIND node DID unused */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0905 FIND node DID unused " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - spin_unlock_irq(phba->host->host_lock); - return ndlp; - } - } - } - spin_unlock_irq(phba->host->host_lock); /* FIND node did <did> NOT FOUND */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_NODE, + lpfc_printf_log(phba, KERN_INFO, LOG_NODE, "%d:0932 FIND node did x%x NOT FOUND Data: x%x\n", phba->brd_no, did, order); - - /* no match found */ return NULL; } @@ -2036,7 +1905,7 @@ lpfc_disc_start(struct lpfc_hba * phba) if (rc == MBX_NOT_FINISHED) { mempool_free( mbox, phba->mbox_mem_pool); lpfc_disc_flush_list(phba); - psli->ring[(psli->ip_ring)].flag &= + psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; @@ -2415,7 +2284,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) if (clrlaerr) { lpfc_disc_flush_list(phba); - psli->ring[(psli->ip_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; + psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; phba->hba_state = LPFC_HBA_READY; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index eedf9880136..f79cb613690 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -42,14 +42,14 @@ #define FCELSSIZE 1024 /* maximum ELS transfer size */ #define LPFC_FCP_RING 0 /* ring 0 for FCP initiator commands */ -#define LPFC_IP_RING 1 /* ring 1 for IP commands */ +#define LPFC_EXTRA_RING 1 /* ring 1 for other protocols */ #define LPFC_ELS_RING 2 /* ring 2 for ELS commands */ #define LPFC_FCP_NEXT_RING 3 #define SLI2_IOCB_CMD_R0_ENTRIES 172 /* SLI-2 FCP command ring entries */ #define SLI2_IOCB_RSP_R0_ENTRIES 134 /* SLI-2 FCP response ring entries */ -#define SLI2_IOCB_CMD_R1_ENTRIES 4 /* SLI-2 IP command ring entries */ -#define SLI2_IOCB_RSP_R1_ENTRIES 4 /* SLI-2 IP response ring entries */ +#define SLI2_IOCB_CMD_R1_ENTRIES 4 /* SLI-2 extra command ring entries */ +#define SLI2_IOCB_RSP_R1_ENTRIES 4 /* SLI-2 extra response ring entries */ #define SLI2_IOCB_CMD_R1XTRA_ENTRIES 36 /* SLI-2 extra FCP cmd ring entries */ #define SLI2_IOCB_RSP_R1XTRA_ENTRIES 52 /* SLI-2 extra FCP rsp ring entries */ #define SLI2_IOCB_CMD_R2_ENTRIES 20 /* SLI-2 ELS command ring entries */ @@ -121,6 +121,20 @@ struct lpfc_sli_ct_request { uint32_t rsvd[7]; } rft; + struct rff { + uint32_t PortId; + uint8_t reserved[2]; +#ifdef __BIG_ENDIAN_BITFIELD + uint8_t feature_res:6; + uint8_t feature_init:1; + uint8_t feature_tgt:1; +#else /* __LITTLE_ENDIAN_BITFIELD */ + uint8_t feature_tgt:1; + uint8_t feature_init:1; + uint8_t feature_res:6; +#endif + uint8_t type_code; /* type=8 for FCP */ + } rff; struct rnn { uint32_t PortId; /* For RNN_ID requests */ uint8_t wwnn[8]; @@ -136,6 +150,7 @@ struct lpfc_sli_ct_request { #define SLI_CT_REVISION 1 #define GID_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 260) #define RFT_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 228) +#define RFF_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 235) #define RNN_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 252) #define RSNN_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request)) @@ -225,6 +240,7 @@ struct lpfc_sli_ct_request { #define SLI_CTNS_RNN_ID 0x0213 #define SLI_CTNS_RCS_ID 0x0214 #define SLI_CTNS_RFT_ID 0x0217 +#define SLI_CTNS_RFF_ID 0x021F #define SLI_CTNS_RSPN_ID 0x0218 #define SLI_CTNS_RPT_ID 0x021A #define SLI_CTNS_RIP_NN 0x0235 @@ -1089,12 +1105,6 @@ typedef struct { #define PCI_DEVICE_ID_ZEPHYR_SCSP 0xfe11 #define PCI_DEVICE_ID_ZEPHYR_DCSP 0xfe12 -#define PCI_SUBSYSTEM_ID_LP11000S 0xfc11 -#define PCI_SUBSYSTEM_ID_LP11002S 0xfc12 -#define PCI_SUBSYSTEM_ID_LPE11000S 0xfc21 -#define PCI_SUBSYSTEM_ID_LPE11002S 0xfc22 -#define PCI_SUBSYSTEM_ID_LPE11010S 0xfc2A - #define JEDEC_ID_ADDRESS 0x0080001c #define FIREFLY_JEDEC_ID 0x1ACC #define SUPERFLY_JEDEC_ID 0x0020 @@ -1284,6 +1294,10 @@ typedef struct { /* FireFly BIU registers */ #define CMD_FCP_IREAD_CX 0x1B #define CMD_FCP_ICMND_CR 0x1C #define CMD_FCP_ICMND_CX 0x1D +#define CMD_FCP_TSEND_CX 0x1F +#define CMD_FCP_TRECEIVE_CX 0x21 +#define CMD_FCP_TRSP_CX 0x23 +#define CMD_FCP_AUTO_TRSP_CX 0x29 #define CMD_ADAPTER_MSG 0x20 #define CMD_ADAPTER_DUMP 0x22 @@ -1310,6 +1324,9 @@ typedef struct { /* FireFly BIU registers */ #define CMD_FCP_IREAD64_CX 0x9B #define CMD_FCP_ICMND64_CR 0x9C #define CMD_FCP_ICMND64_CX 0x9D +#define CMD_FCP_TSEND64_CX 0x9F +#define CMD_FCP_TRECEIVE64_CX 0xA1 +#define CMD_FCP_TRSP64_CX 0xA3 #define CMD_GEN_REQUEST64_CR 0xC2 #define CMD_GEN_REQUEST64_CX 0xC3 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index a5723ad0a09..afca45cdbce 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -268,6 +268,8 @@ lpfc_config_port_post(struct lpfc_hba * phba) kfree(mp); pmb->context1 = NULL; + if (phba->cfg_soft_wwnn) + u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn); if (phba->cfg_soft_wwpn) u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn); memcpy(&phba->fc_nodename, &phba->fc_sparam.nodeName, @@ -349,8 +351,8 @@ lpfc_config_port_post(struct lpfc_hba * phba) phba->hba_state = LPFC_LINK_DOWN; /* Only process IOCBs on ring 0 till hba_state is READY */ - if (psli->ring[psli->ip_ring].cmdringaddr) - psli->ring[psli->ip_ring].flag |= LPFC_STOP_IOCB_EVENT; + if (psli->ring[psli->extra_ring].cmdringaddr) + psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT; if (psli->ring[psli->fcp_ring].cmdringaddr) psli->ring[psli->fcp_ring].flag |= LPFC_STOP_IOCB_EVENT; if (psli->ring[psli->next_ring].cmdringaddr) @@ -517,7 +519,8 @@ lpfc_handle_eratt(struct lpfc_hba * phba) struct lpfc_sli_ring *pring; uint32_t event_data; - if (phba->work_hs & HS_FFER6) { + if (phba->work_hs & HS_FFER6 || + phba->work_hs & HS_FFER5) { /* Re-establishing Link */ lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, "%d:1301 Re-establishing Link " @@ -611,7 +614,7 @@ lpfc_handle_latt(struct lpfc_hba * phba) pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la; rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB)); if (rc == MBX_NOT_FINISHED) - goto lpfc_handle_latt_free_mp; + goto lpfc_handle_latt_free_mbuf; /* Clear Link Attention in HA REG */ spin_lock_irq(phba->host->host_lock); @@ -621,6 +624,8 @@ lpfc_handle_latt(struct lpfc_hba * phba) return; +lpfc_handle_latt_free_mbuf: + lpfc_mbuf_free(phba, mp->virt, mp->phys); lpfc_handle_latt_free_mp: kfree(mp); lpfc_handle_latt_free_pmb: @@ -802,19 +807,13 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) { lpfc_vpd_t *vp; uint16_t dev_id = phba->pcidev->device; - uint16_t dev_subid = phba->pcidev->subsystem_device; - uint8_t hdrtype; int max_speed; - char * ports; struct { char * name; int max_speed; - char * ports; char * bus; - } m = {"<Unknown>", 0, "", ""}; + } m = {"<Unknown>", 0, ""}; - pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype); - ports = (hdrtype == 0x80) ? "2-port " : ""; if (mdp && mdp[0] != '\0' && descp && descp[0] != '\0') return; @@ -834,130 +833,93 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) switch (dev_id) { case PCI_DEVICE_ID_FIREFLY: - m = (typeof(m)){"LP6000", max_speed, "", "PCI"}; + m = (typeof(m)){"LP6000", max_speed, "PCI"}; break; case PCI_DEVICE_ID_SUPERFLY: if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3) - m = (typeof(m)){"LP7000", max_speed, "", "PCI"}; + m = (typeof(m)){"LP7000", max_speed, "PCI"}; else - m = (typeof(m)){"LP7000E", max_speed, "", "PCI"}; + m = (typeof(m)){"LP7000E", max_speed, "PCI"}; break; case PCI_DEVICE_ID_DRAGONFLY: - m = (typeof(m)){"LP8000", max_speed, "", "PCI"}; + m = (typeof(m)){"LP8000", max_speed, "PCI"}; break; case PCI_DEVICE_ID_CENTAUR: if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) - m = (typeof(m)){"LP9002", max_speed, "", "PCI"}; + m = (typeof(m)){"LP9002", max_speed, "PCI"}; else - m = (typeof(m)){"LP9000", max_speed, "", "PCI"}; + m = (typeof(m)){"LP9000", max_speed, "PCI"}; break; case PCI_DEVICE_ID_RFLY: - m = (typeof(m)){"LP952", max_speed, "", "PCI"}; + m = (typeof(m)){"LP952", max_speed, "PCI"}; break; case PCI_DEVICE_ID_PEGASUS: - m = (typeof(m)){"LP9802", max_speed, "", "PCI-X"}; + m = (typeof(m)){"LP9802", max_speed, "PCI-X"}; break; case PCI_DEVICE_ID_THOR: - if (hdrtype == 0x80) - m = (typeof(m)){"LP10000DC", - max_speed, ports, "PCI-X"}; - else - m = (typeof(m)){"LP10000", - max_speed, ports, "PCI-X"}; + m = (typeof(m)){"LP10000", max_speed, "PCI-X"}; break; case PCI_DEVICE_ID_VIPER: - m = (typeof(m)){"LPX1000", max_speed, "", "PCI-X"}; + m = (typeof(m)){"LPX1000", max_speed, "PCI-X"}; break; case PCI_DEVICE_ID_PFLY: - m = (typeof(m)){"LP982", max_speed, "", "PCI-X"}; + m = (typeof(m)){"LP982", max_speed, "PCI-X"}; break; case PCI_DEVICE_ID_TFLY: - if (hdrtype == 0x80) - m = (typeof(m)){"LP1050DC", max_speed, ports, "PCI-X"}; - else - m = (typeof(m)){"LP1050", max_speed, ports, "PCI-X"}; + m = (typeof(m)){"LP1050", max_speed, "PCI-X"}; break; case PCI_DEVICE_ID_HELIOS: - if (hdrtype == 0x80) - m = (typeof(m)){"LP11002", max_speed, ports, "PCI-X2"}; - else - m = (typeof(m)){"LP11000", max_speed, ports, "PCI-X2"}; + m = (typeof(m)){"LP11000", max_speed, "PCI-X2"}; break; case PCI_DEVICE_ID_HELIOS_SCSP: - m = (typeof(m)){"LP11000-SP", max_speed, ports, "PCI-X2"}; + m = (typeof(m)){"LP11000-SP", max_speed, "PCI-X2"}; break; case PCI_DEVICE_ID_HELIOS_DCSP: - m = (typeof(m)){"LP11002-SP", max_speed, ports, "PCI-X2"}; + m = (typeof(m)){"LP11002-SP", max_speed, "PCI-X2"}; break; case PCI_DEVICE_ID_NEPTUNE: - if (hdrtype == 0x80) - m = (typeof(m)){"LPe1002", max_speed, ports, "PCIe"}; - else - m = (typeof(m)){"LPe1000", max_speed, ports, "PCIe"}; + m = (typeof(m)){"LPe1000", max_speed, "PCIe"}; break; case PCI_DEVICE_ID_NEPTUNE_SCSP: - m = (typeof(m)){"LPe1000-SP", max_speed, ports, "PCIe"}; + m = (typeof(m)){"LPe1000-SP", max_speed, "PCIe"}; break; case PCI_DEVICE_ID_NEPTUNE_DCSP: - m = (typeof(m)){"LPe1002-SP", max_speed, ports, "PCIe"}; + m = (typeof(m)){"LPe1002-SP", max_speed, "PCIe"}; break; case PCI_DEVICE_ID_BMID: - m = (typeof(m)){"LP1150", max_speed, ports, "PCI-X2"}; + m = (typeof(m)){"LP1150", max_speed, "PCI-X2"}; break; case PCI_DEVICE_ID_BSMB: - m = (typeof(m)){"LP111", max_speed, ports, "PCI-X2"}; + m = (typeof(m)){"LP111", max_speed, "PCI-X2"}; break; case PCI_DEVICE_ID_ZEPHYR: - if (hdrtype == 0x80) - m = (typeof(m)){"LPe11002", max_speed, ports, "PCIe"}; - else - m = (typeof(m)){"LPe11000", max_speed, ports, "PCIe"}; + m = (typeof(m)){"LPe11000", max_speed, "PCIe"}; break; case PCI_DEVICE_ID_ZEPHYR_SCSP: - m = (typeof(m)){"LPe11000", max_speed, ports, "PCIe"}; + m = (typeof(m)){"LPe11000", max_speed, "PCIe"}; break; case PCI_DEVICE_ID_ZEPHYR_DCSP: - m = (typeof(m)){"LPe11002-SP", max_speed, ports, "PCIe"}; + m = (typeof(m)){"LPe11002-SP", max_speed, "PCIe"}; break; case PCI_DEVICE_ID_ZMID: - m = (typeof(m)){"LPe1150", max_speed, ports, "PCIe"}; + m = (typeof(m)){"LPe1150", max_speed, "PCIe"}; break; case PCI_DEVICE_ID_ZSMB: - m = (typeof(m)){"LPe111", max_speed, ports, "PCIe"}; + m = (typeof(m)){"LPe111", max_speed, "PCIe"}; break; case PCI_DEVICE_ID_LP101: - m = (typeof(m)){"LP101", max_speed, ports, "PCI-X"}; + m = (typeof(m)){"LP101", max_speed, "PCI-X"}; break; case PCI_DEVICE_ID_LP10000S: - m = (typeof(m)){"LP10000-S", max_speed, ports, "PCI"}; + m = (typeof(m)){"LP10000-S", max_speed, "PCI"}; break; case PCI_DEVICE_ID_LP11000S: + m = (typeof(m)){"LP11000-S", max_speed, + "PCI-X2"}; + break; case PCI_DEVICE_ID_LPE11000S: - switch (dev_subid) { - case PCI_SUBSYSTEM_ID_LP11000S: - m = (typeof(m)){"LP11000-S", max_speed, - ports, "PCI-X2"}; - break; - case PCI_SUBSYSTEM_ID_LP11002S: - m = (typeof(m)){"LP11002-S", max_speed, - ports, "PCI-X2"}; - break; - case PCI_SUBSYSTEM_ID_LPE11000S: - m = (typeof(m)){"LPe11000-S", max_speed, - ports, "PCIe"}; - break; - case PCI_SUBSYSTEM_ID_LPE11002S: - m = (typeof(m)){"LPe11002-S", max_speed, - ports, "PCIe"}; - break; - case PCI_SUBSYSTEM_ID_LPE11010S: - m = (typeof(m)){"LPe11010-S", max_speed, - "10-port ", "PCIe"}; - break; - default: - m = (typeof(m)){ NULL }; - break; - } + m = (typeof(m)){"LPe11000-S", max_speed, + "PCIe"}; break; default: m = (typeof(m)){ NULL }; @@ -968,8 +930,8 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) snprintf(mdp, 79,"%s", m.name); if (descp && descp[0] == '\0') snprintf(descp, 255, - "Emulex %s %dGb %s%s Fibre Channel Adapter", - m.name, m.max_speed, m.ports, m.bus); + "Emulex %s %dGb %s Fibre Channel Adapter", + m.name, m.max_speed, m.bus); } /**************************************************/ @@ -1651,6 +1613,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) if (error) goto out_remove_host; + if (phba->cfg_use_msi) { + error = pci_enable_msi(phba->pcidev); + if (error) + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "%d:0452 " + "Enable MSI failed, continuing with " + "IRQ\n", phba->brd_no); + } + error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED, LPFC_DRIVER_NAME, phba); if (error) { @@ -1730,6 +1700,7 @@ out_free_irq: lpfc_stop_timer(phba); phba->work_hba_events = 0; free_irq(phba->pcidev->irq, phba); + pci_disable_msi(phba->pcidev); out_free_sysfs_attr: lpfc_free_sysfs_attr(phba); out_remove_host: @@ -1796,6 +1767,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) /* Release the irq reservation */ free_irq(phba->pcidev->irq, phba); + pci_disable_msi(phba->pcidev); lpfc_cleanup(phba, 0); lpfc_stop_timer(phba); diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index 62c8ca862e9..438cbcd9eb1 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h @@ -28,7 +28,7 @@ #define LOG_NODE 0x80 /* Node table events */ #define LOG_MISC 0x400 /* Miscellaneous events */ #define LOG_SLI 0x800 /* SLI events */ -#define LOG_CHK_COND 0x1000 /* FCP Check condition flag */ +#define LOG_FCP_ERROR 0x1000 /* log errors, not underruns */ #define LOG_LIBDFC 0x2000 /* Libdfc events */ #define LOG_ALL_MSG 0xffff /* LOG all messages */ diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index d5f415007db..0c7e731dc45 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -739,7 +739,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba, uint32_t evt) { struct lpfc_iocbq *cmdiocb, *rspiocb; - struct lpfc_dmabuf *pcmd, *prsp; + struct lpfc_dmabuf *pcmd, *prsp, *mp; uint32_t *lp; IOCB_t *irsp; struct serv_parm *sp; @@ -829,6 +829,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba, NLP_REGLOGIN_LIST); return ndlp->nlp_state; } + mp = (struct lpfc_dmabuf *)mbox->context1; + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); mempool_free(mbox, phba->mbox_mem_pool); } else { mempool_free(mbox, phba->mbox_mem_pool); @@ -1620,8 +1623,8 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba, * or discovery in progress for this node. Starting discovery * here will affect the counting of discovery threads. */ - if ((!(ndlp->nlp_flag & NLP_DELAY_TMO)) && - (ndlp->nlp_flag & NLP_NPR_2B_DISC)){ + if (!(ndlp->nlp_flag & NLP_DELAY_TMO) && + !(ndlp->nlp_flag & NLP_NPR_2B_DISC)){ if (ndlp->nlp_flag & NLP_NPR_ADISC) { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; ndlp->nlp_state = NLP_STE_ADISC_ISSUE; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 97ae98dc95d..c3e68e0d8f7 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -297,8 +297,10 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd) uint32_t fcpi_parm = lpfc_cmd->cur_iocbq.iocb.un.fcpi.fcpi_parm; uint32_t resp_info = fcprsp->rspStatus2; uint32_t scsi_status = fcprsp->rspStatus3; + uint32_t *lp; uint32_t host_status = DID_OK; uint32_t rsplen = 0; + uint32_t logit = LOG_FCP | LOG_FCP_ERROR; /* * If this is a task management command, there is no @@ -310,10 +312,25 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd) goto out; } - lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, - "%d:0730 FCP command failed: RSP " - "Data: x%x x%x x%x x%x x%x x%x\n", - phba->brd_no, resp_info, scsi_status, + if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) { + uint32_t snslen = be32_to_cpu(fcprsp->rspSnsLen); + if (snslen > SCSI_SENSE_BUFFERSIZE) + snslen = SCSI_SENSE_BUFFERSIZE; + + if (resp_info & RSP_LEN_VALID) + rsplen = be32_to_cpu(fcprsp->rspRspLen); + memcpy(cmnd->sense_buffer, &fcprsp->rspInfo0 + rsplen, snslen); + } + lp = (uint32_t *)cmnd->sense_buffer; + + if (!scsi_status && (resp_info & RESID_UNDER)) + logit = LOG_FCP; + + lpfc_printf_log(phba, KERN_WARNING, logit, + "%d:0730 FCP command x%x failed: x%x SNS x%x x%x " + "Data: x%x x%x x%x x%x x%x\n", + phba->brd_no, cmnd->cmnd[0], scsi_status, + be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info, be32_to_cpu(fcprsp->rspResId), be32_to_cpu(fcprsp->rspSnsLen), be32_to_cpu(fcprsp->rspRspLen), @@ -328,14 +345,6 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd) } } - if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) { - uint32_t snslen = be32_to_cpu(fcprsp->rspSnsLen); - if (snslen > SCSI_SENSE_BUFFERSIZE) - snslen = SCSI_SENSE_BUFFERSIZE; - - memcpy(cmnd->sense_buffer, &fcprsp->rspInfo0 + rsplen, snslen); - } - cmnd->resid = 0; if (resp_info & RESID_UNDER) { cmnd->resid = be32_to_cpu(fcprsp->rspResId); @@ -378,7 +387,7 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd) */ } else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, + lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR, "%d:0734 FCP Read Check Error Data: " "x%x x%x x%x x%x\n", phba->brd_no, be32_to_cpu(fcpcmd->fcpDl), @@ -670,6 +679,9 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba, struct lpfc_iocbq *iocbqrsp; int ret; + if (!rdata->pnode) + return FAILED; + lpfc_cmd->rdata = rdata; ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, lun, FCP_TARGET_RESET); @@ -976,20 +988,34 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) lpfc_block_error_handler(cmnd); spin_lock_irq(shost->host_lock); + loopcnt = 0; /* * If target is not in a MAPPED state, delay the reset until * target is rediscovered or devloss timeout expires. */ while ( 1 ) { if (!pnode) - break; + return FAILED; if (pnode->nlp_state != NLP_STE_MAPPED_NODE) { spin_unlock_irq(phba->host->host_lock); schedule_timeout_uninterruptible(msecs_to_jiffies(500)); spin_lock_irq(phba->host->host_lock); + loopcnt++; + rdata = cmnd->device->hostdata; + if (!rdata || + (loopcnt > ((phba->cfg_devloss_tmo * 2) + 1))) { + lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + "%d:0721 LUN Reset rport failure:" + " cnt x%x rdata x%p\n", + phba->brd_no, loopcnt, rdata); + goto out; + } + pnode = rdata->pnode; + if (!pnode) + return FAILED; } - if ((pnode) && (pnode->nlp_state == NLP_STE_MAPPED_NODE)) + if (pnode->nlp_state == NLP_STE_MAPPED_NODE) break; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 582f5ea4e84..a4128e19338 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -117,6 +117,10 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case CMD_FCP_IREAD_CX: case CMD_FCP_ICMND_CR: case CMD_FCP_ICMND_CX: + case CMD_FCP_TSEND_CX: + case CMD_FCP_TRSP_CX: + case CMD_FCP_TRECEIVE_CX: + case CMD_FCP_AUTO_TRSP_CX: case CMD_ADAPTER_MSG: case CMD_ADAPTER_DUMP: case CMD_XMIT_SEQUENCE64_CR: @@ -131,6 +135,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case CMD_FCP_IREAD64_CX: case CMD_FCP_ICMND64_CR: case CMD_FCP_ICMND64_CX: + case CMD_FCP_TSEND64_CX: + case CMD_FCP_TRSP64_CX: + case CMD_FCP_TRECEIVE64_CX: case CMD_GEN_REQUEST64_CR: case CMD_GEN_REQUEST64_CX: case CMD_XMIT_ELS_RSP64_CX: @@ -1098,6 +1105,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, lpfc_sli_pcimem_bcopy((uint32_t *) entry, (uint32_t *) &rspiocbq.iocb, sizeof (IOCB_t)); + INIT_LIST_HEAD(&(rspiocbq.list)); irsp = &rspiocbq.iocb; type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK); @@ -1149,6 +1157,11 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, } } break; + case LPFC_UNSOL_IOCB: + spin_unlock_irqrestore(phba->host->host_lock, iflag); + lpfc_sli_process_unsol_iocb(phba, pring, &rspiocbq); + spin_lock_irqsave(phba->host->host_lock, iflag); + break; default: if (irsp->ulpCommand == CMD_ADAPTER_MSG) { char adaptermsg[LPFC_MAX_ADPTMSG]; @@ -2472,13 +2485,17 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) psli = &phba->sli; /* Adjust cmd/rsp ring iocb entries more evenly */ + + /* Take some away from the FCP ring */ pring = &psli->ring[psli->fcp_ring]; pring->numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES; pring->numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES; pring->numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES; pring->numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES; - pring = &psli->ring[1]; + /* and give them to the extra ring */ + pring = &psli->ring[psli->extra_ring]; + pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES; pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES; pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES; @@ -2488,8 +2505,8 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) pring->iotag_max = 4096; pring->num_mask = 1; pring->prt[0].profile = 0; /* Mask 0 */ - pring->prt[0].rctl = FC_UNSOL_DATA; - pring->prt[0].type = 5; + pring->prt[0].rctl = phba->cfg_multi_ring_rctl; + pring->prt[0].type = phba->cfg_multi_ring_type; pring->prt[0].lpfc_sli_rcv_unsol_event = NULL; return 0; } @@ -2505,7 +2522,7 @@ lpfc_sli_setup(struct lpfc_hba *phba) psli->sli_flag = 0; psli->fcp_ring = LPFC_FCP_RING; psli->next_ring = LPFC_FCP_NEXT_RING; - psli->ip_ring = LPFC_IP_RING; + psli->extra_ring = LPFC_EXTRA_RING; psli->iocbq_lookup = NULL; psli->iocbq_lookup_len = 0; @@ -2528,7 +2545,7 @@ lpfc_sli_setup(struct lpfc_hba *phba) pring->fast_iotag = pring->iotag_max; pring->num_mask = 0; break; - case LPFC_IP_RING: /* ring 1 - IP */ + case LPFC_EXTRA_RING: /* ring 1 - EXTRA */ /* numCiocb and numRiocb are used in config_port */ pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES; pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES; @@ -3238,6 +3255,21 @@ lpfc_intr_handler(int irq, void *dev_id) lpfc_sli_handle_fast_ring_event(phba, &phba->sli.ring[LPFC_FCP_RING], status); + + if (phba->cfg_multi_ring_support == 2) { + /* + * Process all events on extra ring. Take the optimized path + * for extra ring IO. Any other IO is slow path and is handled + * by the worker thread. + */ + status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING))); + status >>= (4*LPFC_EXTRA_RING); + if (status & HA_RXATT) { + lpfc_sli_handle_fast_ring_event(phba, + &phba->sli.ring[LPFC_EXTRA_RING], + status); + } + } return IRQ_HANDLED; } /* lpfc_intr_handler */ diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index e26de680935..a43549959dc 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -198,7 +198,7 @@ struct lpfc_sli { int fcp_ring; /* ring used for FCP initiator commands */ int next_ring; - int ip_ring; /* ring used for IP network drv cmds */ + int extra_ring; /* extra ring used for other protocols */ struct lpfc_sli_stat slistat; /* SLI statistical info */ struct list_head mboxq; diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index ac417908b40..a61ef3d1e7f 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.1.10" +#define LPFC_DRIVER_VERSION "8.1.11" #define LPFC_DRIVER_NAME "lpfc" diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 86099fde1b2..77d9d3804cc 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -73,10 +73,10 @@ static unsigned short int max_mbox_busy_wait = MBOX_BUSY_WAIT; module_param(max_mbox_busy_wait, ushort, 0); MODULE_PARM_DESC(max_mbox_busy_wait, "Maximum wait for mailbox in microseconds if busy (default=MBOX_BUSY_WAIT=10)"); -#define RDINDOOR(adapter) readl((adapter)->base + 0x20) -#define RDOUTDOOR(adapter) readl((adapter)->base + 0x2C) -#define WRINDOOR(adapter,value) writel(value, (adapter)->base + 0x20) -#define WROUTDOOR(adapter,value) writel(value, (adapter)->base + 0x2C) +#define RDINDOOR(adapter) readl((adapter)->mmio_base + 0x20) +#define RDOUTDOOR(adapter) readl((adapter)->mmio_base + 0x2C) +#define WRINDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x20) +#define WROUTDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x2C) /* * Global variables @@ -1386,7 +1386,8 @@ megaraid_isr_memmapped(int irq, void *devp) handled = 1; - while( RDINDOOR(adapter) & 0x02 ) cpu_relax(); + while( RDINDOOR(adapter) & 0x02 ) + cpu_relax(); mega_cmd_done(adapter, completed, nstatus, status); @@ -4668,6 +4669,8 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->host_no, mega_baseport, irq); adapter->base = mega_baseport; + if (flag & BOARD_MEMMAP) + adapter->mmio_base = (void __iomem *) mega_baseport; INIT_LIST_HEAD(&adapter->free_list); INIT_LIST_HEAD(&adapter->pending_list); diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index 66529f11d23..c6e74643abe 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -801,7 +801,8 @@ typedef struct { clustering is available */ u32 flag; - unsigned long base; + unsigned long base; + void __iomem *mmio_base; /* mbox64 with mbox not aligned on 16-byte boundry */ mbox64_t *una_mbox64; diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 7e4262f2af9..046223b4ae5 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -517,7 +517,7 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp, * Returns the number of frames required for numnber of sge's (sge_count) */ -u32 megasas_get_frame_count(u8 sge_count) +static u32 megasas_get_frame_count(u8 sge_count) { int num_cnt; int sge_bytes; @@ -1733,7 +1733,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance, * * Tasklet to complete cmds */ -void megasas_complete_cmd_dpc(unsigned long instance_addr) +static void megasas_complete_cmd_dpc(unsigned long instance_addr) { u32 producer; u32 consumer; diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index adb8eb4f5fd..bbf521cbc55 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -589,10 +589,12 @@ static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd) static struct ncr_driver_setup driver_setup = SCSI_NCR_DRIVER_SETUP; +#ifndef MODULE #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT static struct ncr_driver_setup driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP; #endif +#endif /* !MODULE */ #define initverbose (driver_setup.verbose) #define bootverbose (np->verbose) @@ -641,6 +643,13 @@ static struct ncr_driver_setup #define OPT_IARB 26 #endif +#ifdef MODULE +#define ARG_SEP ' ' +#else +#define ARG_SEP ',' +#endif + +#ifndef MODULE static char setup_token[] __initdata = "tags:" "mpar:" "spar:" "disc:" @@ -660,12 +669,6 @@ static char setup_token[] __initdata = #endif ; /* DONNOT REMOVE THIS ';' */ -#ifdef MODULE -#define ARG_SEP ' ' -#else -#define ARG_SEP ',' -#endif - static int __init get_setup_token(char *p) { char *cur = setup_token; @@ -682,7 +685,6 @@ static int __init get_setup_token(char *p) return 0; } - static int __init sym53c8xx__setup(char *str) { #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT @@ -804,6 +806,7 @@ static int __init sym53c8xx__setup(char *str) #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */ return 1; } +#endif /* !MODULE */ /*=================================================================== ** @@ -8321,12 +8324,12 @@ char *ncr53c8xx; /* command line passed by insmod */ module_param(ncr53c8xx, charp, 0); #endif +#ifndef MODULE static int __init ncr53c8xx_setup(char *str) { return sym53c8xx__setup(str); } -#ifndef MODULE __setup("ncr53c8xx=", ncr53c8xx_setup); #endif diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c index dd67a68c5c2..c116a6ae3c5 100644 --- a/drivers/scsi/oktagon_esp.c +++ b/drivers/scsi/oktagon_esp.c @@ -72,12 +72,12 @@ static void dma_advance_sg(Scsi_Cmnd *); static int oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x); #ifdef USE_BOTTOM_HALF -static void dma_commit(void *opaque); +static void dma_commit(struct work_struct *unused); long oktag_to_io(long *paddr, long *addr, long len); long oktag_from_io(long *addr, long *paddr, long len); -static DECLARE_WORK(tq_fake_dma, dma_commit, NULL); +static DECLARE_WORK(tq_fake_dma, dma_commit); #define DMA_MAXTRANSFER 0x8000 @@ -266,7 +266,7 @@ oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x) */ -static void dma_commit(void *opaque) +static void dma_commit(struct work_struct *unused) { long wait,len2,pos; struct NCR_ESP *esp; diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index ee449b29fc8..aad362ba02e 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -154,16 +154,11 @@ static int aha152x_config_cs(struct pcmcia_device *link) DEBUG(0, "aha152x_config(0x%p)\n", link); - tuple.DesiredTuple = CISTPL_CONFIG; tuple.TupleData = tuple_data; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + tuple.Attributes = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { if (pcmcia_get_tuple_data(link, &tuple) != 0 || diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 85f7ffac19a..a1c5f265069 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -136,14 +136,9 @@ static int fdomain_config(struct pcmcia_device *link) DEBUG(0, "fdomain_config(0x%p)\n", link); - tuple.DesiredTuple = CISTPL_CONFIG; tuple.TupleData = tuple_data; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index f2d79c3f0b8..d72df5dae4e 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1685,16 +1685,10 @@ static int nsp_cs_config(struct pcmcia_device *link) nsp_dbg(NSP_DEBUG_INIT, "in"); - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = tuple_data; tuple.TupleDataMax = sizeof(tuple_data); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf)); diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 86c2ac6ae62..9d431fe7f47 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -208,18 +208,11 @@ static int qlogic_config(struct pcmcia_device * link) DEBUG(0, "qlogic_config(0x%p)\n", link); + info->manf_id = link->manf_id; + tuple.TupleData = (cisdata_t *) tuple_data; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - - tuple.DesiredTuple = CISTPL_MANFID; - if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS)) - info->manf_id = le16_to_cpu(tuple.TupleData[0]); tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 72fe5d055de..fb7acea6028 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -722,19 +722,11 @@ SYM53C500_config(struct pcmcia_device *link) DEBUG(0, "SYM53C500_config(0x%p)\n", link); + info->manf_id = link->manf_id; + tuple.TupleData = (cisdata_t *)tuple_data; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - - tuple.DesiredTuple = CISTPL_MANFID; - if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) && - (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS)) - info->manf_id = le16_to_cpu(tuple.TupleData[0]); tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 89a2a9f11e4..584ba4d6e03 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -31,7 +31,7 @@ typedef struct { int base; /* Actual port address */ int mode; /* Transfer mode */ struct scsi_cmnd *cur_cmd; /* Current queued command */ - struct work_struct ppa_tq; /* Polling interrupt stuff */ + struct delayed_work ppa_tq; /* Polling interrupt stuff */ unsigned long jstart; /* Jiffies at start */ unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */ unsigned int failed:1; /* Failure flag */ @@ -627,9 +627,9 @@ static int ppa_completion(struct scsi_cmnd *cmd) * the scheduler's task queue to generate a stream of call-backs and * complete the request when the drive is ready. */ -static void ppa_interrupt(void *data) +static void ppa_interrupt(struct work_struct *work) { - ppa_struct *dev = (ppa_struct *) data; + ppa_struct *dev = container_of(work, ppa_struct, ppa_tq.work); struct scsi_cmnd *cmd = dev->cur_cmd; if (!cmd) { @@ -637,7 +637,6 @@ static void ppa_interrupt(void *data) return; } if (ppa_engine(dev, cmd)) { - dev->ppa_tq.data = (void *) dev; schedule_delayed_work(&dev->ppa_tq, 1); return; } @@ -822,8 +821,7 @@ static int ppa_queuecommand(struct scsi_cmnd *cmd, cmd->result = DID_ERROR << 16; /* default return code */ cmd->SCp.phase = 0; /* bus free */ - dev->ppa_tq.data = dev; - schedule_work(&dev->ppa_tq); + schedule_delayed_work(&dev->ppa_tq, 0); ppa_pb_claim(dev); @@ -1086,7 +1084,7 @@ static int __ppa_attach(struct parport *pb) else ports = 8; - INIT_WORK(&dev->ppa_tq, ppa_interrupt, dev); + INIT_DELAYED_WORK(&dev->ppa_tq, ppa_interrupt); err = -ENOMEM; host = scsi_host_alloc(&ppa_template, sizeof(ppa_struct *)); diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 285c8e8ff1a..7b18a6c7b7e 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -390,7 +390,7 @@ static struct sysfs_entry { { "optrom_ctl", &sysfs_optrom_ctl_attr, }, { "vpd", &sysfs_vpd_attr, 1 }, { "sfp", &sysfs_sfp_attr, 1 }, - { 0 }, + { NULL }, }; void diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 08cb5e3fb55..a823f0bc519 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -59,9 +59,6 @@ int qla2x00_initialize_adapter(scsi_qla_host_t *ha) { int rval; - uint8_t restart_risc = 0; - uint8_t retry; - uint32_t wait_time; /* Clear adapter flags. */ ha->flags.online = 0; @@ -104,87 +101,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n"); - retry = 10; - /* - * Try to configure the loop. - */ - do { - restart_risc = 0; - - /* If firmware needs to be loaded */ - if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) { - if ((rval = ha->isp_ops.chip_diag(ha)) == QLA_SUCCESS) { - rval = qla2x00_setup_chip(ha); - } - } - - if (rval == QLA_SUCCESS && - (rval = qla2x00_init_rings(ha)) == QLA_SUCCESS) { -check_fw_ready_again: - /* - * Wait for a successful LIP up to a maximum - * of (in seconds): RISC login timeout value, - * RISC retry count value, and port down retry - * value OR a minimum of 4 seconds OR If no - * cable, only 5 seconds. - */ - rval = qla2x00_fw_ready(ha); - if (rval == QLA_SUCCESS) { - clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); - - /* Issue a marker after FW becomes ready. */ - qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); - - /* - * Wait at most MAX_TARGET RSCNs for a stable - * link. - */ - wait_time = 256; - do { - clear_bit(LOOP_RESYNC_NEEDED, - &ha->dpc_flags); - rval = qla2x00_configure_loop(ha); - - if (test_and_clear_bit(ISP_ABORT_NEEDED, - &ha->dpc_flags)) { - restart_risc = 1; - break; - } - - /* - * If loop state change while we were - * discoverying devices then wait for - * LIP to complete - */ - - if (atomic_read(&ha->loop_state) != - LOOP_READY && retry--) { - goto check_fw_ready_again; - } - wait_time--; - } while (!atomic_read(&ha->loop_down_timer) && - retry && - wait_time && - (test_bit(LOOP_RESYNC_NEEDED, - &ha->dpc_flags))); - - if (wait_time == 0) - rval = QLA_FUNCTION_FAILED; - } else if (ha->device_flags & DFLG_NO_CABLE) - /* If no cable, then all is good. */ - rval = QLA_SUCCESS; - } - } while (restart_risc && retry--); - - if (rval == QLA_SUCCESS) { - clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); - qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); - ha->marker_needed = 0; - - ha->flags.online = 1; - } else { - DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); + if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) { + rval = ha->isp_ops.chip_diag(ha); + if (rval) + return (rval); + rval = qla2x00_setup_chip(ha); + if (rval) + return (rval); } + rval = qla2x00_init_rings(ha); return (rval); } @@ -2208,8 +2133,7 @@ qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) atomic_set(&fcport->state, FCS_ONLINE); - if (ha->flags.init_done) - qla2x00_reg_remote_port(ha, fcport); + qla2x00_reg_remote_port(ha, fcport); } void diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 208607be78c..cbe0cad83b6 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -95,6 +95,8 @@ MODULE_PARM_DESC(ql2xqfullrampup, */ static int qla2xxx_slave_configure(struct scsi_device * device); static int qla2xxx_slave_alloc(struct scsi_device *); +static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time); +static void qla2xxx_scan_start(struct Scsi_Host *); static void qla2xxx_slave_destroy(struct scsi_device *); static int qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)); @@ -124,6 +126,8 @@ static struct scsi_host_template qla2x00_driver_template = { .slave_alloc = qla2xxx_slave_alloc, .slave_destroy = qla2xxx_slave_destroy, + .scan_finished = qla2xxx_scan_finished, + .scan_start = qla2xxx_scan_start, .change_queue_depth = qla2x00_change_queue_depth, .change_queue_type = qla2x00_change_queue_type, .this_id = -1, @@ -287,7 +291,7 @@ qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str) return str; } -char * +static char * qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str) { char un_str[10]; @@ -325,7 +329,7 @@ qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str) return (str); } -char * +static char * qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str) { sprintf(str, "%d.%02d.%02d ", ha->fw_major_version, @@ -634,7 +638,7 @@ qla2x00_block_error_handler(struct scsi_cmnd *cmnd) * Note: * Only return FAILED if command not returned by firmware. **************************************************************************/ -int +static int qla2xxx_eh_abort(struct scsi_cmnd *cmd) { scsi_qla_host_t *ha = to_qla_host(cmd->device->host); @@ -771,7 +775,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t) * SUCCESS/FAILURE (defined as macro in scsi.h). * **************************************************************************/ -int +static int qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) { scsi_qla_host_t *ha = to_qla_host(cmd->device->host); @@ -902,7 +906,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha) * SUCCESS/FAILURE (defined as macro in scsi.h). * **************************************************************************/ -int +static int qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) { scsi_qla_host_t *ha = to_qla_host(cmd->device->host); @@ -963,7 +967,7 @@ eh_bus_reset_done: * * Note: **************************************************************************/ -int +static int qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) { scsi_qla_host_t *ha = to_qla_host(cmd->device->host); @@ -1366,6 +1370,29 @@ qla24xx_disable_intrs(scsi_qla_host_t *ha) spin_unlock_irqrestore(&ha->hardware_lock, flags); } +static void +qla2xxx_scan_start(struct Scsi_Host *shost) +{ + scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata; + + set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); + set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); + set_bit(RSCN_UPDATE, &ha->dpc_flags); +} + +static int +qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time) +{ + scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata; + + if (!ha->host) + return 1; + if (time > ha->loop_reset_delay * HZ) + return 1; + + return atomic_read(&ha->loop_state) == LOOP_READY; +} + /* * PCI driver interface */ @@ -1377,10 +1404,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) struct Scsi_Host *host; scsi_qla_host_t *ha; unsigned long flags = 0; - unsigned long wait_switch = 0; char pci_info[20]; char fw_str[30]; - fc_port_t *fcport; struct scsi_host_template *sht; if (pci_enable_device(pdev)) @@ -1631,30 +1656,19 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->isp_ops.enable_intrs(ha); - /* v2.19.5b6 */ - /* - * Wait around max loop_reset_delay secs for the devices to come - * on-line. We don't want Linux scanning before we are ready. - * - */ - for (wait_switch = jiffies + (ha->loop_reset_delay * HZ); - time_before(jiffies,wait_switch) && - !(ha->device_flags & (DFLG_NO_CABLE | DFLG_FABRIC_DEVICES)) - && (ha->device_flags & SWITCH_FOUND) ;) { - - qla2x00_check_fabric_devices(ha); - - msleep(10); - } - pci_set_drvdata(pdev, ha); + ha->flags.init_done = 1; + ha->flags.online = 1; + num_hosts++; ret = scsi_add_host(host, &pdev->dev); if (ret) goto probe_failed; + scsi_scan_host(host); + qla2x00_alloc_sysfs_attr(ha); qla2x00_init_host_attr(ha); @@ -1669,10 +1683,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no, ha->isp_ops.fw_version_str(ha, fw_str)); - /* Go with fc_rport registration. */ - list_for_each_entry(fcport, &ha->fcports, list) - qla2x00_reg_remote_port(ha, fcport); - return 0; probe_failed: diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index c71dbd5bd54..15390ad8745 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -449,7 +449,7 @@ nvram_data_to_access_addr(uint32_t naddr) return FARX_ACCESS_NVRAM_DATA | naddr; } -uint32_t +static uint32_t qla24xx_read_flash_dword(scsi_qla_host_t *ha, uint32_t addr) { int rval; @@ -490,7 +490,7 @@ qla24xx_read_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, return dwptr; } -int +static int qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data) { int rval; @@ -512,7 +512,7 @@ qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data) return rval; } -void +static void qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, uint8_t *flash_id) { @@ -537,7 +537,7 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, } } -int +static int qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) { diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c index 752031fadfe..7b4e077a39c 100644 --- a/drivers/scsi/qla4xxx/ql4_dbg.c +++ b/drivers/scsi/qla4xxx/ql4_dbg.c @@ -71,7 +71,7 @@ void __dump_registers(struct scsi_qla_host *ha) readw(&ha->reg->u1.isp4010.nvram)); } - else if (is_qla4022(ha)) { + else if (is_qla4022(ha) | is_qla4032(ha)) { printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n", (uint8_t) offsetof(struct isp_reg, u1.isp4022.intr_mask), @@ -119,7 +119,7 @@ void __dump_registers(struct scsi_qla_host *ha) readw(&ha->reg->u2.isp4010.port_err_status)); } - else if (is_qla4022(ha)) { + else if (is_qla4022(ha) | is_qla4032(ha)) { printk(KERN_INFO "Page 0 Registers:\n"); printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n", (uint8_t) offsetof(struct isp_reg, diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index a7f6c7b1c59..4249e52a559 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -40,7 +40,11 @@ #ifndef PCI_DEVICE_ID_QLOGIC_ISP4022 #define PCI_DEVICE_ID_QLOGIC_ISP4022 0x4022 -#endif /* */ +#endif + +#ifndef PCI_DEVICE_ID_QLOGIC_ISP4032 +#define PCI_DEVICE_ID_QLOGIC_ISP4032 0x4032 +#endif #define QLA_SUCCESS 0 #define QLA_ERROR 1 @@ -277,7 +281,6 @@ struct scsi_qla_host { #define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */ #define AF_GET_CRASH_RECORD 7 /* 0x00000080 */ #define AF_LINK_UP 8 /* 0x00000100 */ -#define AF_TOPCAT_CHIP_PRESENT 9 /* 0x00000200 */ #define AF_IRQ_ATTACHED 10 /* 0x00000400 */ #define AF_ISNS_CMD_IN_PROCESS 12 /* 0x00001000 */ #define AF_ISNS_CMD_DONE 13 /* 0x00002000 */ @@ -317,16 +320,17 @@ struct scsi_qla_host { /* NVRAM registers */ struct eeprom_data *nvram; spinlock_t hardware_lock ____cacheline_aligned; - spinlock_t list_lock; uint32_t eeprom_cmd_data; /* Counters for general statistics */ + uint64_t isr_count; uint64_t adapter_error_count; uint64_t device_error_count; uint64_t total_io_count; uint64_t total_mbytes_xferred; uint64_t link_failure_count; uint64_t invalid_crc_count; + uint32_t bytes_xfered; uint32_t spurious_int_count; uint32_t aborted_io_count; uint32_t io_timeout_count; @@ -438,6 +442,11 @@ static inline int is_qla4022(struct scsi_qla_host *ha) return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4022; } +static inline int is_qla4032(struct scsi_qla_host *ha) +{ + return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4032; +} + static inline int adapter_up(struct scsi_qla_host *ha) { return (test_bit(AF_ONLINE, &ha->flags) != 0) && @@ -451,58 +460,58 @@ static inline struct scsi_qla_host* to_qla_host(struct Scsi_Host *shost) static inline void __iomem* isp_semaphore(struct scsi_qla_host *ha) { - return (is_qla4022(ha) ? - &ha->reg->u1.isp4022.semaphore : - &ha->reg->u1.isp4010.nvram); + return (is_qla4010(ha) ? + &ha->reg->u1.isp4010.nvram : + &ha->reg->u1.isp4022.semaphore); } static inline void __iomem* isp_nvram(struct scsi_qla_host *ha) { - return (is_qla4022(ha) ? - &ha->reg->u1.isp4022.nvram : - &ha->reg->u1.isp4010.nvram); + return (is_qla4010(ha) ? + &ha->reg->u1.isp4010.nvram : + &ha->reg->u1.isp4022.nvram); } static inline void __iomem* isp_ext_hw_conf(struct scsi_qla_host *ha) { - return (is_qla4022(ha) ? - &ha->reg->u2.isp4022.p0.ext_hw_conf : - &ha->reg->u2.isp4010.ext_hw_conf); + return (is_qla4010(ha) ? + &ha->reg->u2.isp4010.ext_hw_conf : + &ha->reg->u2.isp4022.p0.ext_hw_conf); } static inline void __iomem* isp_port_status(struct scsi_qla_host *ha) { - return (is_qla4022(ha) ? - &ha->reg->u2.isp4022.p0.port_status : - &ha->reg->u2.isp4010.port_status); + return (is_qla4010(ha) ? + &ha->reg->u2.isp4010.port_status : + &ha->reg->u2.isp4022.p0.port_status); } static inline void __iomem* isp_port_ctrl(struct scsi_qla_host *ha) { - return (is_qla4022(ha) ? - &ha->reg->u2.isp4022.p0.port_ctrl : - &ha->reg->u2.isp4010.port_ctrl); + return (is_qla4010(ha) ? + &ha->reg->u2.isp4010.port_ctrl : + &ha->reg->u2.isp4022.p0.port_ctrl); } static inline void __iomem* isp_port_error_status(struct scsi_qla_host *ha) { - return (is_qla4022(ha) ? - &ha->reg->u2.isp4022.p0.port_err_status : - &ha->reg->u2.isp4010.port_err_status); + return (is_qla4010(ha) ? + &ha->reg->u2.isp4010.port_err_status : + &ha->reg->u2.isp4022.p0.port_err_status); } static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha) { - return (is_qla4022(ha) ? - &ha->reg->u2.isp4022.p0.gp_out : - &ha->reg->u2.isp4010.gp_out); + return (is_qla4010(ha) ? + &ha->reg->u2.isp4010.gp_out : + &ha->reg->u2.isp4022.p0.gp_out); } static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha) { - return (is_qla4022(ha) ? - offsetof(struct eeprom_data, isp4022.ext_hw_conf) / 2 : - offsetof(struct eeprom_data, isp4010.ext_hw_conf) / 2); + return (is_qla4010(ha) ? + offsetof(struct eeprom_data, isp4010.ext_hw_conf) / 2 : + offsetof(struct eeprom_data, isp4022.ext_hw_conf) / 2); } int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits); @@ -511,59 +520,59 @@ int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits); static inline int ql4xxx_lock_flash(struct scsi_qla_host *a) { - if (is_qla4022(a)) + if (is_qla4010(a)) + return ql4xxx_sem_spinlock(a, QL4010_FLASH_SEM_MASK, + QL4010_FLASH_SEM_BITS); + else return ql4xxx_sem_spinlock(a, QL4022_FLASH_SEM_MASK, (QL4022_RESOURCE_BITS_BASE_CODE | (a->mac_index)) << 13); - else - return ql4xxx_sem_spinlock(a, QL4010_FLASH_SEM_MASK, - QL4010_FLASH_SEM_BITS); } static inline void ql4xxx_unlock_flash(struct scsi_qla_host *a) { - if (is_qla4022(a)) - ql4xxx_sem_unlock(a, QL4022_FLASH_SEM_MASK); - else + if (is_qla4010(a)) ql4xxx_sem_unlock(a, QL4010_FLASH_SEM_MASK); + else + ql4xxx_sem_unlock(a, QL4022_FLASH_SEM_MASK); } static inline int ql4xxx_lock_nvram(struct scsi_qla_host *a) { - if (is_qla4022(a)) + if (is_qla4010(a)) + return ql4xxx_sem_spinlock(a, QL4010_NVRAM_SEM_MASK, + QL4010_NVRAM_SEM_BITS); + else return ql4xxx_sem_spinlock(a, QL4022_NVRAM_SEM_MASK, (QL4022_RESOURCE_BITS_BASE_CODE | (a->mac_index)) << 10); - else - return ql4xxx_sem_spinlock(a, QL4010_NVRAM_SEM_MASK, - QL4010_NVRAM_SEM_BITS); } static inline void ql4xxx_unlock_nvram(struct scsi_qla_host *a) { - if (is_qla4022(a)) - ql4xxx_sem_unlock(a, QL4022_NVRAM_SEM_MASK); - else + if (is_qla4010(a)) ql4xxx_sem_unlock(a, QL4010_NVRAM_SEM_MASK); + else + ql4xxx_sem_unlock(a, QL4022_NVRAM_SEM_MASK); } static inline int ql4xxx_lock_drvr(struct scsi_qla_host *a) { - if (is_qla4022(a)) + if (is_qla4010(a)) + return ql4xxx_sem_lock(a, QL4010_DRVR_SEM_MASK, + QL4010_DRVR_SEM_BITS); + else return ql4xxx_sem_lock(a, QL4022_DRVR_SEM_MASK, (QL4022_RESOURCE_BITS_BASE_CODE | (a->mac_index)) << 1); - else - return ql4xxx_sem_lock(a, QL4010_DRVR_SEM_MASK, - QL4010_DRVR_SEM_BITS); } static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a) { - if (is_qla4022(a)) - ql4xxx_sem_unlock(a, QL4022_DRVR_SEM_MASK); - else + if (is_qla4010(a)) ql4xxx_sem_unlock(a, QL4010_DRVR_SEM_MASK); + else + ql4xxx_sem_unlock(a, QL4022_DRVR_SEM_MASK); } /*---------------------------------------------------------------------------*/ diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 427489de64b..4eea8c57191 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -296,7 +296,6 @@ static inline uint32_t clr_rmask(uint32_t val) /* ISP Semaphore definitions */ /* ISP General Purpose Output definitions */ -#define GPOR_TOPCAT_RESET 0x00000004 /* shadow registers (DMA'd from HA to system memory. read only) */ struct shadow_regs { @@ -339,10 +338,13 @@ union external_hw_config_reg { /* Mailbox command definitions */ #define MBOX_CMD_ABOUT_FW 0x0009 #define MBOX_CMD_LUN_RESET 0x0016 +#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E #define MBOX_CMD_GET_FW_STATUS 0x001F #define MBOX_CMD_SET_ISNS_SERVICE 0x0021 #define ISNS_DISABLE 0 #define ISNS_ENABLE 1 +#define MBOX_CMD_COPY_FLASH 0x0024 +#define MBOX_CMD_WRITE_FLASH 0x0025 #define MBOX_CMD_READ_FLASH 0x0026 #define MBOX_CMD_CLEAR_DATABASE_ENTRY 0x0031 #define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT 0x0056 @@ -360,10 +362,13 @@ union external_hw_config_reg { #define DDB_DS_SESSION_FAILED 0x06 #define DDB_DS_LOGIN_IN_PROCESS 0x07 #define MBOX_CMD_GET_FW_STATE 0x0069 +#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A +#define MBOX_CMD_RESTORE_FACTORY_DEFAULTS 0x0087 /* Mailbox 1 */ #define FW_STATE_READY 0x0000 #define FW_STATE_CONFIG_WAIT 0x0001 +#define FW_STATE_WAIT_LOGIN 0x0002 #define FW_STATE_ERROR 0x0004 #define FW_STATE_DHCP_IN_PROGRESS 0x0008 diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 1b221ff0f6f..2122967bbf0 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -8,6 +8,7 @@ #ifndef __QLA4x_GBL_H #define __QLA4x_GBL_H +int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a); int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port); int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb); int qla4xxx_initialize_adapter(struct scsi_qla_host * ha, @@ -75,4 +76,4 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha, extern int ql4xextended_error_logging; extern int ql4xdiscoverywait; extern int ql4xdontresethba; -#endif /* _QLA4x_GBL_H */ +#endif /* _QLA4x_GBL_H */ diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index bb3a1c11f44..cc210f297a7 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -259,10 +259,16 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) "seconds expired= %d\n", ha->host_no, __func__, ha->firmware_state, ha->addl_fw_state, timeout_count)); + if (is_qla4032(ha) && + !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) && + (timeout_count < ADAPTER_INIT_TOV - 5)) { + break; + } + msleep(1000); } /* end of for */ - if (timeout_count <= 0) + if (timeout_count == 0) DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n", ha->host_no, __func__)); @@ -806,32 +812,6 @@ int qla4xxx_relogin_device(struct scsi_qla_host *ha, return QLA_SUCCESS; } -/** - * qla4010_get_topcat_presence - check if it is QLA4040 TopCat Chip - * @ha: Pointer to host adapter structure. - * - **/ -static int qla4010_get_topcat_presence(struct scsi_qla_host *ha) -{ - unsigned long flags; - uint16_t topcat; - - if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS) - return QLA_ERROR; - spin_lock_irqsave(&ha->hardware_lock, flags); - topcat = rd_nvram_word(ha, offsetof(struct eeprom_data, - isp4010.topcat)); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if ((topcat & TOPCAT_MASK) == TOPCAT_PRESENT) - set_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags); - else - clear_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags); - ql4xxx_unlock_nvram(ha); - return QLA_SUCCESS; -} - - static int qla4xxx_config_nvram(struct scsi_qla_host *ha) { unsigned long flags; @@ -866,7 +846,7 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha) /* set defaults */ if (is_qla4010(ha)) extHwConfig.Asuint32_t = 0x1912; - else if (is_qla4022(ha)) + else if (is_qla4022(ha) | is_qla4032(ha)) extHwConfig.Asuint32_t = 0x0023; } DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n", @@ -927,7 +907,7 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) spin_lock_irqsave(&ha->hardware_lock, flags); writel(jiffies, &ha->reg->mailbox[7]); - if (is_qla4022(ha)) + if (is_qla4022(ha) | is_qla4032(ha)) writel(set_rmask(NVR_WRITE_ENABLE), &ha->reg->u1.isp4022.nvram); @@ -978,7 +958,7 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) return status; } -static int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) +int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) { #define QL4_LOCK_DRVR_WAIT 300 #define QL4_LOCK_DRVR_SLEEP 100 @@ -1018,12 +998,7 @@ static int qla4xxx_start_firmware(struct scsi_qla_host *ha) int soft_reset = 1; int config_chip = 0; - if (is_qla4010(ha)){ - if (qla4010_get_topcat_presence(ha) != QLA_SUCCESS) - return QLA_ERROR; - } - - if (is_qla4022(ha)) + if (is_qla4022(ha) | is_qla4032(ha)) ql4xxx_set_mac_number(ha); if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h index 0d61797af7d..6375eb017dd 100644 --- a/drivers/scsi/qla4xxx/ql4_inline.h +++ b/drivers/scsi/qla4xxx/ql4_inline.h @@ -38,7 +38,7 @@ qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index) static inline void __qla4xxx_enable_intrs(struct scsi_qla_host *ha) { - if (is_qla4022(ha)) { + if (is_qla4022(ha) | is_qla4032(ha)) { writel(set_rmask(IMR_SCSI_INTR_ENABLE), &ha->reg->u1.isp4022.intr_mask); readl(&ha->reg->u1.isp4022.intr_mask); @@ -52,7 +52,7 @@ __qla4xxx_enable_intrs(struct scsi_qla_host *ha) static inline void __qla4xxx_disable_intrs(struct scsi_qla_host *ha) { - if (is_qla4022(ha)) { + if (is_qla4022(ha) | is_qla4032(ha)) { writel(clr_rmask(IMR_SCSI_INTR_ENABLE), &ha->reg->u1.isp4022.intr_mask); readl(&ha->reg->u1.isp4022.intr_mask); diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index c0a254b89a3..d41ce380eed 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c @@ -294,6 +294,12 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) cmd_entry->control_flags = CF_WRITE; else if (cmd->sc_data_direction == DMA_FROM_DEVICE) cmd_entry->control_flags = CF_READ; + + ha->bytes_xfered += cmd->request_bufflen; + if (ha->bytes_xfered & ~0xFFFFF){ + ha->total_mbytes_xferred += ha->bytes_xfered >> 20; + ha->bytes_xfered &= 0xFFFFF; + } } /* Set tagged queueing control flags */ diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 1e283321a59..ef975e0dc87 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -627,6 +627,7 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) spin_lock_irqsave(&ha->hardware_lock, flags); + ha->isr_count++; /* * Repeatedly service interrupts up to a maximum of * MAX_REQS_SERVICED_PER_INTR diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c index e3957ca5b64..58afd135aa1 100644 --- a/drivers/scsi/qla4xxx/ql4_nvram.c +++ b/drivers/scsi/qla4xxx/ql4_nvram.c @@ -7,15 +7,22 @@ #include "ql4_def.h" +static inline void eeprom_cmd(uint32_t cmd, struct scsi_qla_host *ha) +{ + writel(cmd, isp_nvram(ha)); + readl(isp_nvram(ha)); + udelay(1); +} + static inline int eeprom_size(struct scsi_qla_host *ha) { - return is_qla4022(ha) ? FM93C86A_SIZE_16 : FM93C66A_SIZE_16; + return is_qla4010(ha) ? FM93C66A_SIZE_16 : FM93C86A_SIZE_16; } static inline int eeprom_no_addr_bits(struct scsi_qla_host *ha) { - return is_qla4022(ha) ? FM93C86A_NO_ADDR_BITS_16 : - FM93C56A_NO_ADDR_BITS_16; + return is_qla4010(ha) ? FM93C56A_NO_ADDR_BITS_16 : + FM93C86A_NO_ADDR_BITS_16 ; } static inline int eeprom_no_data_bits(struct scsi_qla_host *ha) @@ -28,8 +35,7 @@ static int fm93c56a_select(struct scsi_qla_host * ha) DEBUG5(printk(KERN_ERR "fm93c56a_select:\n")); ha->eeprom_cmd_data = AUBURN_EEPROM_CS_1 | 0x000f0000; - writel(ha->eeprom_cmd_data, isp_nvram(ha)); - readl(isp_nvram(ha)); + eeprom_cmd(ha->eeprom_cmd_data, ha); return 1; } @@ -41,12 +47,13 @@ static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr) int previousBit; /* Clock in a zero, then do the start bit. */ - writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1, isp_nvram(ha)); - writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 | - AUBURN_EEPROM_CLK_RISE, isp_nvram(ha)); - writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 | - AUBURN_EEPROM_CLK_FALL, isp_nvram(ha)); - readl(isp_nvram(ha)); + eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1, ha); + + eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 | + AUBURN_EEPROM_CLK_RISE, ha); + eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 | + AUBURN_EEPROM_CLK_FALL, ha); + mask = 1 << (FM93C56A_CMD_BITS - 1); /* Force the previous data bit to be different. */ @@ -60,14 +67,14 @@ static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr) * If the bit changed, then change the DO state to * match. */ - writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha)); + eeprom_cmd(ha->eeprom_cmd_data | dataBit, ha); previousBit = dataBit; } - writel(ha->eeprom_cmd_data | dataBit | - AUBURN_EEPROM_CLK_RISE, isp_nvram(ha)); - writel(ha->eeprom_cmd_data | dataBit | - AUBURN_EEPROM_CLK_FALL, isp_nvram(ha)); - readl(isp_nvram(ha)); + eeprom_cmd(ha->eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_RISE, ha); + eeprom_cmd(ha->eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_FALL, ha); + cmd = cmd << 1; } mask = 1 << (eeprom_no_addr_bits(ha) - 1); @@ -82,14 +89,15 @@ static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr) * If the bit changed, then change the DO state to * match. */ - writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha)); + eeprom_cmd(ha->eeprom_cmd_data | dataBit, ha); + previousBit = dataBit; } - writel(ha->eeprom_cmd_data | dataBit | - AUBURN_EEPROM_CLK_RISE, isp_nvram(ha)); - writel(ha->eeprom_cmd_data | dataBit | - AUBURN_EEPROM_CLK_FALL, isp_nvram(ha)); - readl(isp_nvram(ha)); + eeprom_cmd(ha->eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_RISE, ha); + eeprom_cmd(ha->eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_FALL, ha); + addr = addr << 1; } return 1; @@ -98,8 +106,7 @@ static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr) static int fm93c56a_deselect(struct scsi_qla_host * ha) { ha->eeprom_cmd_data = AUBURN_EEPROM_CS_0 | 0x000f0000; - writel(ha->eeprom_cmd_data, isp_nvram(ha)); - readl(isp_nvram(ha)); + eeprom_cmd(ha->eeprom_cmd_data, ha); return 1; } @@ -112,12 +119,13 @@ static int fm93c56a_datain(struct scsi_qla_host * ha, unsigned short *value) /* Read the data bits * The first bit is a dummy. Clock right over it. */ for (i = 0; i < eeprom_no_data_bits(ha); i++) { - writel(ha->eeprom_cmd_data | - AUBURN_EEPROM_CLK_RISE, isp_nvram(ha)); - writel(ha->eeprom_cmd_data | - AUBURN_EEPROM_CLK_FALL, isp_nvram(ha)); - dataBit = - (readw(isp_nvram(ha)) & AUBURN_EEPROM_DI_1) ? 1 : 0; + eeprom_cmd(ha->eeprom_cmd_data | + AUBURN_EEPROM_CLK_RISE, ha); + eeprom_cmd(ha->eeprom_cmd_data | + AUBURN_EEPROM_CLK_FALL, ha); + + dataBit = (readw(isp_nvram(ha)) & AUBURN_EEPROM_DI_1) ? 1 : 0; + data = (data << 1) | dataBit; } diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h index 08e2aed8c6c..b47b4fc59d8 100644 --- a/drivers/scsi/qla4xxx/ql4_nvram.h +++ b/drivers/scsi/qla4xxx/ql4_nvram.h @@ -134,9 +134,7 @@ struct eeprom_data { u16 phyConfig; /* x36 */ #define PHY_CONFIG_PHY_ADDR_MASK 0x1f #define PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20 - u16 topcat; /* x38 */ -#define TOPCAT_PRESENT 0x0100 -#define TOPCAT_MASK 0xFF00 + u16 reserved_56; /* x38 */ #define EEPROM_UNUSED_1_SIZE 2 u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */ diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 5b8db610953..969c9e43102 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -708,10 +708,10 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) } /** - * qla4010_soft_reset - performs soft reset. + * qla4xxx_soft_reset - performs soft reset. * @ha: Pointer to host adapter structure. **/ -static int qla4010_soft_reset(struct scsi_qla_host *ha) +int qla4xxx_soft_reset(struct scsi_qla_host *ha) { uint32_t max_wait_time; unsigned long flags = 0; @@ -817,29 +817,6 @@ static int qla4010_soft_reset(struct scsi_qla_host *ha) } /** - * qla4xxx_topcat_reset - performs hard reset of TopCat Chip. - * @ha: Pointer to host adapter structure. - **/ -static int qla4xxx_topcat_reset(struct scsi_qla_host *ha) -{ - unsigned long flags; - - ql4xxx_lock_nvram(ha); - spin_lock_irqsave(&ha->hardware_lock, flags); - writel(set_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha)); - readl(isp_gp_out(ha)); - mdelay(1); - - writel(clr_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha)); - readl(isp_gp_out(ha)); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - mdelay(2523); - - ql4xxx_unlock_nvram(ha); - return QLA_SUCCESS; -} - -/** * qla4xxx_flush_active_srbs - returns all outstanding i/o requests to O.S. * @ha: Pointer to host adapter structure. * @@ -867,26 +844,6 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) } /** - * qla4xxx_hard_reset - performs HBA Hard Reset - * @ha: Pointer to host adapter structure. - **/ -static int qla4xxx_hard_reset(struct scsi_qla_host *ha) -{ - /* The QLA4010 really doesn't have an equivalent to a hard reset */ - qla4xxx_flush_active_srbs(ha); - if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) { - int status = QLA_ERROR; - - if ((qla4010_soft_reset(ha) == QLA_SUCCESS) && - (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) && - (qla4010_soft_reset(ha) == QLA_SUCCESS)) - status = QLA_SUCCESS; - return status; - } else - return qla4010_soft_reset(ha); -} - -/** * qla4xxx_recover_adapter - recovers adapter after a fatal error * @ha: Pointer to host adapter structure. * @renew_ddb_list: Indicates what to do with the adapter's ddb list @@ -919,18 +876,11 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, if (status == QLA_SUCCESS) { DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n", ha->host_no, __func__)); - status = qla4xxx_soft_reset(ha); - } - /* FIXMEkaren: Do we want to keep interrupts enabled and process - AENs after soft reset */ - - /* If firmware (SOFT) reset failed, or if all outstanding - * commands have not returned, then do a HARD reset. - */ - if (status == QLA_ERROR) { - DEBUG2(printk("scsi%ld: %s - Performing hard reset..\n", - ha->host_no, __func__)); - status = qla4xxx_hard_reset(ha); + qla4xxx_flush_active_srbs(ha); + if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) + status = qla4xxx_soft_reset(ha); + else + status = QLA_ERROR; } /* Flush any pending ddb changed AENs */ @@ -1011,18 +961,15 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, * the mid-level tries to sleep when it reaches the driver threshold * "host->can_queue". This can cause a panic if we were in our interrupt code. **/ -static void qla4xxx_do_dpc(void *data) +static void qla4xxx_do_dpc(struct work_struct *work) { - struct scsi_qla_host *ha = (struct scsi_qla_host *) data; + struct scsi_qla_host *ha = + container_of(work, struct scsi_qla_host, dpc_work); struct ddb_entry *ddb_entry, *dtemp; - DEBUG2(printk("scsi%ld: %s: DPC handler waking up.\n", - ha->host_no, __func__)); - - DEBUG2(printk("scsi%ld: %s: ha->flags = 0x%08lx\n", - ha->host_no, __func__, ha->flags)); - DEBUG2(printk("scsi%ld: %s: ha->dpc_flags = 0x%08lx\n", - ha->host_no, __func__, ha->dpc_flags)); + DEBUG2(printk("scsi%ld: %s: DPC handler waking up." + "flags = 0x%08lx, dpc_flags = 0x%08lx\n", + ha->host_no, __func__, ha->flags, ha->dpc_flags)); /* Initialization not yet finished. Don't do anything yet. */ if (!test_bit(AF_INIT_DONE, &ha->flags)) @@ -1032,16 +979,8 @@ static void qla4xxx_do_dpc(void *data) test_bit(DPC_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) { - if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) - /* - * dg 09/23 Never initialize ddb list - * once we up and running - * qla4xxx_recover_adapter(ha, - * REBUILD_DDB_LIST); - */ - qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); - - if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) + if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || + test_bit(DPC_RESET_HA, &ha->dpc_flags)) qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); if (test_and_clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { @@ -1122,7 +1061,8 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) destroy_workqueue(ha->dpc_thread); /* Issue Soft Reset to put firmware in unknown state */ - qla4xxx_soft_reset(ha); + if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) + qla4xxx_soft_reset(ha); /* Remove timer thread, if present */ if (ha->timer_active) @@ -1261,7 +1201,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, init_waitqueue_head(&ha->mailbox_wait_queue); spin_lock_init(&ha->hardware_lock); - spin_lock_init(&ha->list_lock); /* Allocate dma buffers */ if (qla4xxx_mem_alloc(ha)) { @@ -1315,7 +1254,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ret = -ENODEV; goto probe_failed; } - INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc, ha); + INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); ret = request_irq(pdev->irq, qla4xxx_intr_handler, SA_INTERRUPT|SA_SHIRQ, "qla4xxx", ha); @@ -1468,27 +1407,6 @@ struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t in } /** - * qla4xxx_soft_reset - performs a SOFT RESET of hba. - * @ha: Pointer to host adapter structure. - **/ -int qla4xxx_soft_reset(struct scsi_qla_host *ha) -{ - - DEBUG2(printk(KERN_WARNING "scsi%ld: %s: chip reset!\n", ha->host_no, - __func__)); - if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) { - int status = QLA_ERROR; - - if ((qla4010_soft_reset(ha) == QLA_SUCCESS) && - (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) && - (qla4010_soft_reset(ha) == QLA_SUCCESS) ) - status = QLA_SUCCESS; - return status; - } else - return qla4010_soft_reset(ha); -} - -/** * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware * @ha: actual ha whose done queue will contain the comd returned by firmware. * @cmd: Scsi Command to wait on. @@ -1686,6 +1604,12 @@ static struct pci_device_id qla4xxx_pci_tbl[] = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP4032, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, {0, 0}, }; MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index b3fe7e68988..454e19c8ad6 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,9 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.00.05b9-k" - -#define QL4_DRIVER_MAJOR_VER 5 -#define QL4_DRIVER_MINOR_VER 0 -#define QL4_DRIVER_PATCH_VER 5 -#define QL4_DRIVER_BETA_VER 9 +#define QLA4XXX_DRIVER_VERSION "5.00.07-k" diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index c59f31533ab..fafc00deaad 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -156,8 +156,7 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { static DEFINE_MUTEX(host_cmd_pool_mutex); -static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, - gfp_t gfp_mask) +struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) { struct scsi_cmnd *cmd; @@ -178,6 +177,7 @@ static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, return cmd; } +EXPORT_SYMBOL_GPL(__scsi_get_command); /* * Function: scsi_get_command() @@ -214,9 +214,29 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) put_device(&dev->sdev_gendev); return cmd; -} +} EXPORT_SYMBOL(scsi_get_command); +void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd, + struct device *dev) +{ + unsigned long flags; + + /* changing locks here, don't need to restore the irq state */ + spin_lock_irqsave(&shost->free_list_lock, flags); + if (unlikely(list_empty(&shost->free_list))) { + list_add(&cmd->list, &shost->free_list); + cmd = NULL; + } + spin_unlock_irqrestore(&shost->free_list_lock, flags); + + if (likely(cmd != NULL)) + kmem_cache_free(shost->cmd_pool->slab, cmd); + + put_device(dev); +} +EXPORT_SYMBOL(__scsi_put_command); + /* * Function: scsi_put_command() * @@ -231,26 +251,15 @@ EXPORT_SYMBOL(scsi_get_command); void scsi_put_command(struct scsi_cmnd *cmd) { struct scsi_device *sdev = cmd->device; - struct Scsi_Host *shost = sdev->host; unsigned long flags; - + /* serious error if the command hasn't come from a device list */ spin_lock_irqsave(&cmd->device->list_lock, flags); BUG_ON(list_empty(&cmd->list)); list_del_init(&cmd->list); - spin_unlock(&cmd->device->list_lock); - /* changing locks here, don't need to restore the irq state */ - spin_lock(&shost->free_list_lock); - if (unlikely(list_empty(&shost->free_list))) { - list_add(&cmd->list, &shost->free_list); - cmd = NULL; - } - spin_unlock_irqrestore(&shost->free_list_lock, flags); - - if (likely(cmd != NULL)) - kmem_cache_free(shost->cmd_pool->slab, cmd); + spin_unlock_irqrestore(&cmd->device->list_lock, flags); - put_device(&sdev->sdev_gendev); + __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev); } EXPORT_SYMBOL(scsi_put_command); @@ -871,9 +880,9 @@ EXPORT_SYMBOL(scsi_device_get); */ void scsi_device_put(struct scsi_device *sdev) { +#ifdef CONFIG_MODULE_UNLOAD struct module *module = sdev->host->hostt->module; -#ifdef CONFIG_MODULE_UNLOAD /* The module refcount will be zero if scsi_device_get() * was called from a module removal routine */ if (module && module_refcount(module) != 0) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index aff1b0cfd4b..2ecb6ff4244 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -453,9 +453,18 @@ static void scsi_eh_done(struct scsi_cmnd *scmd) } /** - * scsi_send_eh_cmnd - send a cmd to a device as part of error recovery. - * @scmd: SCSI Cmd to send. - * @timeout: Timeout for cmd. + * scsi_send_eh_cmnd - submit a scsi command as part of error recory + * @scmd: SCSI command structure to hijack + * @cmnd: CDB to send + * @cmnd_size: size in bytes of @cmnd + * @timeout: timeout for this request + * @copy_sense: request sense data if set to 1 + * + * This function is used to send a scsi command down to a target device + * as part of the error recovery process. If @copy_sense is 0 the command + * sent must be one that does not transfer any data. If @copy_sense is 1 + * the command must be REQUEST_SENSE and this functions copies out the + * sense buffer it got into @scmd->sense_buffer. * * Return value: * SUCCESS or FAILED or NEEDS_RETRY @@ -469,6 +478,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, DECLARE_COMPLETION_ONSTACK(done); unsigned long timeleft; unsigned long flags; + struct scatterlist sgl; unsigned char old_cmnd[MAX_COMMAND_SIZE]; enum dma_data_direction old_data_direction; unsigned short old_use_sg; @@ -500,19 +510,24 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, if (shost->hostt->unchecked_isa_dma) gfp_mask |= __GFP_DMA; - scmd->sc_data_direction = DMA_FROM_DEVICE; - scmd->request_bufflen = 252; - scmd->request_buffer = kzalloc(scmd->request_bufflen, gfp_mask); - if (!scmd->request_buffer) + sgl.page = alloc_page(gfp_mask); + if (!sgl.page) return FAILED; + sgl.offset = 0; + sgl.length = 252; + + scmd->sc_data_direction = DMA_FROM_DEVICE; + scmd->request_bufflen = sgl.length; + scmd->request_buffer = &sgl; + scmd->use_sg = 1; } else { scmd->request_buffer = NULL; scmd->request_bufflen = 0; scmd->sc_data_direction = DMA_NONE; + scmd->use_sg = 0; } scmd->underflow = 0; - scmd->use_sg = 0; scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); if (sdev->scsi_level <= SCSI_2) @@ -583,7 +598,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, memcpy(scmd->sense_buffer, scmd->request_buffer, sizeof(scmd->sense_buffer)); } - kfree(scmd->request_buffer); + __free_page(sgl.page); } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 3ac4890ce08..fb616c69151 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -704,7 +704,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, return NULL; } -static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask) +struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask) { struct scsi_host_sg_pool *sgp; struct scatterlist *sgl; @@ -745,7 +745,9 @@ static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_m return sgl; } -static void scsi_free_sgtable(struct scatterlist *sgl, int index) +EXPORT_SYMBOL(scsi_alloc_sgtable); + +void scsi_free_sgtable(struct scatterlist *sgl, int index) { struct scsi_host_sg_pool *sgp; @@ -755,6 +757,8 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index) mempool_free(sgl, sgp->pool); } +EXPORT_SYMBOL(scsi_free_sgtable); + /* * Function: scsi_release_buffers() * @@ -996,25 +1000,14 @@ static int scsi_init_io(struct scsi_cmnd *cmd) int count; /* - * if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer - */ - if (blk_pc_request(req) && !req->bio) { - cmd->request_bufflen = req->data_len; - cmd->request_buffer = req->data; - req->buffer = req->data; - cmd->use_sg = 0; - return 0; - } - - /* - * we used to not use scatter-gather for single segment request, + * We used to not use scatter-gather for single segment request, * but now we do (it makes highmem I/O easier to support without * kmapping pages) */ cmd->use_sg = req->nr_phys_segments; /* - * if sg table allocation fails, requeue request later. + * If sg table allocation fails, requeue request later. */ sgpnt = scsi_alloc_sgtable(cmd, GFP_ATOMIC); if (unlikely(!sgpnt)) { @@ -1022,24 +1015,21 @@ static int scsi_init_io(struct scsi_cmnd *cmd) return BLKPREP_DEFER; } + req->buffer = NULL; cmd->request_buffer = (char *) sgpnt; - cmd->request_bufflen = req->nr_sectors << 9; if (blk_pc_request(req)) cmd->request_bufflen = req->data_len; - req->buffer = NULL; + else + cmd->request_bufflen = req->nr_sectors << 9; /* * Next, walk the list, and fill in the addresses and sizes of * each segment. */ count = blk_rq_map_sg(req->q, req, cmd->request_buffer); - - /* - * mapped well, send it off - */ if (likely(count <= cmd->use_sg)) { cmd->use_sg = count; - return 0; + return BLKPREP_OK; } printk(KERN_ERR "Incorrect number of segments after building list\n"); @@ -1069,6 +1059,27 @@ static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, return -EOPNOTSUPP; } +static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev, + struct request *req) +{ + struct scsi_cmnd *cmd; + + if (!req->special) { + cmd = scsi_get_command(sdev, GFP_ATOMIC); + if (unlikely(!cmd)) + return NULL; + req->special = cmd; + } else { + cmd = req->special; + } + + /* pull a tag out of the request if we have one */ + cmd->tag = req->tag; + cmd->request = req; + + return cmd; +} + static void scsi_blk_pc_done(struct scsi_cmnd *cmd) { BUG_ON(!blk_pc_request(cmd->request)); @@ -1081,9 +1092,37 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd) scsi_io_completion(cmd, cmd->request_bufflen); } -static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd) +static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) { - struct request *req = cmd->request; + struct scsi_cmnd *cmd; + + cmd = scsi_get_cmd_from_req(sdev, req); + if (unlikely(!cmd)) + return BLKPREP_DEFER; + + /* + * BLOCK_PC requests may transfer data, in which case they must + * a bio attached to them. Or they might contain a SCSI command + * that does not transfer data, in which case they may optionally + * submit a request without an attached bio. + */ + if (req->bio) { + int ret; + + BUG_ON(!req->nr_phys_segments); + + ret = scsi_init_io(cmd); + if (unlikely(ret)) + return ret; + } else { + BUG_ON(req->data_len); + BUG_ON(req->data); + + cmd->request_bufflen = 0; + cmd->request_buffer = NULL; + cmd->use_sg = 0; + req->buffer = NULL; + } BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd)); memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd)); @@ -1099,154 +1138,138 @@ static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd) cmd->allowed = req->retries; cmd->timeout_per_command = req->timeout; cmd->done = scsi_blk_pc_done; + return BLKPREP_OK; } -static int scsi_prep_fn(struct request_queue *q, struct request *req) +/* + * Setup a REQ_TYPE_FS command. These are simple read/write request + * from filesystems that still need to be translated to SCSI CDBs from + * the ULD. + */ +static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) { - struct scsi_device *sdev = q->queuedata; struct scsi_cmnd *cmd; - int specials_only = 0; + struct scsi_driver *drv; + int ret; /* - * Just check to see if the device is online. If it isn't, we - * refuse to process any commands. The device must be brought - * online before trying any recovery commands + * Filesystem requests must transfer data. */ - if (unlikely(!scsi_device_online(sdev))) { - sdev_printk(KERN_ERR, sdev, - "rejecting I/O to offline device\n"); - goto kill; - } - if (unlikely(sdev->sdev_state != SDEV_RUNNING)) { - /* OK, we're not in a running state don't prep - * user commands */ - if (sdev->sdev_state == SDEV_DEL) { - /* Device is fully deleted, no commands - * at all allowed down */ - sdev_printk(KERN_ERR, sdev, - "rejecting I/O to dead device\n"); - goto kill; - } - /* OK, we only allow special commands (i.e. not - * user initiated ones */ - specials_only = sdev->sdev_state; + BUG_ON(!req->nr_phys_segments); + + cmd = scsi_get_cmd_from_req(sdev, req); + if (unlikely(!cmd)) + return BLKPREP_DEFER; + + ret = scsi_init_io(cmd); + if (unlikely(ret)) + return ret; + + /* + * Initialize the actual SCSI command for this request. + */ + drv = *(struct scsi_driver **)req->rq_disk->private_data; + if (unlikely(!drv->init_command(cmd))) { + scsi_release_buffers(cmd); + scsi_put_command(cmd); + return BLKPREP_KILL; } + return BLKPREP_OK; +} + +static int scsi_prep_fn(struct request_queue *q, struct request *req) +{ + struct scsi_device *sdev = q->queuedata; + int ret = BLKPREP_OK; + /* - * Find the actual device driver associated with this command. - * The SPECIAL requests are things like character device or - * ioctls, which did not originate from ll_rw_blk. Note that - * the special field is also used to indicate the cmd for - * the remainder of a partially fulfilled request that can - * come up when there is a medium error. We have to treat - * these two cases differently. We differentiate by looking - * at request->cmd, as this tells us the real story. + * If the device is not in running state we will reject some + * or all commands. */ - if (blk_special_request(req) && req->special) - cmd = req->special; - else if (blk_pc_request(req) || blk_fs_request(req)) { - if (unlikely(specials_only) && !(req->cmd_flags & REQ_PREEMPT)){ - if (specials_only == SDEV_QUIESCE || - specials_only == SDEV_BLOCK) - goto defer; - + if (unlikely(sdev->sdev_state != SDEV_RUNNING)) { + switch (sdev->sdev_state) { + case SDEV_OFFLINE: + /* + * If the device is offline we refuse to process any + * commands. The device must be brought online + * before trying any recovery commands. + */ sdev_printk(KERN_ERR, sdev, - "rejecting I/O to device being removed\n"); - goto kill; + "rejecting I/O to offline device\n"); + ret = BLKPREP_KILL; + break; + case SDEV_DEL: + /* + * If the device is fully deleted, we refuse to + * process any commands as well. + */ + sdev_printk(KERN_ERR, sdev, + "rejecting I/O to dead device\n"); + ret = BLKPREP_KILL; + break; + case SDEV_QUIESCE: + case SDEV_BLOCK: + /* + * If the devices is blocked we defer normal commands. + */ + if (!(req->cmd_flags & REQ_PREEMPT)) + ret = BLKPREP_DEFER; + break; + default: + /* + * For any other not fully online state we only allow + * special commands. In particular any user initiated + * command is not allowed. + */ + if (!(req->cmd_flags & REQ_PREEMPT)) + ret = BLKPREP_KILL; + break; } - - /* - * Now try and find a command block that we can use. - */ - if (!req->special) { - cmd = scsi_get_command(sdev, GFP_ATOMIC); - if (unlikely(!cmd)) - goto defer; - } else - cmd = req->special; - - /* pull a tag out of the request if we have one */ - cmd->tag = req->tag; - } else { - blk_dump_rq_flags(req, "SCSI bad req"); - goto kill; + + if (ret != BLKPREP_OK) + goto out; } - - /* note the overloading of req->special. When the tag - * is active it always means cmd. If the tag goes - * back for re-queueing, it may be reset */ - req->special = cmd; - cmd->request = req; - - /* - * FIXME: drop the lock here because the functions below - * expect to be called without the queue lock held. Also, - * previously, we dequeued the request before dropping the - * lock. We hope REQ_STARTED prevents anything untoward from - * happening now. - */ - if (blk_fs_request(req) || blk_pc_request(req)) { - int ret; + switch (req->cmd_type) { + case REQ_TYPE_BLOCK_PC: + ret = scsi_setup_blk_pc_cmnd(sdev, req); + break; + case REQ_TYPE_FS: + ret = scsi_setup_fs_cmnd(sdev, req); + break; + default: /* - * This will do a couple of things: - * 1) Fill in the actual SCSI command. - * 2) Fill in any other upper-level specific fields - * (timeout). + * All other command types are not supported. * - * If this returns 0, it means that the request failed - * (reading past end of disk, reading offline device, - * etc). This won't actually talk to the device, but - * some kinds of consistency checking may cause the - * request to be rejected immediately. + * Note that these days the SCSI subsystem does not use + * REQ_TYPE_SPECIAL requests anymore. These are only used + * (directly or via blk_insert_request) by non-SCSI drivers. */ + blk_dump_rq_flags(req, "SCSI bad req"); + ret = BLKPREP_KILL; + break; + } - /* - * This sets up the scatter-gather table (allocating if - * required). - */ - ret = scsi_init_io(cmd); - switch(ret) { - /* For BLKPREP_KILL/DEFER the cmd was released */ - case BLKPREP_KILL: - goto kill; - case BLKPREP_DEFER: - goto defer; - } - + out: + switch (ret) { + case BLKPREP_KILL: + req->errors = DID_NO_CONNECT << 16; + break; + case BLKPREP_DEFER: /* - * Initialize the actual SCSI command for this request. + * If we defer, the elv_next_request() returns NULL, but the + * queue must be restarted, so we plug here if no returning + * command will automatically do that. */ - if (blk_pc_request(req)) { - scsi_setup_blk_pc_cmnd(cmd); - } else if (req->rq_disk) { - struct scsi_driver *drv; - - drv = *(struct scsi_driver **)req->rq_disk->private_data; - if (unlikely(!drv->init_command(cmd))) { - scsi_release_buffers(cmd); - scsi_put_command(cmd); - goto kill; - } - } + if (sdev->device_busy == 0) + blk_plug_device(q); + break; + default: + req->cmd_flags |= REQ_DONTPREP; } - /* - * The request is now prepped, no need to come back here - */ - req->cmd_flags |= REQ_DONTPREP; - return BLKPREP_OK; - - defer: - /* If we defer, the elv_next_request() returns NULL, but the - * queue must be restarted, so we plug here if no returning - * command will automatically do that. */ - if (sdev->device_busy == 0) - blk_plug_device(q); - return BLKPREP_DEFER; - kill: - req->errors = DID_NO_CONNECT << 16; - return BLKPREP_KILL; + return ret; } /* @@ -1548,29 +1571,40 @@ u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost) } EXPORT_SYMBOL(scsi_calculate_bounce_limit); -struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) +struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, + request_fn_proc *request_fn) { - struct Scsi_Host *shost = sdev->host; struct request_queue *q; - q = blk_init_queue(scsi_request_fn, NULL); + q = blk_init_queue(request_fn, NULL); if (!q) return NULL; - blk_queue_prep_rq(q, scsi_prep_fn); - blk_queue_max_hw_segments(q, shost->sg_tablesize); blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS); blk_queue_max_sectors(q, shost->max_sectors); blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); blk_queue_segment_boundary(q, shost->dma_boundary); - blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); - blk_queue_softirq_done(q, scsi_softirq_done); if (!shost->use_clustering) clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); return q; } +EXPORT_SYMBOL(__scsi_alloc_queue); + +struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) +{ + struct request_queue *q; + + q = __scsi_alloc_queue(sdev->host, scsi_request_fn); + if (!q) + return NULL; + + blk_queue_prep_rq(q, scsi_prep_fn); + blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); + blk_queue_softirq_done(q, scsi_softirq_done); + return q; +} void scsi_free_queue(struct request_queue *q) { diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 5d023d44e5e..f458c2f686d 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -39,6 +39,9 @@ static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) { }; #endif +/* scsi_scan.c */ +int scsi_complete_async_scans(void); + /* scsi_devinfo.c */ extern int scsi_get_device_flags(struct scsi_device *sdev, const unsigned char *vendor, diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 94a274645f6..14e635aa44c 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -29,7 +29,9 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/blkdev.h> -#include <asm/semaphore.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <linux/spinlock.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -87,6 +89,17 @@ module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(max_luns, "last scsi LUN (should be between 1 and 2^32-1)"); +#ifdef CONFIG_SCSI_SCAN_ASYNC +#define SCSI_SCAN_TYPE_DEFAULT "async" +#else +#define SCSI_SCAN_TYPE_DEFAULT "sync" +#endif + +static char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT; + +module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO); +MODULE_PARM_DESC(scan, "sync, async or none"); + /* * max_scsi_report_luns: the maximum number of LUNS that will be * returned from the REPORT LUNS command. 8 times this value must @@ -108,6 +121,68 @@ MODULE_PARM_DESC(inq_timeout, "Timeout (in seconds) waiting for devices to answer INQUIRY." " Default is 5. Some non-compliant devices need more."); +static DEFINE_SPINLOCK(async_scan_lock); +static LIST_HEAD(scanning_hosts); + +struct async_scan_data { + struct list_head list; + struct Scsi_Host *shost; + struct completion prev_finished; +}; + +/** + * scsi_complete_async_scans - Wait for asynchronous scans to complete + * + * Asynchronous scans add themselves to the scanning_hosts list. Once + * that list is empty, we know that the scans are complete. Rather than + * waking up periodically to check the state of the list, we pretend to be + * a scanning task by adding ourselves at the end of the list and going to + * sleep. When the task before us wakes us up, we take ourselves off the + * list and return. + */ +int scsi_complete_async_scans(void) +{ + struct async_scan_data *data; + + do { + if (list_empty(&scanning_hosts)) + return 0; + /* If we can't get memory immediately, that's OK. Just + * sleep a little. Even if we never get memory, the async + * scans will finish eventually. + */ + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + msleep(1); + } while (!data); + + data->shost = NULL; + init_completion(&data->prev_finished); + + spin_lock(&async_scan_lock); + /* Check that there's still somebody else on the list */ + if (list_empty(&scanning_hosts)) + goto done; + list_add_tail(&data->list, &scanning_hosts); + spin_unlock(&async_scan_lock); + + printk(KERN_INFO "scsi: waiting for bus probes to complete ...\n"); + wait_for_completion(&data->prev_finished); + + spin_lock(&async_scan_lock); + list_del(&data->list); + done: + spin_unlock(&async_scan_lock); + + kfree(data); + return 0; +} + +#ifdef MODULE +/* Only exported for the benefit of scsi_wait_scan */ +EXPORT_SYMBOL_GPL(scsi_complete_async_scans); +#endif + /** * scsi_unlock_floptical - unlock device via a special MODE SENSE command * @sdev: scsi device to send command to @@ -362,9 +437,10 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, goto retry; } -static void scsi_target_reap_usercontext(void *data) +static void scsi_target_reap_usercontext(struct work_struct *work) { - struct scsi_target *starget = data; + struct scsi_target *starget = + container_of(work, struct scsi_target, ew.work); struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); unsigned long flags; @@ -400,7 +476,7 @@ void scsi_target_reap(struct scsi_target *starget) starget->state = STARGET_DEL; spin_unlock_irqrestore(shost->host_lock, flags); execute_in_process_context(scsi_target_reap_usercontext, - starget, &starget->ew); + &starget->ew); return; } @@ -619,7 +695,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized **/ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, - int *bflags) + int *bflags, int async) { /* * XXX do not save the inquiry, since it can change underneath us, @@ -805,7 +881,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, * register it and tell the rest of the kernel * about it. */ - if (scsi_sysfs_add_sdev(sdev) != 0) + if (!async && scsi_sysfs_add_sdev(sdev) != 0) return SCSI_SCAN_NO_RESPONSE; return SCSI_SCAN_LUN_PRESENT; @@ -974,7 +1050,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, goto out_free_result; } - res = scsi_add_lun(sdev, result, &bflags); + res = scsi_add_lun(sdev, result, &bflags, shost->async_scan); if (res == SCSI_SCAN_LUN_PRESENT) { if (bflags & BLIST_KEY) { sdev->lockable = 0; @@ -1474,6 +1550,12 @@ void scsi_scan_target(struct device *parent, unsigned int channel, { struct Scsi_Host *shost = dev_to_shost(parent); + if (strncmp(scsi_scan_type, "none", 4) == 0) + return; + + if (!shost->async_scan) + scsi_complete_async_scans(); + mutex_lock(&shost->scan_mutex); if (scsi_host_scan_allowed(shost)) __scsi_scan_target(parent, channel, id, lun, rescan); @@ -1519,6 +1601,9 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, "%s: <%u:%u:%u>\n", __FUNCTION__, channel, id, lun)); + if (!shost->async_scan) + scsi_complete_async_scans(); + if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) @@ -1539,14 +1624,143 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, return 0; } +static void scsi_sysfs_add_devices(struct Scsi_Host *shost) +{ + struct scsi_device *sdev; + shost_for_each_device(sdev, shost) { + if (scsi_sysfs_add_sdev(sdev) != 0) + scsi_destroy_sdev(sdev); + } +} + +/** + * scsi_prep_async_scan - prepare for an async scan + * @shost: the host which will be scanned + * Returns: a cookie to be passed to scsi_finish_async_scan() + * + * Tells the midlayer this host is going to do an asynchronous scan. + * It reserves the host's position in the scanning list and ensures + * that other asynchronous scans started after this one won't affect the + * ordering of the discovered devices. + */ +static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) +{ + struct async_scan_data *data; + + if (strncmp(scsi_scan_type, "sync", 4) == 0) + return NULL; + + if (shost->async_scan) { + printk("%s called twice for host %d", __FUNCTION__, + shost->host_no); + dump_stack(); + return NULL; + } + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + goto err; + data->shost = scsi_host_get(shost); + if (!data->shost) + goto err; + init_completion(&data->prev_finished); + + spin_lock(&async_scan_lock); + shost->async_scan = 1; + if (list_empty(&scanning_hosts)) + complete(&data->prev_finished); + list_add_tail(&data->list, &scanning_hosts); + spin_unlock(&async_scan_lock); + + return data; + + err: + kfree(data); + return NULL; +} + +/** + * scsi_finish_async_scan - asynchronous scan has finished + * @data: cookie returned from earlier call to scsi_prep_async_scan() + * + * All the devices currently attached to this host have been found. + * This function announces all the devices it has found to the rest + * of the system. + */ +static void scsi_finish_async_scan(struct async_scan_data *data) +{ + struct Scsi_Host *shost; + + if (!data) + return; + + shost = data->shost; + if (!shost->async_scan) { + printk("%s called twice for host %d", __FUNCTION__, + shost->host_no); + dump_stack(); + return; + } + + wait_for_completion(&data->prev_finished); + + scsi_sysfs_add_devices(shost); + + spin_lock(&async_scan_lock); + shost->async_scan = 0; + list_del(&data->list); + if (!list_empty(&scanning_hosts)) { + struct async_scan_data *next = list_entry(scanning_hosts.next, + struct async_scan_data, list); + complete(&next->prev_finished); + } + spin_unlock(&async_scan_lock); + + scsi_host_put(shost); + kfree(data); +} + +static void do_scsi_scan_host(struct Scsi_Host *shost) +{ + if (shost->hostt->scan_finished) { + unsigned long start = jiffies; + if (shost->hostt->scan_start) + shost->hostt->scan_start(shost); + + while (!shost->hostt->scan_finished(shost, jiffies - start)) + msleep(10); + } else { + scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, + SCAN_WILD_CARD, 0); + } +} + +static int do_scan_async(void *_data) +{ + struct async_scan_data *data = _data; + do_scsi_scan_host(data->shost); + scsi_finish_async_scan(data); + return 0; +} + /** * scsi_scan_host - scan the given adapter * @shost: adapter to scan **/ void scsi_scan_host(struct Scsi_Host *shost) { - scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, - SCAN_WILD_CARD, 0); + struct async_scan_data *data; + + if (strncmp(scsi_scan_type, "none", 4) == 0) + return; + + data = scsi_prep_async_scan(shost); + if (!data) { + do_scsi_scan_host(shost); + return; + } + + kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); } EXPORT_SYMBOL(scsi_scan_host); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index e1a91665d1c..259c90cfa36 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -218,16 +218,16 @@ static void scsi_device_cls_release(struct class_device *class_dev) put_device(&sdev->sdev_gendev); } -static void scsi_device_dev_release_usercontext(void *data) +static void scsi_device_dev_release_usercontext(struct work_struct *work) { - struct device *dev = data; struct scsi_device *sdev; struct device *parent; struct scsi_target *starget; unsigned long flags; - parent = dev->parent; - sdev = to_scsi_device(dev); + sdev = container_of(work, struct scsi_device, ew.work); + + parent = sdev->sdev_gendev.parent; starget = to_scsi_target(parent); spin_lock_irqsave(sdev->host->host_lock, flags); @@ -258,7 +258,7 @@ static void scsi_device_dev_release_usercontext(void *data) static void scsi_device_dev_release(struct device *dev) { struct scsi_device *sdp = to_scsi_device(dev); - execute_in_process_context(scsi_device_dev_release_usercontext, dev, + execute_in_process_context(scsi_device_dev_release_usercontext, &sdp->ew); } diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c new file mode 100644 index 00000000000..37bbfbdb870 --- /dev/null +++ b/drivers/scsi/scsi_tgt_if.c @@ -0,0 +1,352 @@ +/* + * SCSI target kernel/user interface functions + * + * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org> + * Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#include <linux/miscdevice.h> +#include <linux/file.h> +#include <net/tcp.h> +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_tgt.h> +#include <scsi/scsi_tgt_if.h> + +#include <asm/cacheflush.h> + +#include "scsi_tgt_priv.h" + +struct tgt_ring { + u32 tr_idx; + unsigned long tr_pages[TGT_RING_PAGES]; + spinlock_t tr_lock; +}; + +/* tx_ring : kernel->user, rx_ring : user->kernel */ +static struct tgt_ring tx_ring, rx_ring; +static DECLARE_WAIT_QUEUE_HEAD(tgt_poll_wait); + +static inline void tgt_ring_idx_inc(struct tgt_ring *ring) +{ + if (ring->tr_idx == TGT_MAX_EVENTS - 1) + ring->tr_idx = 0; + else + ring->tr_idx++; +} + +static struct tgt_event *tgt_head_event(struct tgt_ring *ring, u32 idx) +{ + u32 pidx, off; + + pidx = idx / TGT_EVENT_PER_PAGE; + off = idx % TGT_EVENT_PER_PAGE; + + return (struct tgt_event *) + (ring->tr_pages[pidx] + sizeof(struct tgt_event) * off); +} + +static int tgt_uspace_send_event(u32 type, struct tgt_event *p) +{ + struct tgt_event *ev; + struct tgt_ring *ring = &tx_ring; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&ring->tr_lock, flags); + + ev = tgt_head_event(ring, ring->tr_idx); + if (!ev->hdr.status) + tgt_ring_idx_inc(ring); + else + err = -BUSY; + + spin_unlock_irqrestore(&ring->tr_lock, flags); + + if (err) + return err; + + memcpy(ev, p, sizeof(*ev)); + ev->hdr.type = type; + mb(); + ev->hdr.status = 1; + + flush_dcache_page(virt_to_page(ev)); + + wake_up_interruptible(&tgt_poll_wait); + + return 0; +} + +int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag) +{ + struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); + struct tgt_event ev; + int err; + + memset(&ev, 0, sizeof(ev)); + ev.p.cmd_req.host_no = shost->host_no; + ev.p.cmd_req.data_len = cmd->request_bufflen; + memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb)); + memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun)); + ev.p.cmd_req.attribute = cmd->tag; + ev.p.cmd_req.tag = tag; + + dprintk("%p %d %u %x %llx\n", cmd, shost->host_no, + ev.p.cmd_req.data_len, cmd->tag, + (unsigned long long) ev.p.cmd_req.tag); + + err = tgt_uspace_send_event(TGT_KEVENT_CMD_REQ, &ev); + if (err) + eprintk("tx buf is full, could not send\n"); + + return err; +} + +int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag) +{ + struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); + struct tgt_event ev; + int err; + + memset(&ev, 0, sizeof(ev)); + ev.p.cmd_done.host_no = shost->host_no; + ev.p.cmd_done.tag = tag; + ev.p.cmd_done.result = cmd->result; + + dprintk("%p %d %llu %u %x\n", cmd, shost->host_no, + (unsigned long long) ev.p.cmd_req.tag, + ev.p.cmd_req.data_len, cmd->tag); + + err = tgt_uspace_send_event(TGT_KEVENT_CMD_DONE, &ev); + if (err) + eprintk("tx buf is full, could not send\n"); + + return err; +} + +int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, + struct scsi_lun *scsilun, void *data) +{ + struct tgt_event ev; + int err; + + memset(&ev, 0, sizeof(ev)); + ev.p.tsk_mgmt_req.host_no = host_no; + ev.p.tsk_mgmt_req.function = function; + ev.p.tsk_mgmt_req.tag = tag; + memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun)); + ev.p.tsk_mgmt_req.mid = (u64) (unsigned long) data; + + dprintk("%d %x %llx %llx\n", host_no, function, (unsigned long long) tag, + (unsigned long long) ev.p.tsk_mgmt_req.mid); + + err = tgt_uspace_send_event(TGT_KEVENT_TSK_MGMT_REQ, &ev); + if (err) + eprintk("tx buf is full, could not send\n"); + + return err; +} + +static int event_recv_msg(struct tgt_event *ev) +{ + int err = 0; + + switch (ev->hdr.type) { + case TGT_UEVENT_CMD_RSP: + err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no, + ev->p.cmd_rsp.tag, + ev->p.cmd_rsp.result, + ev->p.cmd_rsp.len, + ev->p.cmd_rsp.uaddr, + ev->p.cmd_rsp.rw); + break; + case TGT_UEVENT_TSK_MGMT_RSP: + err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no, + ev->p.tsk_mgmt_rsp.mid, + ev->p.tsk_mgmt_rsp.result); + break; + default: + eprintk("unknown type %d\n", ev->hdr.type); + err = -EINVAL; + } + + return err; +} + +static ssize_t tgt_write(struct file *file, const char __user * buffer, + size_t count, loff_t * ppos) +{ + struct tgt_event *ev; + struct tgt_ring *ring = &rx_ring; + + while (1) { + ev = tgt_head_event(ring, ring->tr_idx); + /* do we need this? */ + flush_dcache_page(virt_to_page(ev)); + + if (!ev->hdr.status) + break; + + tgt_ring_idx_inc(ring); + event_recv_msg(ev); + ev->hdr.status = 0; + }; + + return count; +} + +static unsigned int tgt_poll(struct file * file, struct poll_table_struct *wait) +{ + struct tgt_event *ev; + struct tgt_ring *ring = &tx_ring; + unsigned long flags; + unsigned int mask = 0; + u32 idx; + + poll_wait(file, &tgt_poll_wait, wait); + + spin_lock_irqsave(&ring->tr_lock, flags); + + idx = ring->tr_idx ? ring->tr_idx - 1 : TGT_MAX_EVENTS - 1; + ev = tgt_head_event(ring, idx); + if (ev->hdr.status) + mask |= POLLIN | POLLRDNORM; + + spin_unlock_irqrestore(&ring->tr_lock, flags); + + return mask; +} + +static int uspace_ring_map(struct vm_area_struct *vma, unsigned long addr, + struct tgt_ring *ring) +{ + int i, err; + + for (i = 0; i < TGT_RING_PAGES; i++) { + struct page *page = virt_to_page(ring->tr_pages[i]); + err = vm_insert_page(vma, addr, page); + if (err) + return err; + addr += PAGE_SIZE; + } + + return 0; +} + +static int tgt_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long addr; + int err; + + if (vma->vm_pgoff) + return -EINVAL; + + if (vma->vm_end - vma->vm_start != TGT_RING_SIZE * 2) { + eprintk("mmap size must be %lu, not %lu \n", + TGT_RING_SIZE * 2, vma->vm_end - vma->vm_start); + return -EINVAL; + } + + addr = vma->vm_start; + err = uspace_ring_map(vma, addr, &tx_ring); + if (err) + return err; + err = uspace_ring_map(vma, addr + TGT_RING_SIZE, &rx_ring); + + return err; +} + +static int tgt_open(struct inode *inode, struct file *file) +{ + tx_ring.tr_idx = rx_ring.tr_idx = 0; + + return 0; +} + +static struct file_operations tgt_fops = { + .owner = THIS_MODULE, + .open = tgt_open, + .poll = tgt_poll, + .write = tgt_write, + .mmap = tgt_mmap, +}; + +static struct miscdevice tgt_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "tgt", + .fops = &tgt_fops, +}; + +static void tgt_ring_exit(struct tgt_ring *ring) +{ + int i; + + for (i = 0; i < TGT_RING_PAGES; i++) + free_page(ring->tr_pages[i]); +} + +static int tgt_ring_init(struct tgt_ring *ring) +{ + int i; + + spin_lock_init(&ring->tr_lock); + + for (i = 0; i < TGT_RING_PAGES; i++) { + ring->tr_pages[i] = get_zeroed_page(GFP_KERNEL); + if (!ring->tr_pages[i]) { + eprintk("out of memory\n"); + return -ENOMEM; + } + } + + return 0; +} + +void scsi_tgt_if_exit(void) +{ + tgt_ring_exit(&tx_ring); + tgt_ring_exit(&rx_ring); + misc_deregister(&tgt_miscdev); +} + +int scsi_tgt_if_init(void) +{ + int err; + + err = tgt_ring_init(&tx_ring); + if (err) + return err; + + err = tgt_ring_init(&rx_ring); + if (err) + goto free_tx_ring; + + err = misc_register(&tgt_miscdev); + if (err) + goto free_rx_ring; + + return 0; +free_rx_ring: + tgt_ring_exit(&rx_ring); +free_tx_ring: + tgt_ring_exit(&tx_ring); + + return err; +} diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c new file mode 100644 index 00000000000..386dbae17b4 --- /dev/null +++ b/drivers/scsi/scsi_tgt_lib.c @@ -0,0 +1,745 @@ +/* + * SCSI target lib functions + * + * Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu> + * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#include <linux/blkdev.h> +#include <linux/hash.h> +#include <linux/module.h> +#include <linux/pagemap.h> +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_tgt.h> +#include <../drivers/md/dm-bio-list.h> + +#include "scsi_tgt_priv.h" + +static struct workqueue_struct *scsi_tgtd; +static kmem_cache_t *scsi_tgt_cmd_cache; + +/* + * TODO: this struct will be killed when the block layer supports large bios + * and James's work struct code is in + */ +struct scsi_tgt_cmd { + /* TODO replace work with James b's code */ + struct work_struct work; + /* TODO replace the lists with a large bio */ + struct bio_list xfer_done_list; + struct bio_list xfer_list; + + struct list_head hash_list; + struct request *rq; + u64 tag; + + void *buffer; + unsigned bufflen; +}; + +#define TGT_HASH_ORDER 4 +#define cmd_hashfn(tag) hash_long((unsigned long) (tag), TGT_HASH_ORDER) + +struct scsi_tgt_queuedata { + struct Scsi_Host *shost; + struct list_head cmd_hash[1 << TGT_HASH_ORDER]; + spinlock_t cmd_hash_lock; +}; + +/* + * Function: scsi_host_get_command() + * + * Purpose: Allocate and setup a scsi command block and blk request + * + * Arguments: shost - scsi host + * data_dir - dma data dir + * gfp_mask- allocator flags + * + * Returns: The allocated scsi command structure. + * + * This should be called by target LLDs to get a command. + */ +struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost, + enum dma_data_direction data_dir, + gfp_t gfp_mask) +{ + int write = (data_dir == DMA_TO_DEVICE); + struct request *rq; + struct scsi_cmnd *cmd; + struct scsi_tgt_cmd *tcmd; + + /* Bail if we can't get a reference to the device */ + if (!get_device(&shost->shost_gendev)) + return NULL; + + tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC); + if (!tcmd) + goto put_dev; + + rq = blk_get_request(shost->uspace_req_q, write, gfp_mask); + if (!rq) + goto free_tcmd; + + cmd = __scsi_get_command(shost, gfp_mask); + if (!cmd) + goto release_rq; + + memset(cmd, 0, sizeof(*cmd)); + cmd->sc_data_direction = data_dir; + cmd->jiffies_at_alloc = jiffies; + cmd->request = rq; + + rq->special = cmd; + rq->cmd_type = REQ_TYPE_SPECIAL; + rq->cmd_flags |= REQ_TYPE_BLOCK_PC; + rq->end_io_data = tcmd; + + bio_list_init(&tcmd->xfer_list); + bio_list_init(&tcmd->xfer_done_list); + tcmd->rq = rq; + + return cmd; + +release_rq: + blk_put_request(rq); +free_tcmd: + kmem_cache_free(scsi_tgt_cmd_cache, tcmd); +put_dev: + put_device(&shost->shost_gendev); + return NULL; + +} +EXPORT_SYMBOL_GPL(scsi_host_get_command); + +/* + * Function: scsi_host_put_command() + * + * Purpose: Free a scsi command block + * + * Arguments: shost - scsi host + * cmd - command block to free + * + * Returns: Nothing. + * + * Notes: The command must not belong to any lists. + */ +void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd) +{ + struct request_queue *q = shost->uspace_req_q; + struct request *rq = cmd->request; + struct scsi_tgt_cmd *tcmd = rq->end_io_data; + unsigned long flags; + + kmem_cache_free(scsi_tgt_cmd_cache, tcmd); + + spin_lock_irqsave(q->queue_lock, flags); + __blk_put_request(q, rq); + spin_unlock_irqrestore(q->queue_lock, flags); + + __scsi_put_command(shost, cmd, &shost->shost_gendev); +} +EXPORT_SYMBOL_GPL(scsi_host_put_command); + +static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd) +{ + struct bio *bio; + + /* must call bio_endio in case bio was bounced */ + while ((bio = bio_list_pop(&tcmd->xfer_done_list))) { + bio_endio(bio, bio->bi_size, 0); + bio_unmap_user(bio); + } + + while ((bio = bio_list_pop(&tcmd->xfer_list))) { + bio_endio(bio, bio->bi_size, 0); + bio_unmap_user(bio); + } +} + +static void cmd_hashlist_del(struct scsi_cmnd *cmd) +{ + struct request_queue *q = cmd->request->q; + struct scsi_tgt_queuedata *qdata = q->queuedata; + unsigned long flags; + struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; + + spin_lock_irqsave(&qdata->cmd_hash_lock, flags); + list_del(&tcmd->hash_list); + spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); +} + +static void scsi_tgt_cmd_destroy(struct work_struct *work) +{ + struct scsi_tgt_cmd *tcmd = + container_of(work, struct scsi_tgt_cmd, work); + struct scsi_cmnd *cmd = tcmd->rq->special; + + dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction, + rq_data_dir(cmd->request)); + /* + * We fix rq->cmd_flags here since when we told bio_map_user + * to write vm for WRITE commands, blk_rq_bio_prep set + * rq_data_dir the flags to READ. + */ + if (cmd->sc_data_direction == DMA_TO_DEVICE) + cmd->request->cmd_flags |= REQ_RW; + else + cmd->request->cmd_flags &= ~REQ_RW; + + scsi_unmap_user_pages(tcmd); + scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd); +} + +static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd, + u64 tag) +{ + struct scsi_tgt_queuedata *qdata = rq->q->queuedata; + unsigned long flags; + struct list_head *head; + + tcmd->tag = tag; + INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy); + spin_lock_irqsave(&qdata->cmd_hash_lock, flags); + head = &qdata->cmd_hash[cmd_hashfn(tag)]; + list_add(&tcmd->hash_list, head); + spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); +} + +/* + * scsi_tgt_alloc_queue - setup queue used for message passing + * shost: scsi host + * + * This should be called by the LLD after host allocation. + * And will be released when the host is released. + */ +int scsi_tgt_alloc_queue(struct Scsi_Host *shost) +{ + struct scsi_tgt_queuedata *queuedata; + struct request_queue *q; + int err, i; + + /* + * Do we need to send a netlink event or should uspace + * just respond to the hotplug event? + */ + q = __scsi_alloc_queue(shost, NULL); + if (!q) + return -ENOMEM; + + queuedata = kzalloc(sizeof(*queuedata), GFP_KERNEL); + if (!queuedata) { + err = -ENOMEM; + goto cleanup_queue; + } + queuedata->shost = shost; + q->queuedata = queuedata; + + /* + * this is a silly hack. We should probably just queue as many + * command as is recvd to userspace. uspace can then make + * sure we do not overload the HBA + */ + q->nr_requests = shost->hostt->can_queue; + /* + * We currently only support software LLDs so this does + * not matter for now. Do we need this for the cards we support? + * If so we should make it a host template value. + */ + blk_queue_dma_alignment(q, 0); + shost->uspace_req_q = q; + + for (i = 0; i < ARRAY_SIZE(queuedata->cmd_hash); i++) + INIT_LIST_HEAD(&queuedata->cmd_hash[i]); + spin_lock_init(&queuedata->cmd_hash_lock); + + return 0; + +cleanup_queue: + blk_cleanup_queue(q); + return err; +} +EXPORT_SYMBOL_GPL(scsi_tgt_alloc_queue); + +void scsi_tgt_free_queue(struct Scsi_Host *shost) +{ + int i; + unsigned long flags; + struct request_queue *q = shost->uspace_req_q; + struct scsi_cmnd *cmd; + struct scsi_tgt_queuedata *qdata = q->queuedata; + struct scsi_tgt_cmd *tcmd, *n; + LIST_HEAD(cmds); + + spin_lock_irqsave(&qdata->cmd_hash_lock, flags); + + for (i = 0; i < ARRAY_SIZE(qdata->cmd_hash); i++) { + list_for_each_entry_safe(tcmd, n, &qdata->cmd_hash[i], + hash_list) { + list_del(&tcmd->hash_list); + list_add(&tcmd->hash_list, &cmds); + } + } + + spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); + + while (!list_empty(&cmds)) { + tcmd = list_entry(cmds.next, struct scsi_tgt_cmd, hash_list); + list_del(&tcmd->hash_list); + cmd = tcmd->rq->special; + + shost->hostt->eh_abort_handler(cmd); + scsi_tgt_cmd_destroy(&tcmd->work); + } +} +EXPORT_SYMBOL_GPL(scsi_tgt_free_queue); + +struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *cmd) +{ + struct scsi_tgt_queuedata *queue = cmd->request->q->queuedata; + return queue->shost; +} +EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host); + +/* + * scsi_tgt_queue_command - queue command for userspace processing + * @cmd: scsi command + * @scsilun: scsi lun + * @tag: unique value to identify this command for tmf + */ +int scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun, + u64 tag) +{ + struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; + int err; + + init_scsi_tgt_cmd(cmd->request, tcmd, tag); + err = scsi_tgt_uspace_send_cmd(cmd, scsilun, tag); + if (err) + cmd_hashlist_del(cmd); + + return err; +} +EXPORT_SYMBOL_GPL(scsi_tgt_queue_command); + +/* + * This is run from a interrpt handler normally and the unmap + * needs process context so we must queue + */ +static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd) +{ + struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; + + dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); + + scsi_tgt_uspace_send_status(cmd, tcmd->tag); + queue_work(scsi_tgtd, &tcmd->work); +} + +static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); + int err; + + dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); + + err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done); + switch (err) { + case SCSI_MLQUEUE_HOST_BUSY: + case SCSI_MLQUEUE_DEVICE_BUSY: + return -EAGAIN; + } + + return 0; +} + +static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd) +{ + struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; + int err; + + err = __scsi_tgt_transfer_response(cmd); + if (!err) + return; + + cmd->result = DID_BUS_BUSY << 16; + err = scsi_tgt_uspace_send_status(cmd, tcmd->tag); + if (err <= 0) + /* the eh will have to pick this up */ + printk(KERN_ERR "Could not send cmd %p status\n", cmd); +} + +static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask) +{ + struct request *rq = cmd->request; + struct scsi_tgt_cmd *tcmd = rq->end_io_data; + int count; + + cmd->use_sg = rq->nr_phys_segments; + cmd->request_buffer = scsi_alloc_sgtable(cmd, gfp_mask); + if (!cmd->request_buffer) + return -ENOMEM; + + cmd->request_bufflen = rq->data_len; + + dprintk("cmd %p addr %p cnt %d %lu\n", cmd, tcmd->buffer, cmd->use_sg, + rq_data_dir(rq)); + count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer); + if (likely(count <= cmd->use_sg)) { + cmd->use_sg = count; + return 0; + } + + eprintk("cmd %p addr %p cnt %d\n", cmd, tcmd->buffer, cmd->use_sg); + scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); + return -EINVAL; +} + +/* TODO: test this crap and replace bio_map_user with new interface maybe */ +static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, + int rw) +{ + struct request_queue *q = cmd->request->q; + struct request *rq = cmd->request; + void *uaddr = tcmd->buffer; + unsigned int len = tcmd->bufflen; + struct bio *bio; + int err; + + while (len > 0) { + dprintk("%lx %u\n", (unsigned long) uaddr, len); + bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw); + if (IS_ERR(bio)) { + err = PTR_ERR(bio); + dprintk("fail to map %lx %u %d %x\n", + (unsigned long) uaddr, len, err, cmd->cmnd[0]); + goto unmap_bios; + } + + uaddr += bio->bi_size; + len -= bio->bi_size; + + /* + * The first bio is added and merged. We could probably + * try to add others using scsi_merge_bio() but for now + * we keep it simple. The first bio should be pretty large + * (either hitting the 1 MB bio pages limit or a queue limit) + * already but for really large IO we may want to try and + * merge these. + */ + if (!rq->bio) { + blk_rq_bio_prep(q, rq, bio); + rq->data_len = bio->bi_size; + } else + /* put list of bios to transfer in next go around */ + bio_list_add(&tcmd->xfer_list, bio); + } + + cmd->offset = 0; + err = scsi_tgt_init_cmd(cmd, GFP_KERNEL); + if (err) + goto unmap_bios; + + return 0; + +unmap_bios: + if (rq->bio) { + bio_unmap_user(rq->bio); + while ((bio = bio_list_pop(&tcmd->xfer_list))) + bio_unmap_user(bio); + } + + return err; +} + +static int scsi_tgt_transfer_data(struct scsi_cmnd *); + +static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd) +{ + struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; + struct bio *bio; + int err; + + /* should we free resources here on error ? */ + if (cmd->result) { +send_uspace_err: + err = scsi_tgt_uspace_send_status(cmd, tcmd->tag); + if (err <= 0) + /* the tgt uspace eh will have to pick this up */ + printk(KERN_ERR "Could not send cmd %p status\n", cmd); + return; + } + + dprintk("cmd %p request_bufflen %u bufflen %u\n", + cmd, cmd->request_bufflen, tcmd->bufflen); + + scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); + bio_list_add(&tcmd->xfer_done_list, cmd->request->bio); + + tcmd->buffer += cmd->request_bufflen; + cmd->offset += cmd->request_bufflen; + + if (!tcmd->xfer_list.head) { + scsi_tgt_transfer_response(cmd); + return; + } + + dprintk("cmd2 %p request_bufflen %u bufflen %u\n", + cmd, cmd->request_bufflen, tcmd->bufflen); + + bio = bio_list_pop(&tcmd->xfer_list); + BUG_ON(!bio); + + blk_rq_bio_prep(cmd->request->q, cmd->request, bio); + cmd->request->data_len = bio->bi_size; + err = scsi_tgt_init_cmd(cmd, GFP_ATOMIC); + if (err) { + cmd->result = DID_ERROR << 16; + goto send_uspace_err; + } + + if (scsi_tgt_transfer_data(cmd)) { + cmd->result = DID_NO_CONNECT << 16; + goto send_uspace_err; + } +} + +static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd) +{ + int err; + struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd); + + err = host->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done); + switch (err) { + case SCSI_MLQUEUE_HOST_BUSY: + case SCSI_MLQUEUE_DEVICE_BUSY: + return -EAGAIN; + default: + return 0; + } +} + +static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr, + unsigned len) +{ + char __user *p = (char __user *) uaddr; + + if (copy_from_user(cmd->sense_buffer, p, + min_t(unsigned, SCSI_SENSE_BUFFERSIZE, len))) { + printk(KERN_ERR "Could not copy the sense buffer\n"); + return -EIO; + } + return 0; +} + +static int scsi_tgt_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd) +{ + struct scsi_tgt_cmd *tcmd; + int err; + + err = shost->hostt->eh_abort_handler(cmd); + if (err) + eprintk("fail to abort %p\n", cmd); + + tcmd = cmd->request->end_io_data; + scsi_tgt_cmd_destroy(&tcmd->work); + return err; +} + +static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag) +{ + struct scsi_tgt_queuedata *qdata = q->queuedata; + struct request *rq = NULL; + struct list_head *head; + struct scsi_tgt_cmd *tcmd; + unsigned long flags; + + head = &qdata->cmd_hash[cmd_hashfn(tag)]; + spin_lock_irqsave(&qdata->cmd_hash_lock, flags); + list_for_each_entry(tcmd, head, hash_list) { + if (tcmd->tag == tag) { + rq = tcmd->rq; + list_del(&tcmd->hash_list); + break; + } + } + spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); + + return rq; +} + +int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, + unsigned long uaddr, u8 rw) +{ + struct Scsi_Host *shost; + struct scsi_cmnd *cmd; + struct request *rq; + struct scsi_tgt_cmd *tcmd; + int err = 0; + + dprintk("%d %llu %d %u %lx %u\n", host_no, (unsigned long long) tag, + result, len, uaddr, rw); + + /* TODO: replace with a O(1) alg */ + shost = scsi_host_lookup(host_no); + if (IS_ERR(shost)) { + printk(KERN_ERR "Could not find host no %d\n", host_no); + return -EINVAL; + } + + if (!shost->uspace_req_q) { + printk(KERN_ERR "Not target scsi host %d\n", host_no); + goto done; + } + + rq = tgt_cmd_hash_lookup(shost->uspace_req_q, tag); + if (!rq) { + printk(KERN_ERR "Could not find tag %llu\n", + (unsigned long long) tag); + err = -EINVAL; + goto done; + } + cmd = rq->special; + + dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd, + result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]); + + if (result == TASK_ABORTED) { + scsi_tgt_abort_cmd(shost, cmd); + goto done; + } + /* + * store the userspace values here, the working values are + * in the request_* values + */ + tcmd = cmd->request->end_io_data; + tcmd->buffer = (void *)uaddr; + tcmd->bufflen = len; + cmd->result = result; + + if (!tcmd->bufflen || cmd->request_buffer) { + err = __scsi_tgt_transfer_response(cmd); + goto done; + } + + /* + * TODO: Do we need to handle case where request does not + * align with LLD. + */ + err = scsi_map_user_pages(rq->end_io_data, cmd, rw); + if (err) { + eprintk("%p %d\n", cmd, err); + err = -EAGAIN; + goto done; + } + + /* userspace failure */ + if (cmd->result) { + if (status_byte(cmd->result) == CHECK_CONDITION) + scsi_tgt_copy_sense(cmd, uaddr, len); + err = __scsi_tgt_transfer_response(cmd); + goto done; + } + /* ask the target LLD to transfer the data to the buffer */ + err = scsi_tgt_transfer_data(cmd); + +done: + scsi_host_put(shost); + return err; +} + +int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, int function, u64 tag, + struct scsi_lun *scsilun, void *data) +{ + int err; + + /* TODO: need to retry if this fails. */ + err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, function, + tag, scsilun, data); + if (err < 0) + eprintk("The task management request lost!\n"); + return err; +} +EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request); + +int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result) +{ + struct Scsi_Host *shost; + int err = -EINVAL; + + dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid); + + shost = scsi_host_lookup(host_no); + if (IS_ERR(shost)) { + printk(KERN_ERR "Could not find host no %d\n", host_no); + return err; + } + + if (!shost->uspace_req_q) { + printk(KERN_ERR "Not target scsi host %d\n", host_no); + goto done; + } + + err = shost->hostt->tsk_mgmt_response(mid, result); +done: + scsi_host_put(shost); + return err; +} + +static int __init scsi_tgt_init(void) +{ + int err; + + scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd", + sizeof(struct scsi_tgt_cmd), + 0, 0, NULL, NULL); + if (!scsi_tgt_cmd_cache) + return -ENOMEM; + + scsi_tgtd = create_workqueue("scsi_tgtd"); + if (!scsi_tgtd) { + err = -ENOMEM; + goto free_kmemcache; + } + + err = scsi_tgt_if_init(); + if (err) + goto destroy_wq; + + return 0; + +destroy_wq: + destroy_workqueue(scsi_tgtd); +free_kmemcache: + kmem_cache_destroy(scsi_tgt_cmd_cache); + return err; +} + +static void __exit scsi_tgt_exit(void) +{ + destroy_workqueue(scsi_tgtd); + scsi_tgt_if_exit(); + kmem_cache_destroy(scsi_tgt_cmd_cache); +} + +module_init(scsi_tgt_init); +module_exit(scsi_tgt_exit); + +MODULE_DESCRIPTION("SCSI target core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h new file mode 100644 index 00000000000..84488c51ff6 --- /dev/null +++ b/drivers/scsi/scsi_tgt_priv.h @@ -0,0 +1,25 @@ +struct scsi_cmnd; +struct scsi_lun; +struct Scsi_Host; +struct task_struct; + +/* tmp - will replace with SCSI logging stuff */ +#define eprintk(fmt, args...) \ +do { \ + printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \ +} while (0) + +#define dprintk(fmt, args...) +/* #define dprintk eprintk */ + +extern void scsi_tgt_if_exit(void); +extern int scsi_tgt_if_init(void); + +extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, + u64 tag); +extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag); +extern int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, + unsigned long uaddr, u8 rw); +extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, + struct scsi_lun *scsilun, void *data); +extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 38c215a78f6..3571ce8934e 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -241,9 +241,9 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) #define FC_MGMTSRVR_PORTID 0x00000a -static void fc_timeout_deleted_rport(void *data); -static void fc_timeout_fail_rport_io(void *data); -static void fc_scsi_scan_rport(void *data); +static void fc_timeout_deleted_rport(struct work_struct *work); +static void fc_timeout_fail_rport_io(struct work_struct *work); +static void fc_scsi_scan_rport(struct work_struct *work); /* * Attribute counts pre object type... @@ -1613,7 +1613,7 @@ fc_flush_work(struct Scsi_Host *shost) * 1 on success / 0 already queued / < 0 for error **/ static int -fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work, +fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work, unsigned long delay) { if (unlikely(!fc_host_devloss_work_q(shost))) { @@ -1625,9 +1625,6 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work, return -EINVAL; } - if (delay == 0) - return queue_work(fc_host_devloss_work_q(shost), work); - return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay); } @@ -1712,12 +1709,13 @@ EXPORT_SYMBOL(fc_remove_host); * fc_starget_delete - called to delete the scsi decendents of an rport * (target and all sdevs) * - * @data: remote port to be operated on. + * @work: remote port to be operated on. **/ static void -fc_starget_delete(void *data) +fc_starget_delete(struct work_struct *work) { - struct fc_rport *rport = (struct fc_rport *)data; + struct fc_rport *rport = + container_of(work, struct fc_rport, stgt_delete_work); struct Scsi_Host *shost = rport_to_shost(rport); unsigned long flags; struct fc_internal *i = to_fc_internal(shost->transportt); @@ -1751,12 +1749,13 @@ fc_starget_delete(void *data) /** * fc_rport_final_delete - finish rport termination and delete it. * - * @data: remote port to be deleted. + * @work: remote port to be deleted. **/ static void -fc_rport_final_delete(void *data) +fc_rport_final_delete(struct work_struct *work) { - struct fc_rport *rport = (struct fc_rport *)data; + struct fc_rport *rport = + container_of(work, struct fc_rport, rport_delete_work); struct device *dev = &rport->dev; struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); @@ -1770,7 +1769,7 @@ fc_rport_final_delete(void *data) /* Delete SCSI target and sdevs */ if (rport->scsi_target_id != -1) - fc_starget_delete(data); + fc_starget_delete(&rport->stgt_delete_work); else if (i->f->dev_loss_tmo_callbk) i->f->dev_loss_tmo_callbk(rport); else if (i->f->terminate_rport_io) @@ -1829,11 +1828,11 @@ fc_rport_create(struct Scsi_Host *shost, int channel, rport->channel = channel; rport->fast_io_fail_tmo = -1; - INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport); - INIT_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io, rport); - INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); - INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport); - INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport); + INIT_DELAYED_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport); + INIT_DELAYED_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io); + INIT_WORK(&rport->scan_work, fc_scsi_scan_rport); + INIT_WORK(&rport->stgt_delete_work, fc_starget_delete); + INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete); spin_lock_irqsave(shost->host_lock, flags); @@ -1963,7 +1962,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, } if (match) { - struct work_struct *work = + struct delayed_work *work = &rport->dev_loss_work; memcpy(&rport->node_name, &ids->node_name, @@ -2267,12 +2266,13 @@ EXPORT_SYMBOL(fc_remote_port_rolechg); * was a SCSI target (thus was blocked), and failed * to return in the alloted time. * - * @data: rport target that failed to reappear in the alloted time. + * @work: rport target that failed to reappear in the alloted time. **/ static void -fc_timeout_deleted_rport(void *data) +fc_timeout_deleted_rport(struct work_struct *work) { - struct fc_rport *rport = (struct fc_rport *)data; + struct fc_rport *rport = + container_of(work, struct fc_rport, dev_loss_work.work); struct Scsi_Host *shost = rport_to_shost(rport); struct fc_host_attrs *fc_host = shost_to_fc_host(shost); unsigned long flags; @@ -2366,15 +2366,16 @@ fc_timeout_deleted_rport(void *data) * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a * disconnected SCSI target. * - * @data: rport to terminate io on. + * @work: rport to terminate io on. * * Notes: Only requests the failure of the io, not that all are flushed * prior to returning. **/ static void -fc_timeout_fail_rport_io(void *data) +fc_timeout_fail_rport_io(struct work_struct *work) { - struct fc_rport *rport = (struct fc_rport *)data; + struct fc_rport *rport = + container_of(work, struct fc_rport, fail_io_work.work); struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); @@ -2387,12 +2388,13 @@ fc_timeout_fail_rport_io(void *data) /** * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. * - * @data: remote port to be scanned. + * @work: remote port to be scanned. **/ static void -fc_scsi_scan_rport(void *data) +fc_scsi_scan_rport(struct work_struct *work) { - struct fc_rport *rport = (struct fc_rport *)data; + struct fc_rport *rport = + container_of(work, struct fc_rport, scan_work); struct Scsi_Host *shost = rport_to_shost(rport); unsigned long flags; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 9b25124a989..9c22f134271 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -234,9 +234,11 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, return 0; } -static void session_recovery_timedout(void *data) +static void session_recovery_timedout(struct work_struct *work) { - struct iscsi_cls_session *session = data; + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, + recovery_work.work); dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " "out after %d secs\n", session->recovery_tmo); @@ -276,7 +278,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, session->transport = transport; session->recovery_tmo = 120; - INIT_WORK(&session->recovery_work, session_recovery_timedout, session); + INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 9f070f0d0f2..3fded483146 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -964,9 +964,10 @@ struct work_queue_wrapper { }; static void -spi_dv_device_work_wrapper(void *data) +spi_dv_device_work_wrapper(struct work_struct *work) { - struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct work_queue_wrapper *wqw = + container_of(work, struct work_queue_wrapper, work); struct scsi_device *sdev = wqw->sdev; kfree(wqw); @@ -1006,7 +1007,7 @@ spi_schedule_dv_device(struct scsi_device *sdev) return; } - INIT_WORK(&wqw->work, spi_dv_device_work_wrapper, wqw); + INIT_WORK(&wqw->work, spi_dv_device_work_wrapper); wqw->sdev = sdev; schedule_work(&wqw->work); diff --git a/drivers/scsi/scsi_wait_scan.c b/drivers/scsi/scsi_wait_scan.c new file mode 100644 index 00000000000..8a636103083 --- /dev/null +++ b/drivers/scsi/scsi_wait_scan.c @@ -0,0 +1,31 @@ +/* + * scsi_wait_scan.c + * + * Copyright (C) 2006 James Bottomley <James.Bottomley@SteelEye.com> + * + * This is a simple module to wait until all the async scans are + * complete. The idea is to use it in initrd/initramfs scripts. You + * modprobe it after all the modprobes of the root SCSI drivers and it + * will wait until they have all finished scanning their busses before + * allowing the boot to proceed + */ + +#include <linux/module.h> +#include "scsi_priv.h" + +static int __init wait_scan_init(void) +{ + scsi_complete_async_scans(); + return 0; +} + +static void __exit wait_scan_exit(void) +{ +} + +MODULE_DESCRIPTION("SCSI wait for scans"); +MODULE_AUTHOR("James Bottomley"); +MODULE_LICENSE("GPL"); + +late_initcall(wait_scan_init); +module_exit(wait_scan_exit); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 84ff203ffed..f6a452846fa 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1051,6 +1051,14 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname) &sshdr, SD_TIMEOUT, SD_MAX_RETRIES); + /* + * If the drive has indicated to us that it + * doesn't have any media in it, don't bother + * with any more polling. + */ + if (media_not_present(sdkp, &sshdr)) + return; + if (the_result) sense_valid = scsi_sense_valid(&sshdr); retries++; @@ -1059,14 +1067,6 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname) ((driver_byte(the_result) & DRIVER_SENSE) && sense_valid && sshdr.sense_key == UNIT_ATTENTION))); - /* - * If the drive has indicated to us that it doesn't have - * any media in it, don't bother with any of the rest of - * this crap. - */ - if (media_not_present(sdkp, &sshdr)) - return; - if ((driver_byte(the_result) & DRIVER_SENSE) == 0) { /* no sense, TUR either succeeded or failed * with a status error */ @@ -1467,7 +1467,6 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); if (scsi_status_is_good(res)) { - int ct = 0; int offset = data.header_length + data.block_descriptor_length; if (offset >= SD_BUF_SIZE - 2) { @@ -1496,11 +1495,13 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, sdkp->DPOFUA = 0; } - ct = sdkp->RCD + 2*sdkp->WCE; - - printk(KERN_NOTICE "SCSI device %s: drive cache: %s%s\n", - diskname, sd_cache_types[ct], - sdkp->DPOFUA ? " w/ FUA" : ""); + printk(KERN_NOTICE "SCSI device %s: " + "write cache: %s, read cache: %s, %s\n", + diskname, + sdkp->WCE ? "enabled" : "disabled", + sdkp->RCD ? "disabled" : "enabled", + sdkp->DPOFUA ? "supports DPO and FUA" + : "doesn't support DPO or FUA"); return; } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index e1a52c525ed..587274dd705 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -9,7 +9,7 @@ Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and Eric Youngdale. - Copyright 1992 - 2005 Kai Makisara + Copyright 1992 - 2006 Kai Makisara email Kai.Makisara@kolumbus.fi Some small formal changes - aeb, 950809 @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support */ -static const char *verstr = "20050830"; +static const char *verstr = "20061107"; #include <linux/module.h> @@ -999,7 +999,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp) STp->min_block = ((STp->buffer)->b_data[4] << 8) | (STp->buffer)->b_data[5]; if ( DEB( debugging || ) !STp->inited) - printk(KERN_WARNING + printk(KERN_INFO "%s: Block limits %d - %d bytes.\n", name, STp->min_block, STp->max_block); } else { @@ -1224,7 +1224,7 @@ static int st_flush(struct file *filp, fl_owner_t id) } DEBC( if (STp->nbr_requests) - printk(KERN_WARNING "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n", + printk(KERN_DEBUG "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n", name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable)); if (STps->rw == ST_WRITING && !STp->pos_unknown) { @@ -4056,11 +4056,11 @@ static int st_probe(struct device *dev) goto out_free_tape; } - sdev_printk(KERN_WARNING, SDp, + sdev_printk(KERN_NOTICE, SDp, "Attached scsi tape %s\n", tape_name(tpnt)); - printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B)\n", - tape_name(tpnt), tpnt->try_dio ? "yes" : "no", - queue_dma_alignment(SDp->request_queue) + 1); + sdev_printk(KERN_INFO, SDp, "%s: try direct i/o: %s (alignment %d B)\n", + tape_name(tpnt), tpnt->try_dio ? "yes" : "no", + queue_dma_alignment(SDp->request_queue) + 1); return 0; diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 185c270bb04..ba6bcdaf2a6 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -11,8 +11,6 @@ * Written By: * Ed Lin <promise_linux@promise.com> * - * Version: 3.0.0.1 - * */ #include <linux/init.h> @@ -37,9 +35,9 @@ #include <scsi/scsi_tcq.h> #define DRV_NAME "stex" -#define ST_DRIVER_VERSION "3.0.0.1" +#define ST_DRIVER_VERSION "3.1.0.1" #define ST_VER_MAJOR 3 -#define ST_VER_MINOR 0 +#define ST_VER_MINOR 1 #define ST_OEM 0 #define ST_BUILD_VER 1 @@ -76,8 +74,10 @@ enum { MU_STATE_STARTED = 4, MU_STATE_RESETTING = 5, - MU_MAX_DELAY_TIME = 240000, + MU_MAX_DELAY = 120, MU_HANDSHAKE_SIGNATURE = 0x55aaaa55, + MU_HANDSHAKE_SIGNATURE_HALF = 0x5a5a0000, + MU_HARD_RESET_WAIT = 30000, HMU_PARTNER_TYPE = 2, /* firmware returned values */ @@ -120,7 +120,8 @@ enum { st_shasta = 0, st_vsc = 1, - st_yosemite = 2, + st_vsc1 = 2, + st_yosemite = 3, PASSTHRU_REQ_TYPE = 0x00000001, PASSTHRU_REQ_NO_WAKEUP = 0x00000100, @@ -150,6 +151,8 @@ enum { MGT_CMD_SIGNATURE = 0xba, INQUIRY_EVPD = 0x01, + + ST_ADDITIONAL_MEM = 0x200000, }; /* SCSI inquiry data */ @@ -211,7 +214,9 @@ struct handshake_frame { __le32 partner_ver_minor; __le32 partner_ver_oem; __le32 partner_ver_build; - u32 reserved1[4]; + __le32 extra_offset; /* NEW */ + __le32 extra_size; /* NEW */ + u32 reserved1[2]; }; struct req_msg { @@ -302,6 +307,7 @@ struct st_hba { void __iomem *mmio_base; /* iomapped PCI memory space */ void *dma_mem; dma_addr_t dma_handle; + size_t dma_size; struct Scsi_Host *host; struct pci_dev *pdev; @@ -507,6 +513,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) size_t count = sizeof(struct st_frame); p = hba->copy_buffer; + stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_FROM_CMD); memset(p->base, 0, sizeof(u32)*6); *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0); p->rom_addr = 0; @@ -901,27 +908,34 @@ static int stex_handshake(struct st_hba *hba) void __iomem *base = hba->mmio_base; struct handshake_frame *h; dma_addr_t status_phys; - int i; + u32 data; + unsigned long before; if (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL); readl(base + IDBL); - for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE - && i < MU_MAX_DELAY_TIME; i++) { + before = jiffies; + while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { + if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { + printk(KERN_ERR DRV_NAME + "(%s): no handshake signature\n", + pci_name(hba->pdev)); + return -1; + } rmb(); msleep(1); } - - if (i == MU_MAX_DELAY_TIME) { - printk(KERN_ERR DRV_NAME - "(%s): no handshake signature\n", - pci_name(hba->pdev)); - return -1; - } } udelay(10); + data = readl(base + OMR1); + if ((data & 0xffff0000) == MU_HANDSHAKE_SIGNATURE_HALF) { + data &= 0x0000ffff; + if (hba->host->can_queue > data) + hba->host->can_queue = data; + } + h = (struct handshake_frame *)(hba->dma_mem + MU_REQ_BUFFER_SIZE); h->rb_phy = cpu_to_le32(hba->dma_handle); h->rb_phy_hi = cpu_to_le32((hba->dma_handle >> 16) >> 16); @@ -931,6 +945,11 @@ static int stex_handshake(struct st_hba *hba) h->status_cnt = cpu_to_le16(MU_STATUS_COUNT); stex_gettime(&h->hosttime); h->partner_type = HMU_PARTNER_TYPE; + if (hba->dma_size > STEX_BUFFER_SIZE) { + h->extra_offset = cpu_to_le32(STEX_BUFFER_SIZE); + h->extra_size = cpu_to_le32(ST_ADDITIONAL_MEM); + } else + h->extra_offset = h->extra_size = 0; status_phys = hba->dma_handle + MU_REQ_BUFFER_SIZE; writel(status_phys, base + IMR0); @@ -944,19 +963,18 @@ static int stex_handshake(struct st_hba *hba) readl(base + IDBL); /* flush */ udelay(10); - for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE - && i < MU_MAX_DELAY_TIME; i++) { + before = jiffies; + while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { + if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { + printk(KERN_ERR DRV_NAME + "(%s): no signature after handshake frame\n", + pci_name(hba->pdev)); + return -1; + } rmb(); msleep(1); } - if (i == MU_MAX_DELAY_TIME) { - printk(KERN_ERR DRV_NAME - "(%s): no signature after handshake frame\n", - pci_name(hba->pdev)); - return -1; - } - writel(0, base + IMR0); readl(base + IMR0); writel(0, base + OMR0); @@ -1038,9 +1056,9 @@ static void stex_hard_reset(struct st_hba *hba) pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET; pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); - for (i = 0; i < MU_MAX_DELAY_TIME; i++) { + for (i = 0; i < MU_HARD_RESET_WAIT; i++) { pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd); - if (pci_cmd & PCI_COMMAND_MASTER) + if (pci_cmd != 0xffff && (pci_cmd & PCI_COMMAND_MASTER)) break; msleep(1); } @@ -1100,18 +1118,18 @@ static int stex_reset(struct scsi_cmnd *cmd) static int stex_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) { - int heads = 255, sectors = 63, cylinders; + int heads = 255, sectors = 63; if (capacity < 0x200000) { heads = 64; sectors = 32; } - cylinders = sector_div(capacity, heads * sectors); + sector_div(capacity, heads * sectors); geom[0] = heads; geom[1] = sectors; - geom[2] = cylinders; + geom[2] = capacity; return 0; } @@ -1193,8 +1211,13 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_iounmap; } + hba->cardtype = (unsigned int) id->driver_data; + if (hba->cardtype == st_vsc && (pdev->subsystem_device & 0xf) == 0x1) + hba->cardtype = st_vsc1; + hba->dma_size = (hba->cardtype == st_vsc1) ? + (STEX_BUFFER_SIZE + ST_ADDITIONAL_MEM) : (STEX_BUFFER_SIZE); hba->dma_mem = dma_alloc_coherent(&pdev->dev, - STEX_BUFFER_SIZE, &hba->dma_handle, GFP_KERNEL); + hba->dma_size, &hba->dma_handle, GFP_KERNEL); if (!hba->dma_mem) { err = -ENOMEM; printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n", @@ -1207,8 +1230,6 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) hba->copy_buffer = hba->dma_mem + MU_BUFFER_SIZE; hba->mu_status = MU_STATE_STARTING; - hba->cardtype = (unsigned int) id->driver_data; - /* firmware uses id/lun pair for a logical drive, but lun would be always 0 if CONFIG_SCSI_MULTI_LUN not configured, so we use channel to map lun here */ @@ -1233,7 +1254,7 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto out_free_irq; - err = scsi_init_shared_tag_map(host, ST_CAN_QUEUE); + err = scsi_init_shared_tag_map(host, host->can_queue); if (err) { printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n", pci_name(pdev)); @@ -1256,7 +1277,7 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) out_free_irq: free_irq(pdev->irq, hba); out_pci_free: - dma_free_coherent(&pdev->dev, STEX_BUFFER_SIZE, + dma_free_coherent(&pdev->dev, hba->dma_size, hba->dma_mem, hba->dma_handle); out_iounmap: iounmap(hba->mmio_base); @@ -1317,7 +1338,7 @@ static void stex_hba_free(struct st_hba *hba) pci_release_regions(hba->pdev); - dma_free_coherent(&hba->pdev->dev, STEX_BUFFER_SIZE, + dma_free_coherent(&hba->pdev->dev, hba->dma_size, hba->dma_mem, hba->dma_handle); } @@ -1346,15 +1367,32 @@ static void stex_shutdown(struct pci_dev *pdev) } static struct pci_device_id stex_pci_tbl[] = { - { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, - { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, - { 0x105a, 0xf350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, - { 0x105a, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, - { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, - { 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, - { 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, - { 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc }, - { 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yosemite }, + /* st_shasta */ + { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + st_shasta }, /* SuperTrak EX8350/8300/16350/16300 */ + { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + st_shasta }, /* SuperTrak EX12350 */ + { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + st_shasta }, /* SuperTrak EX4350 */ + { 0x105a, 0xe350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + st_shasta }, /* SuperTrak EX24350 */ + + /* st_vsc */ + { 0x105a, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc }, + + /* st_yosemite */ + { 0x105a, 0x8650, PCI_ANY_ID, 0x4600, 0, 0, + st_yosemite }, /* SuperTrak EX4650 */ + { 0x105a, 0x8650, PCI_ANY_ID, 0x4610, 0, 0, + st_yosemite }, /* SuperTrak EX4650o */ + { 0x105a, 0x8650, PCI_ANY_ID, 0x8600, 0, 0, + st_yosemite }, /* SuperTrak EX8650EL */ + { 0x105a, 0x8650, PCI_ANY_ID, 0x8601, 0, 0, + st_yosemite }, /* SuperTrak EX8650 */ + { 0x105a, 0x8650, PCI_ANY_ID, 0x8602, 0, 0, + st_yosemite }, /* SuperTrak EX8654 */ + { 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + st_yosemite }, /* generic st_yosemite */ { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, stex_pci_tbl); diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h index 646e840266e..76a069b7ac0 100644 --- a/drivers/scsi/t128.h +++ b/drivers/scsi/t128.h @@ -8,20 +8,20 @@ * drew@colorado.edu * +1 (303) 440-4894 * - * DISTRIBUTION RELEASE 3. + * DISTRIBUTION RELEASE 3. * - * For more information, please consult + * For more information, please consult * * Trantor Systems, Ltd. * T128/T128F/T228 SCSI Host Adapter * Hardware Specifications - * - * Trantor Systems, Ltd. + * + * Trantor Systems, Ltd. * 5415 Randall Place * Fremont, CA 94538 * 1+ (415) 770-1400, FAX 1+ (415) 770-9910 - * - * and + * + * and * * NCR 5380 Family * SCSI Protocol Controller @@ -48,15 +48,15 @@ #define TDEBUG_TRANSFER 0x2 /* - * The trantor boards are memory mapped. They use an NCR5380 or + * The trantor boards are memory mapped. They use an NCR5380 or * equivalent (my sample board had part second sourced from ZILOG). - * NCR's recommended "Pseudo-DMA" architecture is used, where + * NCR's recommended "Pseudo-DMA" architecture is used, where * a PAL drives the DMA signals on the 5380 allowing fast, blind - * transfers with proper handshaking. + * transfers with proper handshaking. */ /* - * Note : a boot switch is provided for the purpose of informing the + * Note : a boot switch is provided for the purpose of informing the * firmware to boot or not boot from attached SCSI devices. So, I imagine * there are fewer people who've yanked the ROM like they do on the Seagate * to make bootup faster, and I'll probably use this for autodetection. @@ -92,19 +92,20 @@ #define T_DATA_REG_OFFSET 0x1e00 /* rw 512 bytes long */ #ifndef ASM -static int t128_abort(Scsi_Cmnd *); +static int t128_abort(struct scsi_cmnd *); static int t128_biosparam(struct scsi_device *, struct block_device *, sector_t, int*); static int t128_detect(struct scsi_host_template *); -static int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -static int t128_bus_reset(Scsi_Cmnd *); +static int t128_queue_command(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); +static int t128_bus_reset(struct scsi_cmnd *); #ifndef CMD_PER_LUN #define CMD_PER_LUN 2 #endif #ifndef CAN_QUEUE -#define CAN_QUEUE 32 +#define CAN_QUEUE 32 #endif #ifndef HOSTS_C @@ -120,7 +121,7 @@ static int t128_bus_reset(Scsi_Cmnd *); #define T128_address(reg) (base + T_5380_OFFSET + ((reg) * 0x20)) -#if !(TDEBUG & TDEBUG_TRANSFER) +#if !(TDEBUG & TDEBUG_TRANSFER) #define NCR5380_read(reg) readb(T128_address(reg)) #define NCR5380_write(reg, value) writeb((value),(T128_address(reg))) #else @@ -129,7 +130,7 @@ static int t128_bus_reset(Scsi_Cmnd *); , instance->hostno, (reg), T128_address(reg))), readb(T128_address(reg))) #define NCR5380_write(reg, value) { \ - printk("scsi%d : write %02x to register %d at address %08x\n", \ + printk("scsi%d : write %02x to register %d at address %08x\n", \ instance->hostno, (value), (reg), T128_address(reg)); \ writeb((value), (T128_address(reg))); \ } @@ -142,10 +143,10 @@ static int t128_bus_reset(Scsi_Cmnd *); #define NCR5380_bus_reset t128_bus_reset #define NCR5380_proc_info t128_proc_info -/* 15 14 12 10 7 5 3 +/* 15 14 12 10 7 5 3 1101 0100 1010 1000 */ - -#define T128_IRQS 0xc4a8 + +#define T128_IRQS 0xc4a8 #endif /* else def HOSTS_C */ #endif /* ndef ASM */ diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index aee1b31f1a1..3db206d29b3 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -60,7 +60,8 @@ struct timer_list mcfrs_timer_struct; #if defined(CONFIG_HW_FEITH) #define CONSOLE_BAUD_RATE 38400 #define DEFAULT_CBAUD B38400 -#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || defined(CONFIG_M5329EVB) +#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \ + defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO) #define CONSOLE_BAUD_RATE 115200 #define DEFAULT_CBAUD B115200 #elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \ @@ -109,12 +110,30 @@ static struct mcf_serial mcfrs_table[] = { .irq = IRQBASE, .flags = ASYNC_BOOT_AUTOCONF, }, +#ifdef MCFUART_BASE2 { /* ttyS1 */ .magic = 0, .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2), .irq = IRQBASE+1, .flags = ASYNC_BOOT_AUTOCONF, }, +#endif +#ifdef MCFUART_BASE3 + { /* ttyS2 */ + .magic = 0, + .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3), + .irq = IRQBASE+2, + .flags = ASYNC_BOOT_AUTOCONF, + }, +#endif +#ifdef MCFUART_BASE4 + { /* ttyS3 */ + .magic = 0, + .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4), + .irq = IRQBASE+3, + .flags = ASYNC_BOOT_AUTOCONF, + }, +#endif }; @@ -1516,6 +1535,22 @@ static void mcfrs_irqinit(struct mcf_serial *info) imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); +#if defined(CONFIG_M527x) + { + /* + * External Pin Mask Setting & Enable External Pin for Interface + * mrcbis@aliceposta.it + */ + unsigned short *serpin_enable_mask; + serpin_enable_mask = (MCF_IPSBAR + MCF_GPIO_PAR_UART); + if (info->line == 0) + *serpin_enable_mask |= UART0_ENABLE_MASK; + else if (info->line == 1) + *serpin_enable_mask |= UART1_ENABLE_MASK; + else if (info->line == 2) + *serpin_enable_mask |= UART2_ENABLE_MASK; + } +#endif #elif defined(CONFIG_M520x) volatile unsigned char *icrp, *uartp; volatile unsigned long *imrp; @@ -1713,7 +1748,7 @@ mcfrs_init(void) /* Initialize the tty_driver structure */ mcfrs_serial_driver->owner = THIS_MODULE; mcfrs_serial_driver->name = "ttyS"; - mcfrs_serial_driver->driver_name = "serial"; + mcfrs_serial_driver->driver_name = "mcfserial"; mcfrs_serial_driver->major = TTY_MAJOR; mcfrs_serial_driver->minor_start = 64; mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; @@ -1797,10 +1832,23 @@ void mcfrs_init_console(void) uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8; uartp[MCFUART_UMR] = MCFUART_MR2_STOP1; +#ifdef CONFIG_M5272 +{ + /* + * For the MCF5272, also compute the baudrate fraction. + */ + int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud); + fraction *= 16; + fraction /= (32 * mcfrs_console_baud); + uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */ + clk = (MCF_BUSCLK / mcfrs_console_baud) / 32; +} +#else clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */ +#endif + uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8; /* set msb baud */ uartp[MCFUART_UBG2] = (clk & 0xff); /* set lsb baud */ - uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 00f9ffd6948..431433f4dd6 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -723,7 +723,7 @@ static int serial_config(struct pcmcia_device * link) u_char *buf; cisparse_t *parse; cistpl_cftable_entry_t *cf; - int i, last_ret, last_fn; + int i; DEBUG(0, "serial_config(0x%p)\n", link); @@ -740,15 +740,6 @@ static int serial_config(struct pcmcia_device * link) tuple->TupleOffset = 0; tuple->TupleDataMax = 255; tuple->Attributes = 0; - /* Get configuration register information */ - tuple->DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(link, tuple, parse); - if (last_ret != CS_SUCCESS) { - last_fn = ParseTuple; - goto cs_failed; - } - link->conf.ConfigBase = parse->config.base; - link->conf.Present = parse->config.rmask[0]; /* Is this a compliant multifunction card? */ tuple->DesiredTuple = CISTPL_LONGLINK_MFC; @@ -757,27 +748,25 @@ static int serial_config(struct pcmcia_device * link) /* Is this a multiport card? */ tuple->DesiredTuple = CISTPL_MANFID; - if (first_tuple(link, tuple, parse) == CS_SUCCESS) { - info->manfid = parse->manfid.manf; - info->prodid = parse->manfid.card; - - for (i = 0; i < ARRAY_SIZE(quirks); i++) - if ((quirks[i].manfid == ~0 || - quirks[i].manfid == info->manfid) && - (quirks[i].prodid == ~0 || - quirks[i].prodid == info->prodid)) { - info->quirk = &quirks[i]; - break; - } - } + info->manfid = link->manf_id; + info->prodid = link->card_id; + + for (i = 0; i < ARRAY_SIZE(quirks); i++) + if ((quirks[i].manfid == ~0 || + quirks[i].manfid == info->manfid) && + (quirks[i].prodid == ~0 || + quirks[i].prodid == info->prodid)) { + info->quirk = &quirks[i]; + break; + } /* Another check for dual-serial cards: look for either serial or multifunction cards that ask for appropriate IO port ranges */ tuple->DesiredTuple = CISTPL_FUNCID; if ((info->multi == 0) && - ((first_tuple(link, tuple, parse) != CS_SUCCESS) || - (parse->funcid.func == CISTPL_FUNCID_MULTI) || - (parse->funcid.func == CISTPL_FUNCID_SERIAL))) { + (link->has_func_id) && + ((link->func_id == CISTPL_FUNCID_MULTI) || + (link->func_id == CISTPL_FUNCID_SERIAL))) { tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; if (first_tuple(link, tuple, parse) == CS_SUCCESS) { if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) @@ -814,8 +803,6 @@ static int serial_config(struct pcmcia_device * link) kfree(cfg_mem); return 0; - cs_failed: - cs_error(link, last_fn, last_ret); failed: serial_remove(link); kfree(cfg_mem); @@ -925,6 +912,30 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"), PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"), PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "GLOBETROTTER.cis"), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100 1.00.",0x19ca78af,0xf964f42b), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232 1.00.",0x19ca78af,0x69fb7490), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767), + PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7), + PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41), + PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029), + PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), + PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc), + PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7), + PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41), + PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029), + PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), + PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), + PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), /* too generic */ /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */ /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */ diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index cfcc3caf49d..3b5f19ec212 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -775,7 +775,7 @@ static int sci_notifier(struct notifier_block *self, * * Clean this up later.. */ - clk = clk_get("module_clk"); + clk = clk_get(NULL, "module_clk"); port->uartclk = clk_get_rate(clk) * 16; clk_put(clk); } @@ -960,7 +960,7 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios, default: { #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) - struct clk *clk = clk_get("module_clk"); + struct clk *clk = clk_get(NULL, "module_clk"); t = SCBRR_VALUE(baud, clk_get_rate(clk)); clk_put(clk); #else @@ -1128,7 +1128,7 @@ static void __init sci_init_ports(void) * XXX: We should use a proper SCI/SCIF clock */ { - struct clk *clk = clk_get("module_clk"); + struct clk *clk = clk_get(NULL, "module_clk"); sci_ports[i].port.uartclk = clk_get_rate(clk) * 16; clk_put(clk); } diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 7ee992146ae..e4557cc4f74 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -133,6 +133,20 @@ # define SCIF_ORER 0x0001 /* Overrun error bit */ # define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7206) +# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */ +# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */ +# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */ +# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7619) +# define SCSPTR0 0xf8400020 /* 16 bit SCIF */ +# define SCSPTR1 0xf8410020 /* 16 bit SCIF */ +# define SCSPTR2 0xf8420020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY #else # error CPU subtype not defined #endif @@ -365,6 +379,7 @@ SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) #if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780) +SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) @@ -544,6 +559,28 @@ static inline int sci_rxd_in(struct uart_port *port) if (port->mapbase == 0xffe10000) return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ } +#elif defined(CONFIG_CPU_SUBTYPE_SH7206) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xfffe8000) + return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xfffe8800) + return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xfffe9000) + return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xfffe9800) + return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7619) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xf8400000) + return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xf8410000) + return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xf8420000) + return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ +} #endif /* diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 72025df5561..494d9b85648 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -148,7 +148,7 @@ struct chip_data { void (*cs_control)(u32 command); }; -static void pump_messages(void *data); +static void pump_messages(struct work_struct *work); static int flush(struct driver_data *drv_data) { @@ -884,9 +884,10 @@ static void pump_transfers(unsigned long data) } } -static void pump_messages(void *data) +static void pump_messages(struct work_struct *work) { - struct driver_data *drv_data = data; + struct driver_data *drv_data = + container_of(work, struct driver_data, pump_messages); unsigned long flags; /* Lock queue and check for queue work */ @@ -1098,7 +1099,7 @@ static int init_queue(struct driver_data *drv_data) tasklet_init(&drv_data->pump_transfers, pump_transfers, (unsigned long)drv_data); - INIT_WORK(&drv_data->pump_messages, pump_messages, drv_data); + INIT_WORK(&drv_data->pump_messages, pump_messages); drv_data->workqueue = create_singlethread_workqueue( drv_data->master->cdev.dev->bus_id); if (drv_data->workqueue == NULL) diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index a23862ef72b..08c1c57c612 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -265,9 +265,10 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) * Drivers can provide word-at-a-time i/o primitives, or provide * transfer-at-a-time ones to leverage dma or fifo hardware. */ -static void bitbang_work(void *_bitbang) +static void bitbang_work(struct work_struct *work) { - struct spi_bitbang *bitbang = _bitbang; + struct spi_bitbang *bitbang = + container_of(work, struct spi_bitbang, work); unsigned long flags; spin_lock_irqsave(&bitbang->lock, flags); @@ -456,7 +457,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) if (!bitbang->master || !bitbang->chipselect) return -EINVAL; - INIT_WORK(&bitbang->work, bitbang_work, bitbang); + INIT_WORK(&bitbang->work, bitbang_work); spin_lock_init(&bitbang->lock); INIT_LIST_HEAD(&bitbang->queue); diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index dda0ca45d90..164a5dcf1f1 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c @@ -69,25 +69,21 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static void ixj_get_serial(struct pcmcia_device * link, IXJ * j) { - tuple_t tuple; - u_short buf[128]; char *str; - int last_ret, last_fn, i, place; + int i, place; DEBUG(0, "ixj_get_serial(0x%p)\n", link); - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 80; - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_VERS_1; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - str = (char *) buf; - printk("PCMCIA Version %d.%d\n", str[0], str[1]); - str += 2; + + str = link->prod_id[0]; + if (!str) + goto cs_failed; printk("%s", str); - str = str + strlen(str) + 1; + str = link->prod_id[1]; + if (!str) + goto cs_failed; printk(" %s", str); - str = str + strlen(str) + 1; + str = link->prod_id[2]; + if (!str) + goto cs_failed; place = 1; for (i = strlen(str) - 1; i >= 0; i--) { switch (str[i]) { @@ -122,7 +118,9 @@ static void ixj_get_serial(struct pcmcia_device * link, IXJ * j) } place = place * 0x10; } - str = str + strlen(str) + 1; + str = link->prod_id[3]; + if (!str) + goto cs_failed; printk(" version %s\n", str); cs_failed: return; @@ -146,13 +144,6 @@ static int ixj_config(struct pcmcia_device * link) tuple.TupleData = (cisdata_t *) buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index e6565633ba0..3dfa3e40e14 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -158,7 +158,7 @@ struct cxacru_data { const struct cxacru_modem_type *modem_type; int line_status; - struct work_struct poll_work; + struct delayed_work poll_work; /* contol handles */ struct mutex cm_serialize; @@ -347,7 +347,7 @@ static int cxacru_card_status(struct cxacru_data *instance) return 0; } -static void cxacru_poll_status(struct cxacru_data *instance); +static void cxacru_poll_status(struct work_struct *work); static int cxacru_atm_start(struct usbatm_data *usbatm_instance, struct atm_dev *atm_dev) @@ -376,12 +376,14 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, } /* Start status polling */ - cxacru_poll_status(instance); + cxacru_poll_status(&instance->poll_work.work); return 0; } -static void cxacru_poll_status(struct cxacru_data *instance) +static void cxacru_poll_status(struct work_struct *work) { + struct cxacru_data *instance = + container_of(work, struct cxacru_data, poll_work.work); u32 buf[CXINF_MAX] = {}; struct usbatm_data *usbatm = instance->usbatm; struct atm_dev *atm_dev = usbatm->atm_dev; @@ -720,7 +722,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, mutex_init(&instance->cm_serialize); - INIT_WORK(&instance->poll_work, (void *)cxacru_poll_status, instance); + INIT_DELAYED_WORK(&instance->poll_work, cxacru_poll_status); usbatm_instance->driver_data = instance; diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index a823486495c..8ed6c75adf0 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -142,7 +142,7 @@ struct speedtch_instance_data { struct speedtch_params params; /* set in probe, constant afterwards */ - struct work_struct status_checker; + struct delayed_work status_checker; unsigned char last_status; @@ -498,8 +498,11 @@ static int speedtch_start_synchro(struct speedtch_instance_data *instance) return ret; } -static void speedtch_check_status(struct speedtch_instance_data *instance) +static void speedtch_check_status(struct work_struct *work) { + struct speedtch_instance_data *instance = + container_of(work, struct speedtch_instance_data, + status_checker.work); struct usbatm_data *usbatm = instance->usbatm; struct atm_dev *atm_dev = usbatm->atm_dev; unsigned char *buf = instance->scratch_buffer; @@ -576,7 +579,7 @@ static void speedtch_status_poll(unsigned long data) { struct speedtch_instance_data *instance = (void *)data; - schedule_work(&instance->status_checker); + schedule_delayed_work(&instance->status_checker, 0); /* The following check is racy, but the race is harmless */ if (instance->poll_delay < MAX_POLL_DELAY) @@ -596,7 +599,7 @@ static void speedtch_resubmit_int(unsigned long data) if (int_urb) { ret = usb_submit_urb(int_urb, GFP_ATOMIC); if (!ret) - schedule_work(&instance->status_checker); + schedule_delayed_work(&instance->status_checker, 0); else { atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY)); @@ -640,7 +643,7 @@ static void speedtch_handle_int(struct urb *int_urb) if ((int_urb = instance->int_urb)) { ret = usb_submit_urb(int_urb, GFP_ATOMIC); - schedule_work(&instance->status_checker); + schedule_delayed_work(&instance->status_checker, 0); if (ret < 0) { atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); goto fail; @@ -855,7 +858,7 @@ static int speedtch_bind(struct usbatm_data *usbatm, usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); - INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance); + INIT_DELAYED_WORK(&instance->status_checker, speedtch_check_status); instance->status_checker.timer.function = speedtch_status_poll; instance->status_checker.timer.data = (unsigned long)instance; diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index c137c041f7a..f2d196fa1e8 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -655,9 +655,9 @@ static int request_dsp(struct uea_softc *sc) /* * The uea_load_page() function must be called within a process context */ -static void uea_load_page(void *xsc) +static void uea_load_page(struct work_struct *work) { - struct uea_softc *sc = xsc; + struct uea_softc *sc = container_of(work, struct uea_softc, task); u16 pageno = sc->pageno; u16 ovl = sc->ovl; struct block_info bi; @@ -1348,7 +1348,7 @@ static int uea_boot(struct uea_softc *sc) uea_enters(INS_TO_USBDEV(sc)); - INIT_WORK(&sc->task, uea_load_page, sc); + INIT_WORK(&sc->task, uea_load_page); init_waitqueue_head(&sc->sync_q); init_waitqueue_head(&sc->cmv_ack_wait); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ec3438dc8ee..7f1fa956dcd 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -421,9 +421,9 @@ static void acm_write_bulk(struct urb *urb) schedule_work(&acm->work); } -static void acm_softint(void *private) +static void acm_softint(struct work_struct *work) { - struct acm *acm = private; + struct acm *acm = container_of(work, struct acm, work); dbg("Entering acm_softint."); if (!ACM_READY(acm)) @@ -927,7 +927,7 @@ skip_normal_probe: acm->rx_buflimit = num_rx_buf; acm->urb_task.func = acm_rx_tasklet; acm->urb_task.data = (unsigned long) acm; - INIT_WORK(&acm->work, acm_softint, acm); + INIT_WORK(&acm->work, acm_softint); spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0ce393eb3c4..9be41ed1f9a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -68,7 +68,7 @@ struct usb_hub { unsigned has_indicators:1; u8 indicator[USB_MAXCHILDREN]; - struct work_struct leds; + struct delayed_work leds; }; @@ -218,9 +218,10 @@ static void set_port_led( #define LED_CYCLE_PERIOD ((2*HZ)/3) -static void led_work (void *__hub) +static void led_work (struct work_struct *work) { - struct usb_hub *hub = __hub; + struct usb_hub *hub = + container_of(work, struct usb_hub, leds.work); struct usb_device *hdev = hub->hdev; unsigned i; unsigned changed = 0; @@ -405,9 +406,10 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) * talking to TTs must queue control transfers (not just bulk and iso), so * both can talk to the same hub concurrently. */ -static void hub_tt_kevent (void *arg) +static void hub_tt_kevent (struct work_struct *work) { - struct usb_hub *hub = arg; + struct usb_hub *hub = + container_of(work, struct usb_hub, tt.kevent); unsigned long flags; spin_lock_irqsave (&hub->tt.lock, flags); @@ -694,7 +696,7 @@ static int hub_configure(struct usb_hub *hub, spin_lock_init (&hub->tt.lock); INIT_LIST_HEAD (&hub->tt.clear_list); - INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub); + INIT_WORK (&hub->tt.kevent, hub_tt_kevent); switch (hdev->descriptor.bDeviceProtocol) { case 0: break; @@ -938,7 +940,7 @@ descriptor_error: INIT_LIST_HEAD(&hub->event_list); hub->intfdev = &intf->dev; hub->hdev = hdev; - INIT_WORK(&hub->leds, led_work, hub); + INIT_DELAYED_WORK(&hub->leds, led_work); usb_set_intfdata (intf, hub); intf->needs_remote_wakeup = 1; @@ -2381,7 +2383,7 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) /* hub LEDs are probably harder to miss than syslog */ if (hub->has_indicators) { hub->indicator[port1-1] = INDICATOR_GREEN_BLINK; - schedule_work (&hub->leds); + schedule_delayed_work (&hub->leds, 0); } } kfree(qual); @@ -2555,7 +2557,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (hub->has_indicators) { hub->indicator[port1-1] = INDICATOR_AMBER_BLINK; - schedule_work (&hub->leds); + schedule_delayed_work (&hub->leds, 0); } status = -ENOTCONN; /* Don't retry */ goto loop_disable; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 29b0fa9ff9d..7390b67c609 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1501,9 +1501,10 @@ struct set_config_request { }; /* Worker routine for usb_driver_set_configuration() */ -static void driver_set_config_work(void *_req) +static void driver_set_config_work(struct work_struct *work) { - struct set_config_request *req = _req; + struct set_config_request *req = + container_of(work, struct set_config_request, work); usb_lock_device(req->udev); usb_set_configuration(req->udev, req->config); @@ -1541,7 +1542,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config) return -ENOMEM; req->udev = udev; req->config = config; - INIT_WORK(&req->work, driver_set_config_work, req); + INIT_WORK(&req->work, driver_set_config_work); usb_get_dev(udev); if (!schedule_work(&req->work)) { diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 81cb52564e6..02426d0b9a3 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -203,9 +203,10 @@ static void ksuspend_usb_cleanup(void) #ifdef CONFIG_USB_SUSPEND /* usb_autosuspend_work - callback routine to autosuspend a USB device */ -static void usb_autosuspend_work(void *_udev) +static void usb_autosuspend_work(struct work_struct *work) { - struct usb_device *udev = _udev; + struct usb_device *udev = + container_of(work, struct usb_device, autosuspend.work); usb_pm_lock(udev); udev->auto_pm = 1; @@ -215,7 +216,7 @@ static void usb_autosuspend_work(void *_udev) #else -static void usb_autosuspend_work(void *_udev) +static void usb_autosuspend_work(struct work_struct *work) {} #endif /* CONFIG_USB_SUSPEND */ @@ -304,7 +305,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) #ifdef CONFIG_PM mutex_init(&dev->pm_mutex); - INIT_WORK(&dev->autosuspend, usb_autosuspend_work, dev); + INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); #endif return dev; } diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 3bd1dfe565c..d15bf22b9a0 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1833,9 +1833,9 @@ static void rx_fill (struct eth_dev *dev, gfp_t gfp_flags) spin_unlock_irqrestore(&dev->req_lock, flags); } -static void eth_work (void *_dev) +static void eth_work (struct work_struct *work) { - struct eth_dev *dev = _dev; + struct eth_dev *dev = container_of(work, struct eth_dev, work); if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) { if (netif_running (dev->net)) @@ -2398,7 +2398,7 @@ autoconf_fail: dev = netdev_priv(net); spin_lock_init (&dev->lock); spin_lock_init (&dev->req_lock); - INIT_WORK (&dev->work, eth_work, dev); + INIT_WORK (&dev->work, eth_work); INIT_LIST_HEAD (&dev->tx_reqs); INIT_LIST_HEAD (&dev->rx_reqs); diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 54f554e0f0a..ac9f11d1981 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -169,21 +169,14 @@ static int sl811_cs_config(struct pcmcia_device *link) DBG(0, "sl811_cs_config(0x%p)\n", link); - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf)); + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index ef54e310bfc..a9d7119e317 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -163,7 +163,7 @@ struct u132_endp { u16 queue_next; struct urb *urb_list[ENDP_QUEUE_SIZE]; struct list_head urb_more; - struct work_struct scheduler; + struct delayed_work scheduler; }; struct u132_ring { unsigned in_use:1; @@ -171,7 +171,7 @@ struct u132_ring { u8 number; struct u132 *u132; struct u132_endp *curr_endp; - struct work_struct scheduler; + struct delayed_work scheduler; }; #define OHCI_QUIRK_AMD756 0x01 #define OHCI_QUIRK_SUPERIO 0x02 @@ -198,7 +198,7 @@ struct u132 { u32 hc_roothub_portstatus[MAX_ROOT_PORTS]; int flags; unsigned long next_statechange; - struct work_struct monitor; + struct delayed_work monitor; int num_endpoints; struct u132_addr addr[MAX_U132_ADDRS]; struct u132_udev udev[MAX_U132_UDEVS]; @@ -310,7 +310,7 @@ static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, if (delta > 0) { if (queue_delayed_work(workqueue, &ring->scheduler, delta)) return; - } else if (queue_work(workqueue, &ring->scheduler)) + } else if (queue_delayed_work(workqueue, &ring->scheduler, 0)) return; kref_put(&u132->kref, u132_hcd_delete); return; @@ -389,12 +389,8 @@ static inline void u132_endp_init_kref(struct u132 *u132, static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(workqueue, &endp->scheduler, delta)) - kref_get(&endp->kref); - } else if (queue_work(workqueue, &endp->scheduler)) - kref_get(&endp->kref); - return; + if (queue_delayed_work(workqueue, &endp->scheduler, delta)) + kref_get(&endp->kref); } static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp) @@ -410,24 +406,14 @@ static inline void u132_monitor_put_kref(struct u132 *u132) static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(workqueue, &u132->monitor, delta)) { - kref_get(&u132->kref); - } - } else if (queue_work(workqueue, &u132->monitor)) - kref_get(&u132->kref); - return; + if (queue_delayed_work(workqueue, &u132->monitor, delta)) + kref_get(&u132->kref); } static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(workqueue, &u132->monitor, delta)) - return; - } else if (queue_work(workqueue, &u132->monitor)) - return; - kref_put(&u132->kref, u132_hcd_delete); - return; + if (!queue_delayed_work(workqueue, &u132->monitor, delta)) + kref_put(&u132->kref, u132_hcd_delete); } static void u132_monitor_cancel_work(struct u132 *u132) @@ -489,9 +475,9 @@ static int read_roothub_info(struct u132 *u132) return 0; } -static void u132_hcd_monitor_work(void *data) +static void u132_hcd_monitor_work(struct work_struct *work) { - struct u132 *u132 = data; + struct u132 *u132 = container_of(work, struct u132, monitor.work); if (u132->going > 1) { dev_err(&u132->platform_dev->dev, "device has been removed %d\n" , u132->going); @@ -1315,15 +1301,14 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, } } -static void u132_hcd_ring_work_scheduler(void *data); -static void u132_hcd_endp_work_scheduler(void *data); /* * this work function is only executed from the work queue * */ -static void u132_hcd_ring_work_scheduler(void *data) +static void u132_hcd_ring_work_scheduler(struct work_struct *work) { - struct u132_ring *ring = data; + struct u132_ring *ring = + container_of(work, struct u132_ring, scheduler.work); struct u132 *u132 = ring->u132; down(&u132->scheduler_lock); if (ring->in_use) { @@ -1382,10 +1367,11 @@ static void u132_hcd_ring_work_scheduler(void *data) } } -static void u132_hcd_endp_work_scheduler(void *data) +static void u132_hcd_endp_work_scheduler(struct work_struct *work) { struct u132_ring *ring; - struct u132_endp *endp = data; + struct u132_endp *endp = + container_of(work, struct u132_endp, scheduler.work); struct u132 *u132 = endp->u132; down(&u132->scheduler_lock); ring = endp->ring; @@ -1943,7 +1929,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132, if (!endp) { return -ENOMEM; } - INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; @@ -2032,7 +2018,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, if (!endp) { return -ENOMEM; } - INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); endp->dequeueing = 0; @@ -2117,7 +2103,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132, if (!endp) { return -ENOMEM; } - INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; @@ -3096,10 +3082,10 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) ring->number = rings + 1; ring->length = 0; ring->curr_endp = NULL; - INIT_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler, - (void *)ring); + INIT_DELAYED_WORK(&ring->scheduler, + u132_hcd_ring_work_scheduler); } down(&u132->sw_lock); - INIT_WORK(&u132->monitor, u132_hcd_monitor_work, (void *)u132); + INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); while (ports-- > 0) { struct u132_port *port = &u132->port[ports]; port->u132 = u132; diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index a49644b7c58..4295bab4f1e 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -969,9 +969,10 @@ static void hid_retry_timeout(unsigned long _hid) } /* Workqueue routine to reset the device or clear a halt */ -static void hid_reset(void *_hid) +static void hid_reset(struct work_struct *work) { - struct hid_device *hid = (struct hid_device *) _hid; + struct hid_device *hid = + container_of(work, struct hid_device, reset_work); int rc_lock, rc = 0; if (test_bit(HID_CLEAR_HALT, &hid->iofl)) { @@ -2043,7 +2044,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) init_waitqueue_head(&hid->wait); - INIT_WORK(&hid->reset_work, hid_reset, hid); + INIT_WORK(&hid->reset_work, hid_reset); setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid); spin_lock_init(&hid->inlock); diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index ba30ca6a14a..02cbb7fff24 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -76,7 +76,7 @@ struct appledisplay { char *urbdata; /* interrupt URB data buffer */ char *msgdata; /* control message data buffer */ - struct work_struct work; + struct delayed_work work; int button_pressed; spinlock_t lock; }; @@ -117,7 +117,7 @@ static void appledisplay_complete(struct urb *urb) case ACD_BTN_BRIGHT_UP: case ACD_BTN_BRIGHT_DOWN: pdata->button_pressed = 1; - queue_work(wq, &pdata->work); + queue_delayed_work(wq, &pdata->work, 0); break; case ACD_BTN_NONE: default: @@ -184,9 +184,10 @@ static struct backlight_properties appledisplay_bl_data = { .max_brightness = 0xFF }; -static void appledisplay_work(void *private) +static void appledisplay_work(struct work_struct *work) { - struct appledisplay *pdata = private; + struct appledisplay *pdata = + container_of(work, struct appledisplay, work.work); int retval; up(&pdata->bd->sem); @@ -238,7 +239,7 @@ static int appledisplay_probe(struct usb_interface *iface, pdata->udev = udev; spin_lock_init(&pdata->lock); - INIT_WORK(&pdata->work, appledisplay_work, pdata); + INIT_DELAYED_WORK(&pdata->work, appledisplay_work); /* Allocate buffer for control messages */ pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL); diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index cb0ba3107d7..18b1925032a 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -156,9 +156,9 @@ struct usb_ftdi { struct usb_device *udev; struct usb_interface *interface; struct usb_class_driver *class; - struct work_struct status_work; - struct work_struct command_work; - struct work_struct respond_work; + struct delayed_work status_work; + struct delayed_work command_work; + struct delayed_work respond_work; struct u132_platform_data platform_data; struct resource resources[0]; struct platform_device platform_dev; @@ -210,23 +210,14 @@ static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) - return; - } else if (queue_work(status_queue, &ftdi->status_work)) - return; - kref_put(&ftdi->kref, ftdi_elan_delete); - return; + if (!queue_delayed_work(status_queue, &ftdi->status_work, delta)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) - kref_get(&ftdi->kref); - } else if (queue_work(status_queue, &ftdi->status_work)) - kref_get(&ftdi->kref); - return; + if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) + kref_get(&ftdi->kref); } static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) @@ -237,25 +228,14 @@ static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(command_queue, &ftdi->command_work, - delta)) - return; - } else if (queue_work(command_queue, &ftdi->command_work)) - return; - kref_put(&ftdi->kref, ftdi_elan_delete); - return; + if (!queue_delayed_work(command_queue, &ftdi->command_work, delta)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(command_queue, &ftdi->command_work, - delta)) - kref_get(&ftdi->kref); - } else if (queue_work(command_queue, &ftdi->command_work)) - kref_get(&ftdi->kref); - return; + if (queue_delayed_work(command_queue, &ftdi->command_work, delta)) + kref_get(&ftdi->kref); } static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) @@ -267,25 +247,14 @@ static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(respond_queue, &ftdi->respond_work, - delta)) - return; - } else if (queue_work(respond_queue, &ftdi->respond_work)) - return; - kref_put(&ftdi->kref, ftdi_elan_delete); - return; + if (!queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(respond_queue, &ftdi->respond_work, - delta)) - kref_get(&ftdi->kref); - } else if (queue_work(respond_queue, &ftdi->respond_work)) - kref_get(&ftdi->kref); - return; + if (queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) + kref_get(&ftdi->kref); } static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) @@ -475,9 +444,11 @@ static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) return; } -static void ftdi_elan_command_work(void *data) +static void ftdi_elan_command_work(struct work_struct *work) { - struct usb_ftdi *ftdi = data; + struct usb_ftdi *ftdi = + container_of(work, struct usb_ftdi, command_work.work); + if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); return; @@ -500,9 +471,10 @@ static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) return; } -static void ftdi_elan_respond_work(void *data) +static void ftdi_elan_respond_work(struct work_struct *work) { - struct usb_ftdi *ftdi = data; + struct usb_ftdi *ftdi = + container_of(work, struct usb_ftdi, respond_work.work); if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); return; @@ -534,9 +506,10 @@ static void ftdi_elan_respond_work(void *data) * after the FTDI has been synchronized * */ -static void ftdi_elan_status_work(void *data) +static void ftdi_elan_status_work(struct work_struct *work) { - struct usb_ftdi *ftdi = data; + struct usb_ftdi *ftdi = + container_of(work, struct usb_ftdi, status_work.work); int work_delay_in_msec = 0; if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); @@ -2677,12 +2650,9 @@ static int ftdi_elan_probe(struct usb_interface *interface, ftdi->class = NULL; dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a" "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber); - INIT_WORK(&ftdi->status_work, ftdi_elan_status_work, - (void *)ftdi); - INIT_WORK(&ftdi->command_work, ftdi_elan_command_work, - (void *)ftdi); - INIT_WORK(&ftdi->respond_work, ftdi_elan_respond_work, - (void *)ftdi); + INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); + INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); + INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); return 0; } else { diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index 9110793f81d..9659c79e187 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -81,8 +81,8 @@ struct interfacekit { unsigned char *data; dma_addr_t data_dma; - struct work_struct do_notify; - struct work_struct do_resubmit; + struct delayed_work do_notify; + struct delayed_work do_resubmit; unsigned long input_events; unsigned long sensor_events; }; @@ -374,7 +374,7 @@ static void interfacekit_irq(struct urb *urb) } if (kit->input_events || kit->sensor_events) - schedule_work(&kit->do_notify); + schedule_delayed_work(&kit->do_notify, 0); resubmit: status = usb_submit_urb(urb, SLAB_ATOMIC); @@ -384,9 +384,10 @@ resubmit: kit->udev->devpath, status); } -static void do_notify(void *data) +static void do_notify(struct work_struct *work) { - struct interfacekit *kit = data; + struct interfacekit *kit = + container_of(work, struct interfacekit, do_notify.work); int i; char sysfs_file[8]; @@ -405,9 +406,11 @@ static void do_notify(void *data) } } -static void do_resubmit(void *data) +static void do_resubmit(struct work_struct *work) { - set_outputs(data); + struct interfacekit *kit = + container_of(work, struct interfacekit, do_resubmit.work); + set_outputs(kit); } #define show_set_output(value) \ @@ -575,8 +578,8 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic kit->udev = usb_get_dev(dev); kit->intf = intf; - INIT_WORK(&kit->do_notify, do_notify, kit); - INIT_WORK(&kit->do_resubmit, do_resubmit, kit); + INIT_DELAYED_WORK(&kit->do_notify, do_notify); + INIT_DELAYED_WORK(&kit->do_resubmit, do_resubmit); usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data, maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp, interfacekit_irq, kit, endpoint->bInterval); diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c index c3469b0a67c..2bb4fa572bb 100644 --- a/drivers/usb/misc/phidgetmotorcontrol.c +++ b/drivers/usb/misc/phidgetmotorcontrol.c @@ -41,7 +41,7 @@ struct motorcontrol { unsigned char *data; dma_addr_t data_dma; - struct work_struct do_notify; + struct delayed_work do_notify; unsigned long input_events; unsigned long speed_events; unsigned long exceed_events; @@ -148,7 +148,7 @@ static void motorcontrol_irq(struct urb *urb) set_bit(1, &mc->exceed_events); if (mc->input_events || mc->exceed_events || mc->speed_events) - schedule_work(&mc->do_notify); + schedule_delayed_work(&mc->do_notify, 0); resubmit: status = usb_submit_urb(urb, SLAB_ATOMIC); @@ -159,9 +159,10 @@ resubmit: mc->udev->devpath, status); } -static void do_notify(void *data) +static void do_notify(struct work_struct *work) { - struct motorcontrol *mc = data; + struct motorcontrol *mc = + container_of(work, struct motorcontrol, do_notify.work); int i; char sysfs_file[8]; @@ -348,7 +349,7 @@ static int motorcontrol_probe(struct usb_interface *intf, const struct usb_devic mc->udev = usb_get_dev(dev); mc->intf = intf; mc->acceleration[0] = mc->acceleration[1] = 10; - INIT_WORK(&mc->do_notify, do_notify, mc); + INIT_DELAYED_WORK(&mc->do_notify, do_notify); usb_fill_int_urb(mc->irq, mc->udev, pipe, mc->data, maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp, motorcontrol_irq, mc, endpoint->bInterval); diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 7c906a43e49..fa78326d0bf 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -222,7 +222,7 @@ struct kaweth_device int suspend_lowmem_ctrl; int linkstate; int opened; - struct work_struct lowmem_work; + struct delayed_work lowmem_work; struct usb_device *dev; struct net_device *net; @@ -530,9 +530,10 @@ resubmit: kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC); } -static void kaweth_resubmit_tl(void *d) +static void kaweth_resubmit_tl(struct work_struct *work) { - struct kaweth_device *kaweth = (struct kaweth_device *)d; + struct kaweth_device *kaweth = + container_of(work, struct kaweth_device, lowmem_work.work); if (IS_BLOCKED(kaweth->status)) return; @@ -1126,7 +1127,7 @@ err_fw: /* kaweth is zeroed as part of alloc_netdev */ - INIT_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl, (void *)kaweth); + INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); SET_MODULE_OWNER(netdev); diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 69eb0db399d..b5690b3834e 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -1281,9 +1281,9 @@ static inline void setup_pegasus_II(pegasus_t * pegasus) static struct workqueue_struct *pegasus_workqueue = NULL; #define CARRIER_CHECK_DELAY (2 * HZ) -static void check_carrier(void *data) +static void check_carrier(struct work_struct *work) { - pegasus_t *pegasus = data; + pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work); set_carrier(pegasus->net); if (!(pegasus->flags & PEGASUS_UNPLUG)) { queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, @@ -1319,7 +1319,7 @@ static int pegasus_probe(struct usb_interface *intf, tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus); - INIT_WORK(&pegasus->carrier_check, check_carrier, pegasus); + INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier); pegasus->intf = intf; pegasus->usb = dev; diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index 006438069b6..98f6898cae1 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -95,7 +95,7 @@ typedef struct pegasus { int dev_index; int intr_interval; struct tasklet_struct rx_tl; - struct work_struct carrier_check; + struct delayed_work carrier_check; struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb; struct sk_buff *rx_pool[RX_SKBS]; struct sk_buff *rx_skb; diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 7672e11c94c..327f9755567 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -782,9 +782,10 @@ static struct ethtool_ops usbnet_ethtool_ops = { * especially now that control transfers can be queued. */ static void -kevent (void *data) +kevent (struct work_struct *work) { - struct usbnet *dev = data; + struct usbnet *dev = + container_of(work, struct usbnet, kevent); int status; /* usb_clear_halt() needs a thread context */ @@ -1146,7 +1147,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) skb_queue_head_init (&dev->done); dev->bh.func = usbnet_bh; dev->bh.data = (unsigned long) dev; - INIT_WORK (&dev->kevent, kevent, dev); + INIT_WORK (&dev->kevent, kevent); dev->delay.function = usbnet_bh; dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index b1b5707bc99..86bcf63b6ba 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -92,6 +92,7 @@ struct aircable_private { struct circ_buf *rx_buf; /* read buffer */ int rx_flags; /* for throttilng */ struct work_struct rx_work; /* work cue for the receiving line */ + struct usb_serial_port *port; /* USB port with which associated */ }; /* Private methods */ @@ -251,10 +252,11 @@ static void aircable_send(struct usb_serial_port *port) schedule_work(&port->work); } -static void aircable_read(void *params) +static void aircable_read(struct work_struct *work) { - struct usb_serial_port *port = params; - struct aircable_private *priv = usb_get_serial_port_data(port); + struct aircable_private *priv = + container_of(work, struct aircable_private, rx_work); + struct usb_serial_port *port = priv->port; struct tty_struct *tty; unsigned char *data; int count; @@ -349,7 +351,8 @@ static int aircable_attach (struct usb_serial *serial) } priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - INIT_WORK(&priv->rx_work, aircable_read, port); + priv->port = port; + INIT_WORK(&priv->rx_work, aircable_read); usb_set_serial_port_data(serial->port[0], priv); @@ -516,7 +519,7 @@ static void aircable_read_bulk_callback(struct urb *urb) package_length - shift); } } - aircable_read(port); + aircable_read(&priv->rx_work); } /* Schedule the next read _if_ we are still open */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 5e3ac281a2f..83d0e21145b 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -430,13 +430,14 @@ struct digi_port { int dp_in_close; /* close in progress */ wait_queue_head_t dp_close_wait; /* wait queue for close */ struct work_struct dp_wakeup_work; + struct usb_serial_port *dp_port; }; /* Local Function Declarations */ static void digi_wakeup_write( struct usb_serial_port *port ); -static void digi_wakeup_write_lock(void *); +static void digi_wakeup_write_lock(struct work_struct *work); static int digi_write_oob_command( struct usb_serial_port *port, unsigned char *buf, int count, int interruptible ); static int digi_write_inb_command( struct usb_serial_port *port, @@ -598,11 +599,12 @@ static inline long cond_wait_interruptible_timeout_irqrestore( * on writes. */ -static void digi_wakeup_write_lock(void *arg) +static void digi_wakeup_write_lock(struct work_struct *work) { - struct usb_serial_port *port = arg; + struct digi_port *priv = + container_of(work, struct digi_port, dp_wakeup_work); + struct usb_serial_port *port = priv->dp_port; unsigned long flags; - struct digi_port *priv = usb_get_serial_port_data(port); spin_lock_irqsave( &priv->dp_port_lock, flags ); @@ -1702,8 +1704,8 @@ dbg( "digi_startup: TOP" ); init_waitqueue_head( &priv->dp_flush_wait ); priv->dp_in_close = 0; init_waitqueue_head( &priv->dp_close_wait ); - INIT_WORK(&priv->dp_wakeup_work, - digi_wakeup_write_lock, serial->port[i]); + INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); + priv->dp_port = serial->port[i]; /* initialize write wait queue for this port */ init_waitqueue_head( &serial->port[i]->write_wait ); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 89ce2775be1..72e4d48f51e 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -559,7 +559,8 @@ struct ftdi_private { char prev_status, diff_status; /* Used for TIOCMIWAIT */ __u8 rx_flags; /* receive state flags (throttling) */ spinlock_t rx_lock; /* spinlock for receive state */ - struct work_struct rx_work; + struct delayed_work rx_work; + struct usb_serial_port *port; int rx_processed; unsigned long rx_bytes; @@ -593,7 +594,7 @@ static int ftdi_write_room (struct usb_serial_port *port); static int ftdi_chars_in_buffer (struct usb_serial_port *port); static void ftdi_write_bulk_callback (struct urb *urb); static void ftdi_read_bulk_callback (struct urb *urb); -static void ftdi_process_read (void *param); +static void ftdi_process_read (struct work_struct *work); static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old); static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file); static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear); @@ -1201,7 +1202,8 @@ static int ftdi_sio_attach (struct usb_serial *serial) port->read_urb->transfer_buffer_length = BUFSZ; } - INIT_WORK(&priv->rx_work, ftdi_process_read, port); + INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read); + priv->port = port; /* Free port's existing write urb and transfer buffer. */ if (port->write_urb) { @@ -1640,17 +1642,18 @@ static void ftdi_read_bulk_callback (struct urb *urb) priv->rx_bytes += countread; spin_unlock_irqrestore(&priv->rx_lock, flags); - ftdi_process_read(port); + ftdi_process_read(&priv->rx_work.work); } /* ftdi_read_bulk_callback */ -static void ftdi_process_read (void *param) +static void ftdi_process_read (struct work_struct *work) { /* ftdi_process_read */ - struct usb_serial_port *port = (struct usb_serial_port*)param; + struct ftdi_private *priv = + container_of(work, struct ftdi_private, rx_work.work); + struct usb_serial_port *port = priv->port; struct urb *urb; struct tty_struct *tty; - struct ftdi_private *priv; char error_flag; unsigned char *data; @@ -2179,7 +2182,7 @@ static void ftdi_unthrottle (struct usb_serial_port *port) spin_unlock_irqrestore(&priv->rx_lock, flags); if (actually_throttled) - schedule_work(&priv->rx_work); + schedule_delayed_work(&priv->rx_work, 0); } static int __init ftdi_init (void) diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 909005107ea..e09a0bfe623 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -120,6 +120,8 @@ struct keyspan_pda_private { int tx_throttled; struct work_struct wakeup_work; struct work_struct unthrottle_work; + struct usb_serial *serial; + struct usb_serial_port *port; }; @@ -175,9 +177,11 @@ static struct usb_device_id id_table_fake_xircom [] = { }; #endif -static void keyspan_pda_wakeup_write( struct usb_serial_port *port ) +static void keyspan_pda_wakeup_write(struct work_struct *work) { - + struct keyspan_pda_private *priv = + container_of(work, struct keyspan_pda_private, wakeup_work); + struct usb_serial_port *port = priv->port; struct tty_struct *tty = port->tty; /* wake up port processes */ @@ -187,8 +191,11 @@ static void keyspan_pda_wakeup_write( struct usb_serial_port *port ) tty_wakeup(tty); } -static void keyspan_pda_request_unthrottle( struct usb_serial *serial ) +static void keyspan_pda_request_unthrottle(struct work_struct *work) { + struct keyspan_pda_private *priv = + container_of(work, struct keyspan_pda_private, unthrottle_work); + struct usb_serial *serial = priv->serial; int result; dbg(" request_unthrottle"); @@ -765,11 +772,10 @@ static int keyspan_pda_startup (struct usb_serial *serial) return (1); /* error */ usb_set_serial_port_data(serial->port[0], priv); init_waitqueue_head(&serial->port[0]->write_wait); - INIT_WORK(&priv->wakeup_work, (void *)keyspan_pda_wakeup_write, - (void *)(serial->port[0])); - INIT_WORK(&priv->unthrottle_work, - (void *)keyspan_pda_request_unthrottle, - (void *)(serial)); + INIT_WORK(&priv->wakeup_work, keyspan_pda_wakeup_write); + INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle); + priv->serial = serial; + priv->port = serial->port[0]; return (0); } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index c1257d5292f..3d5072f14b8 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -533,9 +533,10 @@ void usb_serial_port_softint(struct usb_serial_port *port) schedule_work(&port->work); } -static void usb_serial_port_work(void *private) +static void usb_serial_port_work(struct work_struct *work) { - struct usb_serial_port *port = private; + struct usb_serial_port *port = + container_of(work, struct usb_serial_port, work); struct tty_struct *tty; dbg("%s - port %d", __FUNCTION__, port->number); @@ -799,7 +800,7 @@ int usb_serial_probe(struct usb_interface *interface, port->serial = serial; spin_lock_init(&port->lock); mutex_init(&port->mutex); - INIT_WORK(&port->work, usb_serial_port_work, port); + INIT_WORK(&port->work, usb_serial_port_work); serial->port[i] = port; } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 4d1cd7aeccd..154c7d29059 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -227,6 +227,7 @@ struct whiteheat_private { struct list_head rx_urbs_submitted; struct list_head rx_urb_q; struct work_struct rx_work; + struct usb_serial_port *port; struct list_head tx_urbs_free; struct list_head tx_urbs_submitted; }; @@ -241,7 +242,7 @@ static void command_port_read_callback(struct urb *urb); static int start_port_read(struct usb_serial_port *port); static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, struct list_head *head); static struct list_head *list_first(struct list_head *head); -static void rx_data_softint(void *private); +static void rx_data_softint(struct work_struct *work); static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize); static int firm_open(struct usb_serial_port *port); @@ -424,7 +425,8 @@ static int whiteheat_attach (struct usb_serial *serial) spin_lock_init(&info->lock); info->flags = 0; info->mcr = 0; - INIT_WORK(&info->rx_work, rx_data_softint, port); + INIT_WORK(&info->rx_work, rx_data_softint); + info->port = port; INIT_LIST_HEAD(&info->rx_urbs_free); INIT_LIST_HEAD(&info->rx_urbs_submitted); @@ -949,7 +951,7 @@ static void whiteheat_unthrottle (struct usb_serial_port *port) spin_unlock_irqrestore(&info->lock, flags); if (actually_throttled) - rx_data_softint(port); + rx_data_softint(&info->rx_work); return; } @@ -1400,10 +1402,11 @@ static struct list_head *list_first(struct list_head *head) } -static void rx_data_softint(void *private) +static void rx_data_softint(struct work_struct *work) { - struct usb_serial_port *port = (struct usb_serial_port *)private; - struct whiteheat_private *info = usb_get_serial_port_data(port); + struct whiteheat_private *info = + container_of(work, struct whiteheat_private, rx_work); + struct usb_serial_port *port = info->port; struct tty_struct *tty = port->tty; struct whiteheat_urb_wrap *wrap; struct urb *urb; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 302174b8e47..31f476a6479 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -383,9 +383,9 @@ static void fbcon_update_softback(struct vc_data *vc) softback_top = 0; } -static void fb_flashcursor(void *private) +static void fb_flashcursor(struct work_struct *work) { - struct fb_info *info = private; + struct fb_info *info = container_of(work, struct fb_info, queue); struct fbcon_ops *ops = info->fbcon_par; struct display *p; struct vc_data *vc = NULL; @@ -442,7 +442,7 @@ static void fbcon_add_cursor_timer(struct fb_info *info) if ((!info->queue.func || info->queue.func == fb_flashcursor) && !(ops->flags & FBCON_FLAGS_CURSOR_TIMER)) { if (!info->queue.func) - INIT_WORK(&info->queue, fb_flashcursor, info); + INIT_WORK(&info->queue, fb_flashcursor); init_timer(&ops->cursor_timer); ops->cursor_timer.function = cursor_timer_handler; diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 8a8ae55a740..38eb0b69c2d 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -964,9 +964,10 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state) * Our LCD controller task (which is called when we blank or unblank) * via keventd. */ -static void pxafb_task(void *dummy) +static void pxafb_task(struct work_struct *work) { - struct pxafb_info *fbi = dummy; + struct pxafb_info *fbi = + container_of(work, struct pxafb_info, task); u_int state = xchg(&fbi->task_state, -1); set_ctrlr_state(fbi, state); @@ -1159,7 +1160,7 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev) } init_waitqueue_head(&fbi->ctrlr_wait); - INIT_WORK(&fbi->task, pxafb_task, fbi); + INIT_WORK(&fbi->task, pxafb_task); init_MUTEX(&fbi->ctrlr_sem); return fbi; diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 90a79c78454..944273c3dbf 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -110,8 +110,8 @@ struct v9fs_mux_rpc { }; static int v9fs_poll_proc(void *); -static void v9fs_read_work(void *); -static void v9fs_write_work(void *); +static void v9fs_read_work(struct work_struct *work); +static void v9fs_write_work(struct work_struct *work); static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, poll_table * p); static u16 v9fs_mux_get_tag(struct v9fs_mux_data *); @@ -297,8 +297,8 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, m->rbuf = NULL; m->wpos = m->wsize = 0; m->wbuf = NULL; - INIT_WORK(&m->rq, v9fs_read_work, m); - INIT_WORK(&m->wq, v9fs_write_work, m); + INIT_WORK(&m->rq, v9fs_read_work); + INIT_WORK(&m->wq, v9fs_write_work); m->wsched = 0; memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); m->poll_task = NULL; @@ -458,13 +458,13 @@ static int v9fs_poll_proc(void *a) /** * v9fs_write_work - called when a transport can send some data */ -static void v9fs_write_work(void *a) +static void v9fs_write_work(struct work_struct *work) { int n, err; struct v9fs_mux_data *m; struct v9fs_req *req; - m = a; + m = container_of(work, struct v9fs_mux_data, wq); if (m->err < 0) { clear_bit(Wworksched, &m->wsched); @@ -564,7 +564,7 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) /** * v9fs_read_work - called when there is some data to be read from a transport */ -static void v9fs_read_work(void *a) +static void v9fs_read_work(struct work_struct *work) { int n, err; struct v9fs_mux_data *m; @@ -572,7 +572,7 @@ static void v9fs_read_work(void *a) struct v9fs_fcall *rcall; char *rbuf; - m = a; + m = container_of(work, struct v9fs_mux_data, rq); if (m->err < 0) return; @@ -53,13 +53,13 @@ static kmem_cache_t *kioctx_cachep; static struct workqueue_struct *aio_wq; /* Used for rare fput completion. */ -static void aio_fput_routine(void *); -static DECLARE_WORK(fput_work, aio_fput_routine, NULL); +static void aio_fput_routine(struct work_struct *); +static DECLARE_WORK(fput_work, aio_fput_routine); static DEFINE_SPINLOCK(fput_lock); static LIST_HEAD(fput_head); -static void aio_kick_handler(void *); +static void aio_kick_handler(struct work_struct *); static void aio_queue_work(struct kioctx *); /* aio_setup @@ -227,7 +227,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) INIT_LIST_HEAD(&ctx->active_reqs); INIT_LIST_HEAD(&ctx->run_list); - INIT_WORK(&ctx->wq, aio_kick_handler, ctx); + INIT_DELAYED_WORK(&ctx->wq, aio_kick_handler); if (aio_setup_ring(ctx) < 0) goto out_freectx; @@ -469,7 +469,7 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) wake_up(&ctx->wait); } -static void aio_fput_routine(void *data) +static void aio_fput_routine(struct work_struct *data) { spin_lock_irq(&fput_lock); while (likely(!list_empty(&fput_head))) { @@ -857,9 +857,9 @@ static inline void aio_run_all_iocbs(struct kioctx *ctx) * space. * Run on aiod's context. */ -static void aio_kick_handler(void *data) +static void aio_kick_handler(struct work_struct *work) { - struct kioctx *ctx = data; + struct kioctx *ctx = container_of(work, struct kioctx, wq.work); mm_segment_t oldfs = get_fs(); int requeue; @@ -874,7 +874,7 @@ static void aio_kick_handler(void *data) * we're in a worker thread already, don't use queue_delayed_work, */ if (requeue) - queue_work(aio_wq, &ctx->wq); + queue_delayed_work(aio_wq, &ctx->wq, 0); } @@ -940,16 +940,16 @@ static void bio_release_pages(struct bio *bio) * run one bio_put() against the BIO. */ -static void bio_dirty_fn(void *data); +static void bio_dirty_fn(struct work_struct *work); -static DECLARE_WORK(bio_dirty_work, bio_dirty_fn, NULL); +static DECLARE_WORK(bio_dirty_work, bio_dirty_fn); static DEFINE_SPINLOCK(bio_dirty_lock); static struct bio *bio_dirty_list; /* * This runs in process context */ -static void bio_dirty_fn(void *data) +static void bio_dirty_fn(struct work_struct *work) { unsigned long flags; struct bio *bio; diff --git a/fs/file.c b/fs/file.c index 8e81775c5dc..3787e82f54c 100644 --- a/fs/file.c +++ b/fs/file.c @@ -91,8 +91,10 @@ out: spin_unlock(&fddef->lock); } -static void free_fdtable_work(struct fdtable_defer *f) +static void free_fdtable_work(struct work_struct *work) { + struct fdtable_defer *f = + container_of(work, struct fdtable_defer, wq); struct fdtable *fdt; spin_lock_bh(&f->lock); @@ -351,7 +353,7 @@ static void __devinit fdtable_defer_list_init(int cpu) { struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu); spin_lock_init(&fddef->lock); - INIT_WORK(&fddef->wq, (void (*)(void *))free_fdtable_work, fddef); + INIT_WORK(&fddef->wq, free_fdtable_work); init_timer(&fddef->timer); fddef->timer.data = (unsigned long)fddef; fddef->timer.function = fdtable_timer; diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 78fe0fae23f..55f5333dae9 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -35,7 +35,7 @@ struct greedy { struct gfs2_holder gr_gh; - struct work_struct gr_work; + struct delayed_work gr_work; }; struct gfs2_gl_hash_bucket { @@ -1368,9 +1368,9 @@ static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, glops->go_xmote_th(gl, state, flags); } -static void greedy_work(void *data) +static void greedy_work(struct work_struct *work) { - struct greedy *gr = data; + struct greedy *gr = container_of(work, struct greedy, gr_work.work); struct gfs2_holder *gh = &gr->gr_gh; struct gfs2_glock *gl = gh->gh_gl; const struct gfs2_glock_operations *glops = gl->gl_ops; @@ -1422,7 +1422,7 @@ int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time) gfs2_holder_init(gl, 0, 0, gh); set_bit(HIF_GREEDY, &gh->gh_iflags); - INIT_WORK(&gr->gr_work, greedy_work, gr); + INIT_DELAYED_WORK(&gr->gr_work, greedy_work); set_bit(GLF_SKIP_WAITERS2, &gl->gl_flags); schedule_delayed_work(&gr->gr_work, time); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 42e3bef270c..72dad552aa0 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -577,12 +577,12 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) server->rcv.ptr = (unsigned char*)&server->rcv.buf; server->rcv.len = 10; server->rcv.state = 0; - INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc, server); - INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc, server); + INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc); + INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc); sock->sk->sk_write_space = ncp_tcp_write_space; } else { - INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc, server); - INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc, server); + INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc); + INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc); server->timeout_tm.data = (unsigned long)server; server->timeout_tm.function = ncpdgram_timeout_call; } diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c index 11c2b252ebe..e496d8b65e9 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -350,9 +350,10 @@ static void info_server(struct ncp_server *server, unsigned int id, const void * } } -void ncpdgram_rcv_proc(void *s) +void ncpdgram_rcv_proc(struct work_struct *work) { - struct ncp_server *server = s; + struct ncp_server *server = + container_of(work, struct ncp_server, rcv.tq); struct socket* sock; sock = server->ncp_sock; @@ -468,9 +469,10 @@ static void __ncpdgram_timeout_proc(struct ncp_server *server) } } -void ncpdgram_timeout_proc(void *s) +void ncpdgram_timeout_proc(struct work_struct *work) { - struct ncp_server *server = s; + struct ncp_server *server = + container_of(work, struct ncp_server, timeout_tq); mutex_lock(&server->rcv.creq_mutex); __ncpdgram_timeout_proc(server); mutex_unlock(&server->rcv.creq_mutex); @@ -652,18 +654,20 @@ skipdata:; } } -void ncp_tcp_rcv_proc(void *s) +void ncp_tcp_rcv_proc(struct work_struct *work) { - struct ncp_server *server = s; + struct ncp_server *server = + container_of(work, struct ncp_server, rcv.tq); mutex_lock(&server->rcv.creq_mutex); __ncptcp_rcv_proc(server); mutex_unlock(&server->rcv.creq_mutex); } -void ncp_tcp_tx_proc(void *s) +void ncp_tcp_tx_proc(struct work_struct *work) { - struct ncp_server *server = s; + struct ncp_server *server = + container_of(work, struct ncp_server, tx.tq); mutex_lock(&server->rcv.creq_mutex); __ncptcp_try_send(server); diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 5fea638743e..23ab145daa2 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -143,7 +143,7 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, INIT_LIST_HEAD(&clp->cl_state_owners); INIT_LIST_HEAD(&clp->cl_unused); spin_lock_init(&clp->cl_lock); - INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); + INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); clp->cl_boot_time = CURRENT_TIME; clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index ec1114b33d8..371b804e7cc 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -18,10 +18,10 @@ #define NFSDBG_FACILITY NFSDBG_VFS -static void nfs_expire_automounts(void *list); +static void nfs_expire_automounts(struct work_struct *work); LIST_HEAD(nfs_automount_list); -static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list); +static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); int nfs_mountpoint_expiry_timeout = 500 * HZ; static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, @@ -164,9 +164,9 @@ struct inode_operations nfs_referral_inode_operations = { .follow_link = nfs_follow_mountpoint, }; -static void nfs_expire_automounts(void *data) +static void nfs_expire_automounts(struct work_struct *work) { - struct list_head *list = (struct list_head *)data; + struct list_head *list = &nfs_automount_list; mark_mounts_for_expiry(list); if (!list_empty(list)) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 6f346677332..c26cd978c7c 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -185,7 +185,7 @@ extern const u32 nfs4_fs_locations_bitmap[2]; extern void nfs4_schedule_state_renewal(struct nfs_client *); extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); extern void nfs4_kill_renewd(struct nfs_client *); -extern void nfs4_renew_state(void *); +extern void nfs4_renew_state(struct work_struct *); /* nfs4state.c */ struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp); diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 7b6df1852e7..823298561c0 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c @@ -59,9 +59,10 @@ #define NFSDBG_FACILITY NFSDBG_PROC void -nfs4_renew_state(void *data) +nfs4_renew_state(struct work_struct *work) { - struct nfs_client *clp = (struct nfs_client *)data; + struct nfs_client *clp = + container_of(work, struct nfs_client, cl_renewd.work); struct rpc_cred *cred; long lease, timeout; unsigned long last, now; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 293b6495829..e431e93ab50 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1829,9 +1829,8 @@ out: } static struct workqueue_struct *laundry_wq; -static struct work_struct laundromat_work; -static void laundromat_main(void *); -static DECLARE_WORK(laundromat_work, laundromat_main, NULL); +static void laundromat_main(struct work_struct *); +static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); __be32 nfsd4_renew(clientid_t *clid) @@ -1940,7 +1939,7 @@ nfs4_laundromat(void) } void -laundromat_main(void *not_used) +laundromat_main(struct work_struct *not_used) { time_t t; diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 85a048b7a67..edc91ca3792 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -1197,10 +1197,12 @@ int ocfs2_flush_truncate_log(struct ocfs2_super *osb) return status; } -static void ocfs2_truncate_log_worker(void *data) +static void ocfs2_truncate_log_worker(struct work_struct *work) { int status; - struct ocfs2_super *osb = data; + struct ocfs2_super *osb = + container_of(work, struct ocfs2_super, + osb_truncate_log_wq.work); mlog_entry_void(); @@ -1432,7 +1434,8 @@ int ocfs2_truncate_log_init(struct ocfs2_super *osb) /* ocfs2_truncate_log_shutdown keys on the existence of * osb->osb_tl_inode so we don't set any of the osb variables * until we're sure all is well. */ - INIT_WORK(&osb->osb_truncate_log_wq, ocfs2_truncate_log_worker, osb); + INIT_DELAYED_WORK(&osb->osb_truncate_log_wq, + ocfs2_truncate_log_worker); osb->osb_tl_bh = tl_bh; osb->osb_tl_inode = tl_inode; diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 305cba3681f..4cd9a958045 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -141,7 +141,7 @@ struct o2hb_region { * recognizes a node going up and down in one iteration */ u64 hr_generation; - struct work_struct hr_write_timeout_work; + struct delayed_work hr_write_timeout_work; unsigned long hr_last_timeout_start; /* Used during o2hb_check_slot to hold a copy of the block @@ -156,9 +156,11 @@ struct o2hb_bio_wait_ctxt { int wc_error; }; -static void o2hb_write_timeout(void *arg) +static void o2hb_write_timeout(struct work_struct *work) { - struct o2hb_region *reg = arg; + struct o2hb_region *reg = + container_of(work, struct o2hb_region, + hr_write_timeout_work.work); mlog(ML_ERROR, "Heartbeat write timeout to device %s after %u " "milliseconds\n", reg->hr_dev_name, @@ -1404,7 +1406,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, goto out; } - INIT_WORK(®->hr_write_timeout_work, o2hb_write_timeout, reg); + INIT_DELAYED_WORK(®->hr_write_timeout_work, o2hb_write_timeout); /* * A node is considered live after it has beat LIVE_THRESHOLD diff --git a/fs/ocfs2/cluster/quorum.c b/fs/ocfs2/cluster/quorum.c index 7bba98fbfc1..4705d659fe5 100644 --- a/fs/ocfs2/cluster/quorum.c +++ b/fs/ocfs2/cluster/quorum.c @@ -88,7 +88,7 @@ void o2quo_disk_timeout(void) o2quo_fence_self(); } -static void o2quo_make_decision(void *arg) +static void o2quo_make_decision(struct work_struct *work) { int quorum; int lowest_hb, lowest_reachable = 0, fence = 0; @@ -306,7 +306,7 @@ void o2quo_init(void) struct o2quo_state *qs = &o2quo_state; spin_lock_init(&qs->qs_lock); - INIT_WORK(&qs->qs_work, o2quo_make_decision, NULL); + INIT_WORK(&qs->qs_work, o2quo_make_decision); } void o2quo_exit(void) diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index b650efa8c8b..9b3209dc0b1 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -140,11 +140,11 @@ static int o2net_sys_err_translations[O2NET_ERR_MAX] = [O2NET_ERR_DIED] = -EHOSTDOWN,}; /* can't quite avoid *all* internal declarations :/ */ -static void o2net_sc_connect_completed(void *arg); -static void o2net_rx_until_empty(void *arg); -static void o2net_shutdown_sc(void *arg); +static void o2net_sc_connect_completed(struct work_struct *work); +static void o2net_rx_until_empty(struct work_struct *work); +static void o2net_shutdown_sc(struct work_struct *work); static void o2net_listen_data_ready(struct sock *sk, int bytes); -static void o2net_sc_send_keep_req(void *arg); +static void o2net_sc_send_keep_req(struct work_struct *work); static void o2net_idle_timer(unsigned long data); static void o2net_sc_postpone_idle(struct o2net_sock_container *sc); @@ -308,10 +308,10 @@ static struct o2net_sock_container *sc_alloc(struct o2nm_node *node) o2nm_node_get(node); sc->sc_node = node; - INIT_WORK(&sc->sc_connect_work, o2net_sc_connect_completed, sc); - INIT_WORK(&sc->sc_rx_work, o2net_rx_until_empty, sc); - INIT_WORK(&sc->sc_shutdown_work, o2net_shutdown_sc, sc); - INIT_WORK(&sc->sc_keepalive_work, o2net_sc_send_keep_req, sc); + INIT_WORK(&sc->sc_connect_work, o2net_sc_connect_completed); + INIT_WORK(&sc->sc_rx_work, o2net_rx_until_empty); + INIT_WORK(&sc->sc_shutdown_work, o2net_shutdown_sc); + INIT_DELAYED_WORK(&sc->sc_keepalive_work, o2net_sc_send_keep_req); init_timer(&sc->sc_idle_timeout); sc->sc_idle_timeout.function = o2net_idle_timer; @@ -342,7 +342,7 @@ static void o2net_sc_queue_work(struct o2net_sock_container *sc, sc_put(sc); } static void o2net_sc_queue_delayed_work(struct o2net_sock_container *sc, - struct work_struct *work, + struct delayed_work *work, int delay) { sc_get(sc); @@ -350,7 +350,7 @@ static void o2net_sc_queue_delayed_work(struct o2net_sock_container *sc, sc_put(sc); } static void o2net_sc_cancel_delayed_work(struct o2net_sock_container *sc, - struct work_struct *work) + struct delayed_work *work) { if (cancel_delayed_work(work)) sc_put(sc); @@ -564,9 +564,11 @@ static void o2net_ensure_shutdown(struct o2net_node *nn, * ourselves as state_change couldn't get the nn_lock and call set_nn_state * itself. */ -static void o2net_shutdown_sc(void *arg) +static void o2net_shutdown_sc(struct work_struct *work) { - struct o2net_sock_container *sc = arg; + struct o2net_sock_container *sc = + container_of(work, struct o2net_sock_container, + sc_shutdown_work); struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); sclog(sc, "shutting down\n"); @@ -1201,9 +1203,10 @@ out: /* this work func is triggerd by data ready. it reads until it can read no * more. it interprets 0, eof, as fatal. if data_ready hits while we're doing * our work the work struct will be marked and we'll be called again. */ -static void o2net_rx_until_empty(void *arg) +static void o2net_rx_until_empty(struct work_struct *work) { - struct o2net_sock_container *sc = arg; + struct o2net_sock_container *sc = + container_of(work, struct o2net_sock_container, sc_rx_work); int ret; do { @@ -1249,9 +1252,11 @@ static int o2net_set_nodelay(struct socket *sock) /* called when a connect completes and after a sock is accepted. the * rx path will see the response and mark the sc valid */ -static void o2net_sc_connect_completed(void *arg) +static void o2net_sc_connect_completed(struct work_struct *work) { - struct o2net_sock_container *sc = arg; + struct o2net_sock_container *sc = + container_of(work, struct o2net_sock_container, + sc_connect_work); mlog(ML_MSG, "sc sending handshake with ver %llu id %llx\n", (unsigned long long)O2NET_PROTOCOL_VERSION, @@ -1262,9 +1267,11 @@ static void o2net_sc_connect_completed(void *arg) } /* this is called as a work_struct func. */ -static void o2net_sc_send_keep_req(void *arg) +static void o2net_sc_send_keep_req(struct work_struct *work) { - struct o2net_sock_container *sc = arg; + struct o2net_sock_container *sc = + container_of(work, struct o2net_sock_container, + sc_keepalive_work.work); o2net_sendpage(sc, o2net_keep_req, sizeof(*o2net_keep_req)); sc_put(sc); @@ -1314,14 +1321,15 @@ static void o2net_sc_postpone_idle(struct o2net_sock_container *sc) * having a connect attempt fail, etc. This centralizes the logic which decides * if a connect attempt should be made or if we should give up and all future * transmit attempts should fail */ -static void o2net_start_connect(void *arg) +static void o2net_start_connect(struct work_struct *work) { - struct o2net_node *nn = arg; + struct o2net_node *nn = + container_of(work, struct o2net_node, nn_connect_work.work); struct o2net_sock_container *sc = NULL; struct o2nm_node *node = NULL, *mynode = NULL; struct socket *sock = NULL; struct sockaddr_in myaddr = {0, }, remoteaddr = {0, }; - int ret = 0; + int ret = 0, stop; /* if we're greater we initiate tx, otherwise we accept */ if (o2nm_this_node() <= o2net_num_from_nn(nn)) @@ -1342,10 +1350,9 @@ static void o2net_start_connect(void *arg) spin_lock(&nn->nn_lock); /* see if we already have one pending or have given up */ - if (nn->nn_sc || nn->nn_persistent_error) - arg = NULL; + stop = (nn->nn_sc || nn->nn_persistent_error); spin_unlock(&nn->nn_lock); - if (arg == NULL) /* *shrug*, needed some indicator */ + if (stop) goto out; nn->nn_last_connect_attempt = jiffies; @@ -1421,9 +1428,10 @@ out: return; } -static void o2net_connect_expired(void *arg) +static void o2net_connect_expired(struct work_struct *work) { - struct o2net_node *nn = arg; + struct o2net_node *nn = + container_of(work, struct o2net_node, nn_connect_expired.work); spin_lock(&nn->nn_lock); if (!nn->nn_sc_valid) { @@ -1436,9 +1444,10 @@ static void o2net_connect_expired(void *arg) spin_unlock(&nn->nn_lock); } -static void o2net_still_up(void *arg) +static void o2net_still_up(struct work_struct *work) { - struct o2net_node *nn = arg; + struct o2net_node *nn = + container_of(work, struct o2net_node, nn_still_up.work); o2quo_hb_still_up(o2net_num_from_nn(nn)); } @@ -1644,9 +1653,9 @@ out: return ret; } -static void o2net_accept_many(void *arg) +static void o2net_accept_many(struct work_struct *work) { - struct socket *sock = arg; + struct socket *sock = o2net_listen_sock; while (o2net_accept_one(sock) == 0) cond_resched(); } @@ -1700,7 +1709,7 @@ static int o2net_open_listening_sock(__be16 port) write_unlock_bh(&sock->sk->sk_callback_lock); o2net_listen_sock = sock; - INIT_WORK(&o2net_listen_work, o2net_accept_many, sock); + INIT_WORK(&o2net_listen_work, o2net_accept_many); sock->sk->sk_reuse = 1; ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin)); @@ -1819,9 +1828,10 @@ int o2net_init(void) struct o2net_node *nn = o2net_nn_from_num(i); spin_lock_init(&nn->nn_lock); - INIT_WORK(&nn->nn_connect_work, o2net_start_connect, nn); - INIT_WORK(&nn->nn_connect_expired, o2net_connect_expired, nn); - INIT_WORK(&nn->nn_still_up, o2net_still_up, nn); + INIT_DELAYED_WORK(&nn->nn_connect_work, o2net_start_connect); + INIT_DELAYED_WORK(&nn->nn_connect_expired, + o2net_connect_expired); + INIT_DELAYED_WORK(&nn->nn_still_up, o2net_still_up); /* until we see hb from a node we'll return einval */ nn->nn_persistent_error = -ENOTCONN; init_waitqueue_head(&nn->nn_sc_wq); diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h index 4b46aac7d24..daebbd3a2c8 100644 --- a/fs/ocfs2/cluster/tcp_internal.h +++ b/fs/ocfs2/cluster/tcp_internal.h @@ -86,18 +86,18 @@ struct o2net_node { * connect attempt fails and so can be self-arming. shutdown is * careful to first mark the nn such that no connects will be attempted * before canceling delayed connect work and flushing the queue. */ - struct work_struct nn_connect_work; + struct delayed_work nn_connect_work; unsigned long nn_last_connect_attempt; /* this is queued as nodes come up and is canceled when a connection is * established. this expiring gives up on the node and errors out * transmits */ - struct work_struct nn_connect_expired; + struct delayed_work nn_connect_expired; /* after we give up on a socket we wait a while before deciding * that it is still heartbeating and that we should do some * quorum work */ - struct work_struct nn_still_up; + struct delayed_work nn_still_up; }; struct o2net_sock_container { @@ -129,7 +129,7 @@ struct o2net_sock_container { struct work_struct sc_shutdown_work; struct timer_list sc_idle_timeout; - struct work_struct sc_keepalive_work; + struct delayed_work sc_keepalive_work; unsigned sc_handshake_ok:1; diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h index fa968180b07..6b6ff76538c 100644 --- a/fs/ocfs2/dlm/dlmcommon.h +++ b/fs/ocfs2/dlm/dlmcommon.h @@ -153,7 +153,7 @@ static inline struct hlist_head *dlm_lockres_hash(struct dlm_ctxt *dlm, unsigned * called functions that cannot be directly called from the * net message handlers for some reason, usually because * they need to send net messages of their own. */ -void dlm_dispatch_work(void *data); +void dlm_dispatch_work(struct work_struct *work); struct dlm_lock_resource; struct dlm_work_item; diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index f6cdab3a2c6..420a375a394 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -1297,7 +1297,7 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain, spin_lock_init(&dlm->work_lock); INIT_LIST_HEAD(&dlm->work_list); - INIT_WORK(&dlm->dispatched_work, dlm_dispatch_work, dlm); + INIT_WORK(&dlm->dispatched_work, dlm_dispatch_work); kref_init(&dlm->dlm_refs); dlm->dlm_state = DLM_CTXT_NEW; diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 9d950d7cea3..fb3e2b0817f 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -153,9 +153,10 @@ static inline void dlm_reset_recovery(struct dlm_ctxt *dlm) } /* Worker function used during recovery. */ -void dlm_dispatch_work(void *data) +void dlm_dispatch_work(struct work_struct *work) { - struct dlm_ctxt *dlm = (struct dlm_ctxt *)data; + struct dlm_ctxt *dlm = + container_of(work, struct dlm_ctxt, dispatched_work); LIST_HEAD(tmp_list); struct list_head *iter, *iter2; struct dlm_work_item *item; diff --git a/fs/ocfs2/dlm/userdlm.c b/fs/ocfs2/dlm/userdlm.c index eead48bbfac..7d2f578b267 100644 --- a/fs/ocfs2/dlm/userdlm.c +++ b/fs/ocfs2/dlm/userdlm.c @@ -171,15 +171,14 @@ static inline void user_dlm_grab_inode_ref(struct user_lock_res *lockres) BUG(); } -static void user_dlm_unblock_lock(void *opaque); +static void user_dlm_unblock_lock(struct work_struct *work); static void __user_dlm_queue_lockres(struct user_lock_res *lockres) { if (!(lockres->l_flags & USER_LOCK_QUEUED)) { user_dlm_grab_inode_ref(lockres); - INIT_WORK(&lockres->l_work, user_dlm_unblock_lock, - lockres); + INIT_WORK(&lockres->l_work, user_dlm_unblock_lock); queue_work(user_dlm_worker, &lockres->l_work); lockres->l_flags |= USER_LOCK_QUEUED; @@ -279,10 +278,11 @@ static inline void user_dlm_drop_inode_ref(struct user_lock_res *lockres) iput(inode); } -static void user_dlm_unblock_lock(void *opaque) +static void user_dlm_unblock_lock(struct work_struct *work) { int new_level, status; - struct user_lock_res *lockres = (struct user_lock_res *) opaque; + struct user_lock_res *lockres = + container_of(work, struct user_lock_res, l_work); struct dlm_ctxt *dlm = dlm_ctxt_from_user_lockres(lockres); mlog(0, "processing lockres %.*s\n", lockres->l_namelen, diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index c0ad7cb5952..1d7f4ab1e5e 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -703,11 +703,12 @@ struct ocfs2_la_recovery_item { * NOTE: This function can and will sleep on recovery of other nodes * during cluster locking, just like any other ocfs2 process. */ -void ocfs2_complete_recovery(void *data) +void ocfs2_complete_recovery(struct work_struct *work) { int ret; - struct ocfs2_super *osb = data; - struct ocfs2_journal *journal = osb->journal; + struct ocfs2_journal *journal = + container_of(work, struct ocfs2_journal, j_recovery_work); + struct ocfs2_super *osb = journal->j_osb; struct ocfs2_dinode *la_dinode, *tl_dinode; struct ocfs2_la_recovery_item *item; struct list_head *p, *n; diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index d86cb960b7e..899112ad813 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -133,7 +133,7 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb, } /* Exported only for the journal struct init code in super.c. Do not call. */ -void ocfs2_complete_recovery(void *data); +void ocfs2_complete_recovery(struct work_struct *work); /* * Journal Control: diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 078883772bd..b767fd7da6e 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -285,7 +285,7 @@ struct ocfs2_super /* Truncate log info */ struct inode *osb_tl_inode; struct buffer_head *osb_tl_bh; - struct work_struct osb_truncate_log_wq; + struct delayed_work osb_truncate_log_wq; struct ocfs2_node_map osb_recovering_orphan_dirs; unsigned int *osb_orphan_wipes; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index b0992573dee..d9b4214a12d 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1365,7 +1365,7 @@ static int ocfs2_initialize_super(struct super_block *sb, spin_lock_init(&journal->j_lock); journal->j_trans_id = (unsigned long) 1; INIT_LIST_HEAD(&journal->j_la_cleanups); - INIT_WORK(&journal->j_recovery_work, ocfs2_complete_recovery, osb); + INIT_WORK(&journal->j_recovery_work, ocfs2_complete_recovery); journal->j_state = OCFS2_JOURNAL_FREE; /* get some pseudo constants for clustersize bits */ diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index ac93174c963..7280a23ef34 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -104,7 +104,7 @@ static int release_journal_dev(struct super_block *super, struct reiserfs_journal *journal); static int dirty_one_transaction(struct super_block *s, struct reiserfs_journal_list *jl); -static void flush_async_commits(void *p); +static void flush_async_commits(struct work_struct *work); static void queue_log_writer(struct super_block *s); /* values for join in do_journal_begin_r */ @@ -2836,7 +2836,8 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, if (reiserfs_mounted_fs_count <= 1) commit_wq = create_workqueue("reiserfs"); - INIT_WORK(&journal->j_work, flush_async_commits, p_s_sb); + INIT_DELAYED_WORK(&journal->j_work, flush_async_commits); + journal->j_work_sb = p_s_sb; return 0; free_and_return: free_journal_ram(p_s_sb); @@ -3447,10 +3448,11 @@ int journal_end_sync(struct reiserfs_transaction_handle *th, /* ** writeback the pending async commits to disk */ -static void flush_async_commits(void *p) +static void flush_async_commits(struct work_struct *work) { - struct super_block *p_s_sb = p; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = + container_of(work, struct reiserfs_journal, j_work.work); + struct super_block *p_s_sb = journal->j_work_sb; struct reiserfs_journal_list *jl; struct list_head *entry; diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 09360cf1e1f..8e6b56fc1ca 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -149,9 +149,10 @@ xfs_destroy_ioend( */ STATIC void xfs_end_bio_delalloc( - void *data) + struct work_struct *work) { - xfs_ioend_t *ioend = data; + xfs_ioend_t *ioend = + container_of(work, xfs_ioend_t, io_work); xfs_destroy_ioend(ioend); } @@ -161,9 +162,10 @@ xfs_end_bio_delalloc( */ STATIC void xfs_end_bio_written( - void *data) + struct work_struct *work) { - xfs_ioend_t *ioend = data; + xfs_ioend_t *ioend = + container_of(work, xfs_ioend_t, io_work); xfs_destroy_ioend(ioend); } @@ -176,9 +178,10 @@ xfs_end_bio_written( */ STATIC void xfs_end_bio_unwritten( - void *data) + struct work_struct *work) { - xfs_ioend_t *ioend = data; + xfs_ioend_t *ioend = + container_of(work, xfs_ioend_t, io_work); bhv_vnode_t *vp = ioend->io_vnode; xfs_off_t offset = ioend->io_offset; size_t size = ioend->io_size; @@ -220,11 +223,11 @@ xfs_alloc_ioend( ioend->io_size = 0; if (type == IOMAP_UNWRITTEN) - INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten, ioend); + INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten); else if (type == IOMAP_DELAY) - INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc, ioend); + INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc); else - INIT_WORK(&ioend->io_work, xfs_end_bio_written, ioend); + INIT_WORK(&ioend->io_work, xfs_end_bio_written); return ioend; } diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index d3382843698..eef4a0ba11e 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -994,9 +994,10 @@ xfs_buf_wait_unpin( STATIC void xfs_buf_iodone_work( - void *v) + struct work_struct *work) { - xfs_buf_t *bp = (xfs_buf_t *)v; + xfs_buf_t *bp = + container_of(work, xfs_buf_t, b_iodone_work); if (bp->b_iodone) (*(bp->b_iodone))(bp); @@ -1017,10 +1018,10 @@ xfs_buf_ioend( if ((bp->b_iodone) || (bp->b_flags & XBF_ASYNC)) { if (schedule) { - INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work, bp); + INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work); queue_work(xfslogd_workqueue, &bp->b_iodone_work); } else { - xfs_buf_iodone_work(bp); + xfs_buf_iodone_work(&bp->b_iodone_work); } } else { up(&bp->b_iodonesema); diff --git a/include/asm-arm/arch-omap/irda.h b/include/asm-arm/arch-omap/irda.h index 805ae3575e4..345a649ec83 100644 --- a/include/asm-arm/arch-omap/irda.h +++ b/include/asm-arm/arch-omap/irda.h @@ -24,7 +24,7 @@ struct omap_irda_config { /* Very specific to the needs of some platforms (h3,h4) * having calls which can sleep in irda_set_speed. */ - struct work_struct gpio_expa; + struct delayed_work gpio_expa; int rx_channel; int tx_channel; unsigned long dest_start; diff --git a/include/asm-i386/atomic.h b/include/asm-i386/atomic.h index 51a16624252..a6c024e2506 100644 --- a/include/asm-i386/atomic.h +++ b/include/asm-i386/atomic.h @@ -14,7 +14,7 @@ * on us. We need to use _exactly_ the address the user gave us, * not some alias that contains the same information. */ -typedef struct { volatile int counter; } atomic_t; +typedef struct { int counter; } atomic_t; #define ATOMIC_INIT(i) { (i) } diff --git a/include/asm-i386/spinlock_types.h b/include/asm-i386/spinlock_types.h index 59efe849f35..4da9345c150 100644 --- a/include/asm-i386/spinlock_types.h +++ b/include/asm-i386/spinlock_types.h @@ -6,13 +6,13 @@ #endif typedef struct { - volatile unsigned int slock; + unsigned int slock; } raw_spinlock_t; #define __RAW_SPIN_LOCK_UNLOCKED { 1 } typedef struct { - volatile unsigned int lock; + unsigned int lock; } raw_rwlock_t; #define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } diff --git a/include/asm-m68knommu/irq.h b/include/asm-m68knommu/irq.h index 45e7a2fd168..7b8f874f842 100644 --- a/include/asm-m68knommu/irq.h +++ b/include/asm-m68knommu/irq.h @@ -86,5 +86,6 @@ extern void (*mach_disable_irq)(unsigned int); #define enable_irq(x) do { } while (0) #define disable_irq(x) do { } while (0) #define disable_irq_nosync(x) disable_irq(x) +#define irq_canonicalize(irq) (irq) #endif /* _M68K_IRQ_H_ */ diff --git a/include/asm-m68knommu/rtc.h b/include/asm-m68knommu/rtc.h new file mode 100644 index 00000000000..eaf18ec83c8 --- /dev/null +++ b/include/asm-m68knommu/rtc.h @@ -0,0 +1 @@ +#include <asm-m68k/rtc.h> diff --git a/include/asm-m68knommu/ucontext.h b/include/asm-m68knommu/ucontext.h index 5d570cedbb0..713a27f901c 100644 --- a/include/asm-m68knommu/ucontext.h +++ b/include/asm-m68knommu/ucontext.h @@ -5,21 +5,17 @@ typedef int greg_t; #define NGREG 18 typedef greg_t gregset_t[NGREG]; -#ifdef CONFIG_FPU typedef struct fpregset { int f_pcr; int f_psr; int f_fpiaddr; int f_fpregs[8][3]; } fpregset_t; -#endif struct mcontext { int version; gregset_t gregs; -#ifdef CONFIG_FPU fpregset_t fpregs; -#endif }; #define MCONTEXT_VERSION 2 @@ -29,9 +25,7 @@ struct ucontext { struct ucontext *uc_link; stack_t uc_stack; struct mcontext uc_mcontext; -#ifdef CONFIG_FPU unsigned long uc_filler[80]; -#endif sigset_t uc_sigmask; /* mask last for extensibility */ }; diff --git a/include/asm-mips/i8259.h b/include/asm-mips/i8259.h index 0214abe3f0a..4df8d8b118c 100644 --- a/include/asm-mips/i8259.h +++ b/include/asm-mips/i8259.h @@ -19,10 +19,31 @@ #include <asm/io.h> +/* i8259A PIC registers */ +#define PIC_MASTER_CMD 0x20 +#define PIC_MASTER_IMR 0x21 +#define PIC_MASTER_ISR PIC_MASTER_CMD +#define PIC_MASTER_POLL PIC_MASTER_ISR +#define PIC_MASTER_OCW3 PIC_MASTER_ISR +#define PIC_SLAVE_CMD 0xa0 +#define PIC_SLAVE_IMR 0xa1 + +/* i8259A PIC related value */ +#define PIC_CASCADE_IR 2 +#define MASTER_ICW4_DEFAULT 0x01 +#define SLAVE_ICW4_DEFAULT 0x01 +#define PIC_ICW4_AEOI 2 + extern spinlock_t i8259A_lock; +extern void init_8259A(int auto_eoi); +extern void enable_8259A_irq(unsigned int irq); +extern void disable_8259A_irq(unsigned int irq); + extern void init_i8259_irqs(void); +#define I8259A_IRQ_BASE 0 + /* * Do the traditional i8259 interrupt polling thing. This is for the few * cases where no better interrupt acknowledge method is available and we @@ -35,15 +56,15 @@ static inline int i8259_irq(void) spin_lock(&i8259A_lock); /* Perform an interrupt acknowledge cycle on controller 1. */ - outb(0x0C, 0x20); /* prepare for poll */ - irq = inb(0x20) & 7; - if (irq == 2) { + outb(0x0C, PIC_MASTER_CMD); /* prepare for poll */ + irq = inb(PIC_MASTER_CMD) & 7; + if (irq == PIC_CASCADE_IR) { /* * Interrupt is cascaded so perform interrupt * acknowledge on controller 2. */ - outb(0x0C, 0xA0); /* prepare for poll */ - irq = (inb(0xA0) & 7) + 8; + outb(0x0C, PIC_SLAVE_CMD); /* prepare for poll */ + irq = (inb(PIC_SLAVE_CMD) & 7) + 8; } if (unlikely(irq == 7)) { @@ -54,14 +75,14 @@ static inline int i8259_irq(void) * significant bit is not set then there is no valid * interrupt. */ - outb(0x0B, 0x20); /* ISR register */ - if(~inb(0x20) & 0x80) + outb(0x0B, PIC_MASTER_ISR); /* ISR register */ + if(~inb(PIC_MASTER_ISR) & 0x80) irq = -1; } spin_unlock(&i8259A_lock); - return irq; + return likely(irq >= 0) ? irq + I8259A_IRQ_BASE : irq; } #endif /* _ASM_I8259_H */ diff --git a/include/asm-mips/pgtable-32.h b/include/asm-mips/pgtable-32.h index d20f2e9b28b..2fbd47eba32 100644 --- a/include/asm-mips/pgtable-32.h +++ b/include/asm-mips/pgtable-32.h @@ -156,9 +156,9 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #define __pte_offset(address) \ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) #define pte_offset(dir, address) \ - ((pte_t *) (pmd_page_vaddr(*dir)) + __pte_offset(address)) -#define pte_offset_kernel(dir, address) \ - ((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address)) + ((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address)) +#define pte_offset_kernel(dir, address) \ + ((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address)) #define pte_offset_map(dir, address) \ ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address)) diff --git a/include/asm-mips/pgtable-64.h b/include/asm-mips/pgtable-64.h index b9b1e86493e..a5b18710b6a 100644 --- a/include/asm-mips/pgtable-64.h +++ b/include/asm-mips/pgtable-64.h @@ -212,9 +212,9 @@ static inline pmd_t *pmd_offset(pud_t * pud, unsigned long address) #define __pte_offset(address) \ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) #define pte_offset(dir, address) \ - ((pte_t *) (pmd_page_vaddr(*dir)) + __pte_offset(address)) + ((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address)) #define pte_offset_kernel(dir, address) \ - ((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address)) + ((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address)) #define pte_offset_map(dir, address) \ ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address)) #define pte_offset_map_nested(dir, address) \ diff --git a/include/asm-sh/atomic.h b/include/asm-sh/atomic.h index 8bdc1ba56f7..28305c3cbdd 100644 --- a/include/asm-sh/atomic.h +++ b/include/asm-sh/atomic.h @@ -28,11 +28,11 @@ static inline void atomic_add(int i, atomic_t *v) unsigned long tmp; __asm__ __volatile__ ( -"1: movli.l @%3, %0 ! atomic_add \n" -" add %2, %0 \n" -" movco.l %0, @%3 \n" +"1: movli.l @%2, %0 ! atomic_add \n" +" add %1, %0 \n" +" movco.l %0, @%2 \n" " bf 1b \n" - : "=&z" (tmp), "=r" (&v->counter) + : "=&z" (tmp) : "r" (i), "r" (&v->counter) : "t"); #else @@ -50,11 +50,11 @@ static inline void atomic_sub(int i, atomic_t *v) unsigned long tmp; __asm__ __volatile__ ( -"1: movli.l @%3, %0 ! atomic_sub \n" -" sub %2, %0 \n" -" movco.l %0, @%3 \n" +"1: movli.l @%2, %0 ! atomic_sub \n" +" sub %1, %0 \n" +" movco.l %0, @%2 \n" " bf 1b \n" - : "=&z" (tmp), "=r" (&v->counter) + : "=&z" (tmp) : "r" (i), "r" (&v->counter) : "t"); #else @@ -80,12 +80,12 @@ static inline int atomic_add_return(int i, atomic_t *v) #ifdef CONFIG_CPU_SH4A __asm__ __volatile__ ( -"1: movli.l @%3, %0 ! atomic_add_return \n" -" add %2, %0 \n" -" movco.l %0, @%3 \n" +"1: movli.l @%2, %0 ! atomic_add_return \n" +" add %1, %0 \n" +" movco.l %0, @%2 \n" " bf 1b \n" " synco \n" - : "=&z" (temp), "=r" (&v->counter) + : "=&z" (temp) : "r" (i), "r" (&v->counter) : "t"); #else @@ -109,12 +109,12 @@ static inline int atomic_sub_return(int i, atomic_t *v) #ifdef CONFIG_CPU_SH4A __asm__ __volatile__ ( -"1: movli.l @%3, %0 ! atomic_sub_return \n" -" sub %2, %0 \n" -" movco.l %0, @%3 \n" +"1: movli.l @%2, %0 ! atomic_sub_return \n" +" sub %1, %0 \n" +" movco.l %0, @%2 \n" " bf 1b \n" " synco \n" - : "=&z" (temp), "=r" (&v->counter) + : "=&z" (temp) : "r" (i), "r" (&v->counter) : "t"); #else @@ -186,11 +186,11 @@ static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) unsigned long tmp; __asm__ __volatile__ ( -"1: movli.l @%3, %0 ! atomic_clear_mask \n" -" and %2, %0 \n" -" movco.l %0, @%3 \n" +"1: movli.l @%2, %0 ! atomic_clear_mask \n" +" and %1, %0 \n" +" movco.l %0, @%2 \n" " bf 1b \n" - : "=&z" (tmp), "=r" (&v->counter) + : "=&z" (tmp) : "r" (~mask), "r" (&v->counter) : "t"); #else @@ -208,11 +208,11 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v) unsigned long tmp; __asm__ __volatile__ ( -"1: movli.l @%3, %0 ! atomic_set_mask \n" -" or %2, %0 \n" -" movco.l %0, @%3 \n" +"1: movli.l @%2, %0 ! atomic_set_mask \n" +" or %1, %0 \n" +" movco.l %0, @%2 \n" " bf 1b \n" - : "=&z" (tmp), "=r" (&v->counter) + : "=&z" (tmp) : "r" (mask), "r" (&v->counter) : "t"); #else diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h index beeea40f549..795047da5e1 100644 --- a/include/asm-sh/bugs.h +++ b/include/asm-sh/bugs.h @@ -23,16 +23,20 @@ static void __init check_bugs(void) cpu_data->loops_per_jiffy = loops_per_jiffy; switch (cpu_data->type) { - case CPU_SH7604: + case CPU_SH7604 ... CPU_SH7619: *p++ = '2'; break; + case CPU_SH7206: + *p++ = '2'; + *p++ = 'a'; + break; case CPU_SH7705 ... CPU_SH7300: *p++ = '3'; break; case CPU_SH7750 ... CPU_SH4_501: *p++ = '4'; break; - case CPU_SH7770 ... CPU_SH7781: + case CPU_SH7770 ... CPU_SH7785: *p++ = '4'; *p++ = 'a'; break; diff --git a/include/asm-sh/clock.h b/include/asm-sh/clock.h index fdfb75b30f0..1df92807f8c 100644 --- a/include/asm-sh/clock.h +++ b/include/asm-sh/clock.h @@ -4,6 +4,7 @@ #include <linux/kref.h> #include <linux/list.h> #include <linux/seq_file.h> +#include <linux/clk.h> struct clk; @@ -18,7 +19,7 @@ struct clk_ops { struct clk { struct list_head node; const char *name; - + int id; struct module *owner; struct clk *parent; @@ -40,22 +41,13 @@ void arch_init_clk_ops(struct clk_ops **, int type); int clk_init(void); int __clk_enable(struct clk *); -int clk_enable(struct clk *); - void __clk_disable(struct clk *); -void clk_disable(struct clk *); -int clk_set_rate(struct clk *, unsigned long rate); -unsigned long clk_get_rate(struct clk *); void clk_recalc_rate(struct clk *); -struct clk *clk_get(const char *id); -void clk_put(struct clk *); - int clk_register(struct clk *); void clk_unregister(struct clk *); int show_clocks(struct seq_file *m); #endif /* __ASM_SH_CLOCK_H */ - diff --git a/include/asm-sh/cpu-sh2/cache.h b/include/asm-sh/cpu-sh2/cache.h index cd96402e856..20b9796842d 100644 --- a/include/asm-sh/cpu-sh2/cache.h +++ b/include/asm-sh/cpu-sh2/cache.h @@ -12,6 +12,7 @@ #define L1_CACHE_SHIFT 4 +#if defined(CONFIG_CPU_SUBTYPE_SH7604) #define CCR 0xfffffe92 /* Address of Cache Control Register */ #define CCR_CACHE_CE 0x01 /* Cache enable */ @@ -27,5 +28,26 @@ #define CCR_CACHE_ORA CCR_CACHE_TW #define CCR_CACHE_WT 0x00 /* SH-2 is _always_ write-through */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7619) +#define CCR1 0xffffffec +#define CCR CCR1 + +#define CCR_CACHE_CE 0x01 /* Cache enable */ +#define CCR_CACHE_WT 0x06 /* CCR[bit1=1,bit2=1] */ + /* 0x00000000-0x7fffffff: Write-through */ + /* 0x80000000-0x9fffffff: Write-back */ + /* 0xc0000000-0xdfffffff: Write-through */ +#define CCR_CACHE_CB 0x00 /* CCR[bit1=0,bit2=0] */ + /* 0x00000000-0x7fffffff: Write-back */ + /* 0x80000000-0x9fffffff: Write-through */ + /* 0xc0000000-0xdfffffff: Write-back */ +#define CCR_CACHE_CF 0x08 /* Cache invalidate */ + +#define CACHE_OC_ADDRESS_ARRAY 0xf0000000 +#define CACHE_OC_DATA_ARRAY 0xf1000000 + +#define CCR_CACHE_ENABLE CCR_CACHE_CE +#define CCR_CACHE_INVALIDATE CCR_CACHE_CF +#endif #endif /* __ASM_CPU_SH2_CACHE_H */ diff --git a/include/asm-sh/cpu-sh2/freq.h b/include/asm-sh/cpu-sh2/freq.h new file mode 100644 index 00000000000..31de475da70 --- /dev/null +++ b/include/asm-sh/cpu-sh2/freq.h @@ -0,0 +1,18 @@ +/* + * include/asm-sh/cpu-sh2/freq.h + * + * Copyright (C) 2006 Yoshinori Sato + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef __ASM_CPU_SH2_FREQ_H +#define __ASM_CPU_SH2_FREQ_H + +#if defined(CONFIG_CPU_SUBTYPE_SH7619) +#define FREQCR 0xf815ff80 +#endif + +#endif /* __ASM_CPU_SH2_FREQ_H */ + diff --git a/include/asm-sh/cpu-sh2/mmu_context.h b/include/asm-sh/cpu-sh2/mmu_context.h new file mode 100644 index 00000000000..beeb299e01e --- /dev/null +++ b/include/asm-sh/cpu-sh2/mmu_context.h @@ -0,0 +1,16 @@ +/* + * include/asm-sh/cpu-sh2/mmu_context.h + * + * Copyright (C) 2003 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef __ASM_CPU_SH2_MMU_CONTEXT_H +#define __ASM_CPU_SH2_MMU_CONTEXT_H + +/* No MMU */ + +#endif /* __ASM_CPU_SH2_MMU_CONTEXT_H */ + diff --git a/include/asm-sh/cpu-sh2/timer.h b/include/asm-sh/cpu-sh2/timer.h new file mode 100644 index 00000000000..a39c241e819 --- /dev/null +++ b/include/asm-sh/cpu-sh2/timer.h @@ -0,0 +1,6 @@ +#ifndef __ASM_CPU_SH2_TIMER_H +#define __ASM_CPU_SH2_TIMER_H + +/* Nothing needed yet */ + +#endif /* __ASM_CPU_SH2_TIMER_H */ diff --git a/include/asm-sh/cpu-sh2a/addrspace.h b/include/asm-sh/cpu-sh2a/addrspace.h new file mode 100644 index 00000000000..3d2e9aa2152 --- /dev/null +++ b/include/asm-sh/cpu-sh2a/addrspace.h @@ -0,0 +1 @@ +#include <asm/cpu-sh2/addrspace.h> diff --git a/include/asm-sh/cpu-sh2a/cache.h b/include/asm-sh/cpu-sh2a/cache.h new file mode 100644 index 00000000000..3e4b9e48098 --- /dev/null +++ b/include/asm-sh/cpu-sh2a/cache.h @@ -0,0 +1,39 @@ +/* + * include/asm-sh/cpu-sh2a/cache.h + * + * Copyright (C) 2004 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef __ASM_CPU_SH2A_CACHE_H +#define __ASM_CPU_SH2A_CACHE_H + +#define L1_CACHE_SHIFT 4 + +#define CCR1 0xfffc1000 +#define CCR2 0xfffc1004 + +/* CCR1 behaves more like the traditional CCR */ +#define CCR CCR1 + +/* + * Most of the SH-2A CCR1 definitions resemble the SH-4 ones. All others not + * listed here are reserved. + */ +#define CCR_CACHE_CB 0x0000 /* Hack */ +#define CCR_CACHE_OCE 0x0001 +#define CCR_CACHE_WT 0x0002 +#define CCR_CACHE_OCI 0x0008 /* OCF */ +#define CCR_CACHE_ICE 0x0100 +#define CCR_CACHE_ICI 0x0800 /* ICF */ + +#define CACHE_IC_ADDRESS_ARRAY 0xf0000000 +#define CACHE_OC_ADDRESS_ARRAY 0xf0800000 + +#define CCR_CACHE_ENABLE (CCR_CACHE_OCE | CCR_CACHE_ICE) +#define CCR_CACHE_INVALIDATE (CCR_CACHE_OCI | CCR_CACHE_ICI) + +#endif /* __ASM_CPU_SH2A_CACHE_H */ + diff --git a/include/asm-sh/cpu-sh2a/cacheflush.h b/include/asm-sh/cpu-sh2a/cacheflush.h new file mode 100644 index 00000000000..fa3186c7335 --- /dev/null +++ b/include/asm-sh/cpu-sh2a/cacheflush.h @@ -0,0 +1 @@ +#include <asm/cpu-sh2/cacheflush.h> diff --git a/include/asm-sh/cpu-sh2a/dma.h b/include/asm-sh/cpu-sh2a/dma.h new file mode 100644 index 00000000000..0d5ad85c1de --- /dev/null +++ b/include/asm-sh/cpu-sh2a/dma.h @@ -0,0 +1 @@ +#include <asm/cpu-sh2/dma.h> diff --git a/include/asm-sh/cpu-sh2a/freq.h b/include/asm-sh/cpu-sh2a/freq.h new file mode 100644 index 00000000000..e518fff6d10 --- /dev/null +++ b/include/asm-sh/cpu-sh2a/freq.h @@ -0,0 +1,18 @@ +/* + * include/asm-sh/cpu-sh2a/freq.h + * + * Copyright (C) 2006 Yoshinori Sato + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef __ASM_CPU_SH2A_FREQ_H +#define __ASM_CPU_SH2A_FREQ_H + +#if defined(CONFIG_CPU_SUBTYPE_SH7206) +#define FREQCR 0xfffe0010 +#endif + +#endif /* __ASM_CPU_SH2A_FREQ_H */ + diff --git a/include/asm-sh/cpu-sh2a/mmu_context.h b/include/asm-sh/cpu-sh2a/mmu_context.h new file mode 100644 index 00000000000..cd2387f7db9 --- /dev/null +++ b/include/asm-sh/cpu-sh2a/mmu_context.h @@ -0,0 +1 @@ +#include <asm/cpu-sh2/mmu_context.h> diff --git a/include/asm-sh/cpu-sh2a/timer.h b/include/asm-sh/cpu-sh2a/timer.h new file mode 100644 index 00000000000..fee504adf11 --- /dev/null +++ b/include/asm-sh/cpu-sh2a/timer.h @@ -0,0 +1 @@ +#include <asm/cpu-sh2/timer.h> diff --git a/include/asm-sh/cpu-sh2a/ubc.h b/include/asm-sh/cpu-sh2a/ubc.h new file mode 100644 index 00000000000..cf28062b96a --- /dev/null +++ b/include/asm-sh/cpu-sh2a/ubc.h @@ -0,0 +1 @@ +#include <asm/cpu-sh2/ubc.h> diff --git a/include/asm-sh/cpu-sh2a/watchdog.h b/include/asm-sh/cpu-sh2a/watchdog.h new file mode 100644 index 00000000000..c1b3e248847 --- /dev/null +++ b/include/asm-sh/cpu-sh2a/watchdog.h @@ -0,0 +1 @@ +#include <asm/cpu-sh2/watchdog.h> diff --git a/include/asm-sh/dma.h b/include/asm-sh/dma.h index d9daa028689..faf3051cd42 100644 --- a/include/asm-sh/dma.h +++ b/include/asm-sh/dma.h @@ -14,9 +14,7 @@ #include <linux/spinlock.h> #include <linux/wait.h> #include <linux/sysdev.h> -#include <linux/device.h> #include <asm/cpu/dma.h> -#include <asm/semaphore.h> /* The maximum address that we can perform a DMA transfer to on this platform */ /* Don't define MAX_DMA_ADDRESS; it's useless on the SuperH and any @@ -46,16 +44,21 @@ * DMAC (dma_info) flags */ enum { - DMAC_CHANNELS_CONFIGURED = 0x00, - DMAC_CHANNELS_TEI_CAPABLE = 0x01, + DMAC_CHANNELS_CONFIGURED = 0x01, + DMAC_CHANNELS_TEI_CAPABLE = 0x02, /* Transfer end interrupt */ }; /* * DMA channel capabilities / flags */ enum { - DMA_TEI_CAPABLE = 0x01, - DMA_CONFIGURED = 0x02, + DMA_CONFIGURED = 0x01, + + /* + * Transfer end interrupt, inherited from DMAC. + * wait_queue used in dma_wait_for_completion. + */ + DMA_TEI_CAPABLE = 0x02, }; extern spinlock_t dma_spin_lock; @@ -68,28 +71,31 @@ struct dma_ops { int (*get_residue)(struct dma_channel *chan); int (*xfer)(struct dma_channel *chan); - void (*configure)(struct dma_channel *chan, unsigned long flags); + int (*configure)(struct dma_channel *chan, unsigned long flags); + int (*extend)(struct dma_channel *chan, unsigned long op, void *param); }; struct dma_channel { - char dev_id[16]; + char dev_id[16]; /* unique name per DMAC of channel */ - unsigned int chan; /* Physical channel number */ + unsigned int chan; /* DMAC channel number */ unsigned int vchan; /* Virtual channel number */ + unsigned int mode; unsigned int count; unsigned long sar; unsigned long dar; + const char **caps; + unsigned long flags; atomic_t busy; - struct semaphore sem; wait_queue_head_t wait_queue; struct sys_device dev; - char *name; + void *priv_data; }; struct dma_info { @@ -103,6 +109,12 @@ struct dma_info { struct dma_channel *channels; struct list_head list; + int first_channel_nr; +}; + +struct dma_chan_caps { + int ch_num; + const char **caplist; }; #define to_dma_channel(channel) container_of(channel, struct dma_channel, dev) @@ -121,6 +133,8 @@ extern int dma_xfer(unsigned int chan, unsigned long from, #define dma_read_page(chan, from, to) \ dma_read(chan, from, to, PAGE_SIZE) +extern int request_dma_bycap(const char **dmac, const char **caps, + const char *dev_id); extern int request_dma(unsigned int chan, const char *dev_id); extern void free_dma(unsigned int chan); extern int get_dma_residue(unsigned int chan); @@ -131,6 +145,10 @@ extern void dma_configure_channel(unsigned int chan, unsigned long flags); extern int register_dmac(struct dma_info *info); extern void unregister_dmac(struct dma_info *info); +extern struct dma_info *get_dma_info_by_name(const char *dmac_name); + +extern int dma_extend(unsigned int chan, unsigned long op, void *param); +extern int register_chan_caps(const char *dmac, struct dma_chan_caps *capslist); #ifdef CONFIG_SYSFS /* arch/sh/drivers/dma/dma-sysfs.c */ diff --git a/include/asm-sh/elf.h b/include/asm-sh/elf.h index fc050fd7645..43ca244564b 100644 --- a/include/asm-sh/elf.h +++ b/include/asm-sh/elf.h @@ -74,7 +74,7 @@ typedef struct user_fpu_struct elf_fpregset_t; #define ELF_ARCH EM_SH #define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE 4096 +#define ELF_EXEC_PAGESIZE PAGE_SIZE /* This is the location that an ET_DYN program is loaded if exec'ed. Typical use of this is to invoke "./ld.so someprog" to test out a new version of diff --git a/include/asm-sh/entry-macros.S b/include/asm-sh/entry-macros.S new file mode 100644 index 00000000000..500030eae7a --- /dev/null +++ b/include/asm-sh/entry-macros.S @@ -0,0 +1,33 @@ +! entry.S macro define + + .macro cli + stc sr, r0 + or #0xf0, r0 + ldc r0, sr + .endm + + .macro sti + mov #0xf0, r11 + extu.b r11, r11 + not r11, r11 + stc sr, r10 + and r11, r10 +#ifdef CONFIG_HAS_SR_RB + stc k_g_imask, r11 + or r11, r10 +#endif + ldc r10, sr + .endm + + .macro get_current_thread_info, ti, tmp +#ifdef CONFIG_HAS_SR_RB + stc r7_bank, \ti +#else + mov #((THREAD_SIZE - 1) >> 10) ^ 0xff, \tmp + shll8 \tmp + shll2 \tmp + mov r15, \ti + and \tmp, \ti +#endif + .endm + diff --git a/include/asm-sh/irq-sh73180.h b/include/asm-sh/irq-sh73180.h deleted file mode 100644 index b28af9a69d7..00000000000 --- a/include/asm-sh/irq-sh73180.h +++ /dev/null @@ -1,314 +0,0 @@ -#ifndef __ASM_SH_IRQ_SH73180_H -#define __ASM_SH_IRQ_SH73180_H - -/* - * linux/include/asm-sh/irq-sh73180.h - * - * Copyright (C) 2004 Takashi SHUDO <shudo@hitachi-ul.co.jp> - */ - -#undef INTC_IPRA -#undef INTC_IPRB -#undef INTC_IPRC -#undef INTC_IPRD - -#undef DMTE0_IRQ -#undef DMTE1_IRQ -#undef DMTE2_IRQ -#undef DMTE3_IRQ -#undef DMTE4_IRQ -#undef DMTE5_IRQ -#undef DMTE6_IRQ -#undef DMTE7_IRQ -#undef DMAE_IRQ -#undef DMA_IPR_ADDR -#undef DMA_IPR_POS -#undef DMA_PRIORITY - -#undef INTC_IMCR0 -#undef INTC_IMCR1 -#undef INTC_IMCR2 -#undef INTC_IMCR3 -#undef INTC_IMCR4 -#undef INTC_IMCR5 -#undef INTC_IMCR6 -#undef INTC_IMCR7 -#undef INTC_IMCR8 -#undef INTC_IMCR9 -#undef INTC_IMCR10 - - -#define INTC_IPRA 0xA4080000UL -#define INTC_IPRB 0xA4080004UL -#define INTC_IPRC 0xA4080008UL -#define INTC_IPRD 0xA408000CUL -#define INTC_IPRE 0xA4080010UL -#define INTC_IPRF 0xA4080014UL -#define INTC_IPRG 0xA4080018UL -#define INTC_IPRH 0xA408001CUL -#define INTC_IPRI 0xA4080020UL -#define INTC_IPRJ 0xA4080024UL -#define INTC_IPRK 0xA4080028UL - -#define INTC_IMR0 0xA4080080UL -#define INTC_IMR1 0xA4080084UL -#define INTC_IMR2 0xA4080088UL -#define INTC_IMR3 0xA408008CUL -#define INTC_IMR4 0xA4080090UL -#define INTC_IMR5 0xA4080094UL -#define INTC_IMR6 0xA4080098UL -#define INTC_IMR7 0xA408009CUL -#define INTC_IMR8 0xA40800A0UL -#define INTC_IMR9 0xA40800A4UL -#define INTC_IMR10 0xA40800A8UL -#define INTC_IMR11 0xA40800ACUL - -#define INTC_IMCR0 0xA40800C0UL -#define INTC_IMCR1 0xA40800C4UL -#define INTC_IMCR2 0xA40800C8UL -#define INTC_IMCR3 0xA40800CCUL -#define INTC_IMCR4 0xA40800D0UL -#define INTC_IMCR5 0xA40800D4UL -#define INTC_IMCR6 0xA40800D8UL -#define INTC_IMCR7 0xA40800DCUL -#define INTC_IMCR8 0xA40800E0UL -#define INTC_IMCR9 0xA40800E4UL -#define INTC_IMCR10 0xA40800E8UL -#define INTC_IMCR11 0xA40800ECUL - -#define INTC_ICR0 0xA4140000UL -#define INTC_ICR1 0xA414001CUL - -#define INTMSK0 0xa4140044 -#define INTMSKCLR0 0xa4140064 -#define INTC_INTPRI0 0xa4140010 - -/* - NOTE: - - *_IRQ = (INTEVT2 - 0x200)/0x20 -*/ - -/* TMU0 */ -#define TMU0_IRQ 16 -#define TMU0_IPR_ADDR INTC_IPRA -#define TMU0_IPR_POS 3 -#define TMU0_PRIORITY 2 - -#define TIMER_IRQ 16 -#define TIMER_IPR_ADDR INTC_IPRA -#define TIMER_IPR_POS 3 -#define TIMER_PRIORITY 2 - -/* TMU1 */ -#define TMU1_IRQ 17 -#define TMU1_IPR_ADDR INTC_IPRA -#define TMU1_IPR_POS 2 -#define TMU1_PRIORITY 2 - -/* TMU2 */ -#define TMU2_IRQ 18 -#define TMU2_IPR_ADDR INTC_IPRA -#define TMU2_IPR_POS 1 -#define TMU2_PRIORITY 2 - -/* LCDC */ -#define LCDC_IRQ 28 -#define LCDC_IPR_ADDR INTC_IPRB -#define LCDC_IPR_POS 2 -#define LCDC_PRIORITY 2 - -/* VIO (Video I/O) */ -#define CEU_IRQ 52 -#define BEU_IRQ 53 -#define VEU_IRQ 54 -#define VOU_IRQ 55 -#define VIO_IPR_ADDR INTC_IPRE -#define VIO_IPR_POS 2 -#define VIO_PRIORITY 2 - -/* MFI (Multi Functional Interface) */ -#define MFI_IRQ 56 -#define MFI_IPR_ADDR INTC_IPRE -#define MFI_IPR_POS 1 -#define MFI_PRIORITY 2 - -/* VPU (Video Processing Unit) */ -#define VPU_IRQ 60 -#define VPU_IPR_ADDR INTC_IPRE -#define VPU_IPR_POS 0 -#define VPU_PRIORITY 2 - -/* 3DG */ -#define TDG_IRQ 63 -#define TDG_IPR_ADDR INTC_IPRJ -#define TDG_IPR_POS 2 -#define TDG_PRIORITY 2 - -/* DMAC(1) */ -#define DMTE0_IRQ 48 -#define DMTE1_IRQ 49 -#define DMTE2_IRQ 50 -#define DMTE3_IRQ 51 -#define DMA1_IPR_ADDR INTC_IPRE -#define DMA1_IPR_POS 3 -#define DMA1_PRIORITY 7 - -/* DMAC(2) */ -#define DMTE4_IRQ 76 -#define DMTE5_IRQ 77 -#define DMA2_IPR_ADDR INTC_IPRF -#define DMA2_IPR_POS 2 -#define DMA2_PRIORITY 7 - -/* SCIF0 */ -#define SCIF_ERI_IRQ 80 -#define SCIF_RXI_IRQ 81 -#define SCIF_BRI_IRQ 82 -#define SCIF_TXI_IRQ 83 -#define SCIF_IPR_ADDR INTC_IPRG -#define SCIF_IPR_POS 3 -#define SCIF_PRIORITY 3 - -/* SIOF0 */ -#define SIOF0_IRQ 84 -#define SIOF0_IPR_ADDR INTC_IPRH -#define SIOF0_IPR_POS 3 -#define SIOF0_PRIORITY 3 - -/* FLCTL (Flash Memory Controller) */ -#define FLSTE_IRQ 92 -#define FLTEND_IRQ 93 -#define FLTRQ0_IRQ 94 -#define FLTRQ1_IRQ 95 -#define FLCTL_IPR_ADDR INTC_IPRH -#define FLCTL_IPR_POS 1 -#define FLCTL_PRIORITY 3 - -/* IIC(0) (IIC Bus Interface) */ -#define IIC0_ALI_IRQ 96 -#define IIC0_TACKI_IRQ 97 -#define IIC0_WAITI_IRQ 98 -#define IIC0_DTEI_IRQ 99 -#define IIC0_IPR_ADDR INTC_IPRH -#define IIC0_IPR_POS 0 -#define IIC0_PRIORITY 3 - -/* IIC(1) (IIC Bus Interface) */ -#define IIC1_ALI_IRQ 44 -#define IIC1_TACKI_IRQ 45 -#define IIC1_WAITI_IRQ 46 -#define IIC1_DTEI_IRQ 47 -#define IIC1_IPR_ADDR INTC_IPRG -#define IIC1_IPR_POS 0 -#define IIC1_PRIORITY 3 - -/* SIO0 */ -#define SIO0_IRQ 88 -#define SIO0_IPR_ADDR INTC_IPRI -#define SIO0_IPR_POS 3 -#define SIO0_PRIORITY 3 - -/* SDHI */ -#define SDHI_SDHII0_IRQ 100 -#define SDHI_SDHII1_IRQ 101 -#define SDHI_SDHII2_IRQ 102 -#define SDHI_SDHII3_IRQ 103 -#define SDHI_IPR_ADDR INTC_IPRK -#define SDHI_IPR_POS 0 -#define SDHI_PRIORITY 3 - -/* SIU (Sound Interface Unit) */ -#define SIU_IRQ 108 -#define SIU_IPR_ADDR INTC_IPRJ -#define SIU_IPR_POS 1 -#define SIU_PRIORITY 3 - -#define PORT_PACR 0xA4050100UL -#define PORT_PBCR 0xA4050102UL -#define PORT_PCCR 0xA4050104UL -#define PORT_PDCR 0xA4050106UL -#define PORT_PECR 0xA4050108UL -#define PORT_PFCR 0xA405010AUL -#define PORT_PGCR 0xA405010CUL -#define PORT_PHCR 0xA405010EUL -#define PORT_PJCR 0xA4050110UL -#define PORT_PKCR 0xA4050112UL -#define PORT_PLCR 0xA4050114UL -#define PORT_SCPCR 0xA4050116UL -#define PORT_PMCR 0xA4050118UL -#define PORT_PNCR 0xA405011AUL -#define PORT_PQCR 0xA405011CUL -#define PORT_PRCR 0xA405011EUL -#define PORT_PTCR 0xA405014CUL -#define PORT_PUCR 0xA405014EUL -#define PORT_PVCR 0xA4050150UL - -#define PORT_PSELA 0xA4050140UL -#define PORT_PSELB 0xA4050142UL -#define PORT_PSELC 0xA4050144UL -#define PORT_PSELE 0xA4050158UL - -#define PORT_HIZCRA 0xA4050146UL -#define PORT_HIZCRB 0xA4050148UL -#define PORT_DRVCR 0xA405014AUL - -#define PORT_PADR 0xA4050120UL -#define PORT_PBDR 0xA4050122UL -#define PORT_PCDR 0xA4050124UL -#define PORT_PDDR 0xA4050126UL -#define PORT_PEDR 0xA4050128UL -#define PORT_PFDR 0xA405012AUL -#define PORT_PGDR 0xA405012CUL -#define PORT_PHDR 0xA405012EUL -#define PORT_PJDR 0xA4050130UL -#define PORT_PKDR 0xA4050132UL -#define PORT_PLDR 0xA4050134UL -#define PORT_SCPDR 0xA4050136UL -#define PORT_PMDR 0xA4050138UL -#define PORT_PNDR 0xA405013AUL -#define PORT_PQDR 0xA405013CUL -#define PORT_PRDR 0xA405013EUL -#define PORT_PTDR 0xA405016CUL -#define PORT_PUDR 0xA405016EUL -#define PORT_PVDR 0xA4050170UL - -#define IRQ0_IRQ 32 -#define IRQ1_IRQ 33 -#define IRQ2_IRQ 34 -#define IRQ3_IRQ 35 -#define IRQ4_IRQ 36 -#define IRQ5_IRQ 37 -#define IRQ6_IRQ 38 -#define IRQ7_IRQ 39 - -#define INTPRI00 0xA4140010UL - -#define IRQ0_IPR_ADDR INTPRI00 -#define IRQ1_IPR_ADDR INTPRI00 -#define IRQ2_IPR_ADDR INTPRI00 -#define IRQ3_IPR_ADDR INTPRI00 -#define IRQ4_IPR_ADDR INTPRI00 -#define IRQ5_IPR_ADDR INTPRI00 -#define IRQ6_IPR_ADDR INTPRI00 -#define IRQ7_IPR_ADDR INTPRI00 - -#define IRQ0_IPR_POS 7 -#define IRQ1_IPR_POS 6 -#define IRQ2_IPR_POS 5 -#define IRQ3_IPR_POS 4 -#define IRQ4_IPR_POS 3 -#define IRQ5_IPR_POS 2 -#define IRQ6_IPR_POS 1 -#define IRQ7_IPR_POS 0 - -#define IRQ0_PRIORITY 1 -#define IRQ1_PRIORITY 1 -#define IRQ2_PRIORITY 1 -#define IRQ3_PRIORITY 1 -#define IRQ4_PRIORITY 1 -#define IRQ5_PRIORITY 1 -#define IRQ6_PRIORITY 1 -#define IRQ7_PRIORITY 1 - -#endif /* __ASM_SH_IRQ_SH73180_H */ diff --git a/include/asm-sh/irq-sh7343.h b/include/asm-sh/irq-sh7343.h deleted file mode 100644 index 5d15419b53b..00000000000 --- a/include/asm-sh/irq-sh7343.h +++ /dev/null @@ -1,317 +0,0 @@ -#ifndef __ASM_SH_IRQ_SH7343_H -#define __ASM_SH_IRQ_SH7343_H - -/* - * linux/include/asm-sh/irq-sh7343.h - * - * Copyright (C) 2006 Kenati Technologies Inc. - * Andre Mccurdy <andre@kenati.com> - * Ranjit Deshpande <ranjit@kenati.com> - */ - -#undef INTC_IPRA -#undef INTC_IPRB -#undef INTC_IPRC -#undef INTC_IPRD - -#undef DMTE0_IRQ -#undef DMTE1_IRQ -#undef DMTE2_IRQ -#undef DMTE3_IRQ -#undef DMTE4_IRQ -#undef DMTE5_IRQ -#undef DMTE6_IRQ -#undef DMTE7_IRQ -#undef DMAE_IRQ -#undef DMA_IPR_ADDR -#undef DMA_IPR_POS -#undef DMA_PRIORITY - -#undef INTC_IMCR0 -#undef INTC_IMCR1 -#undef INTC_IMCR2 -#undef INTC_IMCR3 -#undef INTC_IMCR4 -#undef INTC_IMCR5 -#undef INTC_IMCR6 -#undef INTC_IMCR7 -#undef INTC_IMCR8 -#undef INTC_IMCR9 -#undef INTC_IMCR10 - - -#define INTC_IPRA 0xA4080000UL -#define INTC_IPRB 0xA4080004UL -#define INTC_IPRC 0xA4080008UL -#define INTC_IPRD 0xA408000CUL -#define INTC_IPRE 0xA4080010UL -#define INTC_IPRF 0xA4080014UL -#define INTC_IPRG 0xA4080018UL -#define INTC_IPRH 0xA408001CUL -#define INTC_IPRI 0xA4080020UL -#define INTC_IPRJ 0xA4080024UL -#define INTC_IPRK 0xA4080028UL -#define INTC_IPRL 0xA408002CUL - -#define INTC_IMR0 0xA4080080UL -#define INTC_IMR1 0xA4080084UL -#define INTC_IMR2 0xA4080088UL -#define INTC_IMR3 0xA408008CUL -#define INTC_IMR4 0xA4080090UL -#define INTC_IMR5 0xA4080094UL -#define INTC_IMR6 0xA4080098UL -#define INTC_IMR7 0xA408009CUL -#define INTC_IMR8 0xA40800A0UL -#define INTC_IMR9 0xA40800A4UL -#define INTC_IMR10 0xA40800A8UL -#define INTC_IMR11 0xA40800ACUL - -#define INTC_IMCR0 0xA40800C0UL -#define INTC_IMCR1 0xA40800C4UL -#define INTC_IMCR2 0xA40800C8UL -#define INTC_IMCR3 0xA40800CCUL -#define INTC_IMCR4 0xA40800D0UL -#define INTC_IMCR5 0xA40800D4UL -#define INTC_IMCR6 0xA40800D8UL -#define INTC_IMCR7 0xA40800DCUL -#define INTC_IMCR8 0xA40800E0UL -#define INTC_IMCR9 0xA40800E4UL -#define INTC_IMCR10 0xA40800E8UL -#define INTC_IMCR11 0xA40800ECUL - -#define INTC_ICR0 0xA4140000UL -#define INTC_ICR1 0xA414001CUL - -#define INTMSK0 0xa4140044 -#define INTMSKCLR0 0xa4140064 -#define INTC_INTPRI0 0xa4140010 - -/* - NOTE: - - *_IRQ = (INTEVT2 - 0x200)/0x20 -*/ - -/* TMU0 */ -#define TMU0_IRQ 16 -#define TMU0_IPR_ADDR INTC_IPRA -#define TMU0_IPR_POS 3 -#define TMU0_PRIORITY 2 - -#define TIMER_IRQ 16 -#define TIMER_IPR_ADDR INTC_IPRA -#define TIMER_IPR_POS 3 -#define TIMER_PRIORITY 2 - -/* TMU1 */ -#define TMU1_IRQ 17 -#define TMU1_IPR_ADDR INTC_IPRA -#define TMU1_IPR_POS 2 -#define TMU1_PRIORITY 2 - -/* TMU2 */ -#define TMU2_IRQ 18 -#define TMU2_IPR_ADDR INTC_IPRA -#define TMU2_IPR_POS 1 -#define TMU2_PRIORITY 2 - -/* LCDC */ -#define LCDC_IRQ 28 -#define LCDC_IPR_ADDR INTC_IPRB -#define LCDC_IPR_POS 2 -#define LCDC_PRIORITY 2 - -/* VIO (Video I/O) */ -#define CEU_IRQ 52 -#define BEU_IRQ 53 -#define VEU_IRQ 54 -#define VOU_IRQ 55 -#define VIO_IPR_ADDR INTC_IPRE -#define VIO_IPR_POS 2 -#define VIO_PRIORITY 2 - -/* MFI (Multi Functional Interface) */ -#define MFI_IRQ 56 -#define MFI_IPR_ADDR INTC_IPRE -#define MFI_IPR_POS 1 -#define MFI_PRIORITY 2 - -/* VPU (Video Processing Unit) */ -#define VPU_IRQ 60 -#define VPU_IPR_ADDR INTC_IPRE -#define VPU_IPR_POS 0 -#define VPU_PRIORITY 2 - -/* 3DG */ -#define TDG_IRQ 63 -#define TDG_IPR_ADDR INTC_IPRJ -#define TDG_IPR_POS 2 -#define TDG_PRIORITY 2 - -/* DMAC(1) */ -#define DMTE0_IRQ 48 -#define DMTE1_IRQ 49 -#define DMTE2_IRQ 50 -#define DMTE3_IRQ 51 -#define DMA1_IPR_ADDR INTC_IPRE -#define DMA1_IPR_POS 3 -#define DMA1_PRIORITY 7 - -/* DMAC(2) */ -#define DMTE4_IRQ 76 -#define DMTE5_IRQ 77 -#define DMA2_IPR_ADDR INTC_IPRF -#define DMA2_IPR_POS 2 -#define DMA2_PRIORITY 7 - -/* SCIF0 */ -#define SCIF_ERI_IRQ 80 -#define SCIF_RXI_IRQ 81 -#define SCIF_BRI_IRQ 82 -#define SCIF_TXI_IRQ 83 -#define SCIF_IPR_ADDR INTC_IPRG -#define SCIF_IPR_POS 3 -#define SCIF_PRIORITY 3 - -/* SIOF0 */ -#define SIOF0_IRQ 84 -#define SIOF0_IPR_ADDR INTC_IPRH -#define SIOF0_IPR_POS 3 -#define SIOF0_PRIORITY 3 - -/* FLCTL (Flash Memory Controller) */ -#define FLSTE_IRQ 92 -#define FLTEND_IRQ 93 -#define FLTRQ0_IRQ 94 -#define FLTRQ1_IRQ 95 -#define FLCTL_IPR_ADDR INTC_IPRH -#define FLCTL_IPR_POS 1 -#define FLCTL_PRIORITY 3 - -/* IIC(0) (IIC Bus Interface) */ -#define IIC0_ALI_IRQ 96 -#define IIC0_TACKI_IRQ 97 -#define IIC0_WAITI_IRQ 98 -#define IIC0_DTEI_IRQ 99 -#define IIC0_IPR_ADDR INTC_IPRH -#define IIC0_IPR_POS 0 -#define IIC0_PRIORITY 3 - -/* IIC(1) (IIC Bus Interface) */ -#define IIC1_ALI_IRQ 44 -#define IIC1_TACKI_IRQ 45 -#define IIC1_WAITI_IRQ 46 -#define IIC1_DTEI_IRQ 47 -#define IIC1_IPR_ADDR INTC_IPRI -#define IIC1_IPR_POS 0 -#define IIC1_PRIORITY 3 - -/* SIO0 */ -#define SIO0_IRQ 88 -#define SIO0_IPR_ADDR INTC_IPRI -#define SIO0_IPR_POS 3 -#define SIO0_PRIORITY 3 - -/* SDHI */ -#define SDHI_SDHII0_IRQ 100 -#define SDHI_SDHII1_IRQ 101 -#define SDHI_SDHII2_IRQ 102 -#define SDHI_SDHII3_IRQ 103 -#define SDHI_IPR_ADDR INTC_IPRK -#define SDHI_IPR_POS 0 -#define SDHI_PRIORITY 3 - -/* SIU (Sound Interface Unit) */ -#define SIU_IRQ 108 -#define SIU_IPR_ADDR INTC_IPRJ -#define SIU_IPR_POS 1 -#define SIU_PRIORITY 3 - -#define PORT_PACR 0xA4050100UL -#define PORT_PBCR 0xA4050102UL -#define PORT_PCCR 0xA4050104UL -#define PORT_PDCR 0xA4050106UL -#define PORT_PECR 0xA4050108UL -#define PORT_PFCR 0xA405010AUL -#define PORT_PGCR 0xA405010CUL -#define PORT_PHCR 0xA405010EUL -#define PORT_PJCR 0xA4050110UL -#define PORT_PKCR 0xA4050112UL -#define PORT_PLCR 0xA4050114UL -#define PORT_SCPCR 0xA4050116UL -#define PORT_PMCR 0xA4050118UL -#define PORT_PNCR 0xA405011AUL -#define PORT_PQCR 0xA405011CUL -#define PORT_PRCR 0xA405011EUL -#define PORT_PTCR 0xA405014CUL -#define PORT_PUCR 0xA405014EUL -#define PORT_PVCR 0xA4050150UL - -#define PORT_PSELA 0xA4050140UL -#define PORT_PSELB 0xA4050142UL -#define PORT_PSELC 0xA4050144UL -#define PORT_PSELE 0xA4050158UL - -#define PORT_HIZCRA 0xA4050146UL -#define PORT_HIZCRB 0xA4050148UL -#define PORT_DRVCR 0xA405014AUL - -#define PORT_PADR 0xA4050120UL -#define PORT_PBDR 0xA4050122UL -#define PORT_PCDR 0xA4050124UL -#define PORT_PDDR 0xA4050126UL -#define PORT_PEDR 0xA4050128UL -#define PORT_PFDR 0xA405012AUL -#define PORT_PGDR 0xA405012CUL -#define PORT_PHDR 0xA405012EUL -#define PORT_PJDR 0xA4050130UL -#define PORT_PKDR 0xA4050132UL -#define PORT_PLDR 0xA4050134UL -#define PORT_SCPDR 0xA4050136UL -#define PORT_PMDR 0xA4050138UL -#define PORT_PNDR 0xA405013AUL -#define PORT_PQDR 0xA405013CUL -#define PORT_PRDR 0xA405013EUL -#define PORT_PTDR 0xA405016CUL -#define PORT_PUDR 0xA405016EUL -#define PORT_PVDR 0xA4050170UL - -#define IRQ0_IRQ 32 -#define IRQ1_IRQ 33 -#define IRQ2_IRQ 34 -#define IRQ3_IRQ 35 -#define IRQ4_IRQ 36 -#define IRQ5_IRQ 37 -#define IRQ6_IRQ 38 -#define IRQ7_IRQ 39 - -#define INTPRI00 0xA4140010UL - -#define IRQ0_IPR_ADDR INTPRI00 -#define IRQ1_IPR_ADDR INTPRI00 -#define IRQ2_IPR_ADDR INTPRI00 -#define IRQ3_IPR_ADDR INTPRI00 -#define IRQ4_IPR_ADDR INTPRI00 -#define IRQ5_IPR_ADDR INTPRI00 -#define IRQ6_IPR_ADDR INTPRI00 -#define IRQ7_IPR_ADDR INTPRI00 - -#define IRQ0_IPR_POS 7 -#define IRQ1_IPR_POS 6 -#define IRQ2_IPR_POS 5 -#define IRQ3_IPR_POS 4 -#define IRQ4_IPR_POS 3 -#define IRQ5_IPR_POS 2 -#define IRQ6_IPR_POS 1 -#define IRQ7_IPR_POS 0 - -#define IRQ0_PRIORITY 1 -#define IRQ1_PRIORITY 1 -#define IRQ2_PRIORITY 1 -#define IRQ3_PRIORITY 1 -#define IRQ4_PRIORITY 1 -#define IRQ5_PRIORITY 1 -#define IRQ6_PRIORITY 1 -#define IRQ7_PRIORITY 1 - -#endif /* __ASM_SH_IRQ_SH7343_H */ diff --git a/include/asm-sh/irq-sh7780.h b/include/asm-sh/irq-sh7780.h deleted file mode 100644 index 19912ae6a7f..00000000000 --- a/include/asm-sh/irq-sh7780.h +++ /dev/null @@ -1,311 +0,0 @@ -#ifndef __ASM_SH_IRQ_SH7780_H -#define __ASM_SH_IRQ_SH7780_H - -/* - * linux/include/asm-sh/irq-sh7780.h - * - * Copyright (C) 2004 Takashi SHUDO <shudo@hitachi-ul.co.jp> - */ -#define INTC_BASE 0xffd00000 -#define INTC_ICR0 (INTC_BASE+0x0) -#define INTC_ICR1 (INTC_BASE+0x1c) -#define INTC_INTPRI (INTC_BASE+0x10) -#define INTC_INTREQ (INTC_BASE+0x24) -#define INTC_INTMSK0 (INTC_BASE+0x44) -#define INTC_INTMSK1 (INTC_BASE+0x48) -#define INTC_INTMSK2 (INTC_BASE+0x40080) -#define INTC_INTMSKCLR0 (INTC_BASE+0x64) -#define INTC_INTMSKCLR1 (INTC_BASE+0x68) -#define INTC_INTMSKCLR2 (INTC_BASE+0x40084) -#define INTC_NMIFCR (INTC_BASE+0xc0) -#define INTC_USERIMASK (INTC_BASE+0x30000) - -#define INTC_INT2PRI0 (INTC_BASE+0x40000) -#define INTC_INT2PRI1 (INTC_BASE+0x40004) -#define INTC_INT2PRI2 (INTC_BASE+0x40008) -#define INTC_INT2PRI3 (INTC_BASE+0x4000c) -#define INTC_INT2PRI4 (INTC_BASE+0x40010) -#define INTC_INT2PRI5 (INTC_BASE+0x40014) -#define INTC_INT2PRI6 (INTC_BASE+0x40018) -#define INTC_INT2PRI7 (INTC_BASE+0x4001c) -#define INTC_INT2A0 (INTC_BASE+0x40030) -#define INTC_INT2A1 (INTC_BASE+0x40034) -#define INTC_INT2MSKR (INTC_BASE+0x40038) -#define INTC_INT2MSKCR (INTC_BASE+0x4003c) -#define INTC_INT2B0 (INTC_BASE+0x40040) -#define INTC_INT2B1 (INTC_BASE+0x40044) -#define INTC_INT2B2 (INTC_BASE+0x40048) -#define INTC_INT2B3 (INTC_BASE+0x4004c) -#define INTC_INT2B4 (INTC_BASE+0x40050) -#define INTC_INT2B5 (INTC_BASE+0x40054) -#define INTC_INT2B6 (INTC_BASE+0x40058) -#define INTC_INT2B7 (INTC_BASE+0x4005c) -#define INTC_INT2GPIC (INTC_BASE+0x40090) -/* - NOTE: - *_IRQ = (INTEVT2 - 0x200)/0x20 -*/ -/* IRQ 0-7 line external int*/ -#define IRQ0_IRQ 2 -#define IRQ0_IPR_ADDR INTC_INTPRI -#define IRQ0_IPR_POS 7 -#define IRQ0_PRIORITY 2 - -#define IRQ1_IRQ 4 -#define IRQ1_IPR_ADDR INTC_INTPRI -#define IRQ1_IPR_POS 6 -#define IRQ1_PRIORITY 2 - -#define IRQ2_IRQ 6 -#define IRQ2_IPR_ADDR INTC_INTPRI -#define IRQ2_IPR_POS 5 -#define IRQ2_PRIORITY 2 - -#define IRQ3_IRQ 8 -#define IRQ3_IPR_ADDR INTC_INTPRI -#define IRQ3_IPR_POS 4 -#define IRQ3_PRIORITY 2 - -#define IRQ4_IRQ 10 -#define IRQ4_IPR_ADDR INTC_INTPRI -#define IRQ4_IPR_POS 3 -#define IRQ4_PRIORITY 2 - -#define IRQ5_IRQ 12 -#define IRQ5_IPR_ADDR INTC_INTPRI -#define IRQ5_IPR_POS 2 -#define IRQ5_PRIORITY 2 - -#define IRQ6_IRQ 14 -#define IRQ6_IPR_ADDR INTC_INTPRI -#define IRQ6_IPR_POS 1 -#define IRQ6_PRIORITY 2 - -#define IRQ7_IRQ 0 -#define IRQ7_IPR_ADDR INTC_INTPRI -#define IRQ7_IPR_POS 0 -#define IRQ7_PRIORITY 2 - -/* TMU */ -/* ch0 */ -#define TMU_IRQ 28 -#define TMU_IPR_ADDR INTC_INT2PRI0 -#define TMU_IPR_POS 3 -#define TMU_PRIORITY 2 - -#define TIMER_IRQ 28 -#define TIMER_IPR_ADDR INTC_INT2PRI0 -#define TIMER_IPR_POS 3 -#define TIMER_PRIORITY 2 - -/* ch 1*/ -#define TMU_CH1_IRQ 29 -#define TMU_CH1_IPR_ADDR INTC_INT2PRI0 -#define TMU_CH1_IPR_POS 2 -#define TMU_CH1_PRIORITY 2 - -#define TIMER1_IRQ 29 -#define TIMER1_IPR_ADDR INTC_INT2PRI0 -#define TIMER1_IPR_POS 2 -#define TIMER1_PRIORITY 2 - -/* ch 2*/ -#define TMU_CH2_IRQ 30 -#define TMU_CH2_IPR_ADDR INTC_INT2PRI0 -#define TMU_CH2_IPR_POS 1 -#define TMU_CH2_PRIORITY 2 -/* ch 2 Input capture */ -#define TMU_CH2IC_IRQ 31 -#define TMU_CH2IC_IPR_ADDR INTC_INT2PRI0 -#define TMU_CH2IC_IPR_POS 0 -#define TMU_CH2IC_PRIORITY 2 -/* ch 3 */ -#define TMU_CH3_IRQ 96 -#define TMU_CH3_IPR_ADDR INTC_INT2PRI1 -#define TMU_CH3_IPR_POS 3 -#define TMU_CH3_PRIORITY 2 -/* ch 4 */ -#define TMU_CH4_IRQ 97 -#define TMU_CH4_IPR_ADDR INTC_INT2PRI1 -#define TMU_CH4_IPR_POS 2 -#define TMU_CH4_PRIORITY 2 -/* ch 5*/ -#define TMU_CH5_IRQ 98 -#define TMU_CH5_IPR_ADDR INTC_INT2PRI1 -#define TMU_CH5_IPR_POS 1 -#define TMU_CH5_PRIORITY 2 - -/* SCIF0 */ -#define SCIF0_ERI_IRQ 40 -#define SCIF0_RXI_IRQ 41 -#define SCIF0_BRI_IRQ 42 -#define SCIF0_TXI_IRQ 43 -#define SCIF0_IPR_ADDR INTC_INT2PRI2 -#define SCIF0_IPR_POS 3 -#define SCIF0_PRIORITY 3 - -/* SCIF1 */ -#define SCIF1_ERI_IRQ 76 -#define SCIF1_RXI_IRQ 77 -#define SCIF1_BRI_IRQ 78 -#define SCIF1_TXI_IRQ 79 -#define SCIF1_IPR_ADDR INTC_INT2PRI2 -#define SCIF1_IPR_POS 2 -#define SCIF1_PRIORITY 3 - -#define WDT_IRQ 27 -#define WDT_IPR_ADDR INTC_INT2PRI2 -#define WDT_IPR_POS 1 -#define WDT_PRIORITY 2 - -/* DMAC(0) */ -#define DMINT0_IRQ 34 -#define DMINT1_IRQ 35 -#define DMINT2_IRQ 36 -#define DMINT3_IRQ 37 -#define DMINT4_IRQ 44 -#define DMINT5_IRQ 45 -#define DMINT6_IRQ 46 -#define DMINT7_IRQ 47 -#define DMAE_IRQ 38 -#define DMA0_IPR_ADDR INTC_INT2PRI3 -#define DMA0_IPR_POS 2 -#define DMA0_PRIORITY 7 - -/* DMAC(1) */ -#define DMINT8_IRQ 92 -#define DMINT9_IRQ 93 -#define DMINT10_IRQ 94 -#define DMINT11_IRQ 95 -#define DMA1_IPR_ADDR INTC_INT2PRI3 -#define DMA1_IPR_POS 1 -#define DMA1_PRIORITY 7 - -#define DMTE0_IRQ DMINT0_IRQ -#define DMTE4_IRQ DMINT4_IRQ -#define DMA_IPR_ADDR DMA0_IPR_ADDR -#define DMA_IPR_POS DMA0_IPR_POS -#define DMA_PRIORITY DMA0_PRIORITY - -/* CMT */ -#define CMT_IRQ 56 -#define CMT_IPR_ADDR INTC_INT2PRI4 -#define CMT_IPR_POS 3 -#define CMT_PRIORITY 0 - -/* HAC */ -#define HAC_IRQ 60 -#define HAC_IPR_ADDR INTC_INT2PRI4 -#define HAC_IPR_POS 2 -#define CMT_PRIORITY 0 - -/* PCIC(0) */ -#define PCIC0_IRQ 64 -#define PCIC0_IPR_ADDR INTC_INT2PRI4 -#define PCIC0_IPR_POS 1 -#define PCIC0_PRIORITY 2 - -/* PCIC(1) */ -#define PCIC1_IRQ 65 -#define PCIC1_IPR_ADDR INTC_INT2PRI4 -#define PCIC1_IPR_POS 0 -#define PCIC1_PRIORITY 2 - -/* PCIC(2) */ -#define PCIC2_IRQ 66 -#define PCIC2_IPR_ADDR INTC_INT2PRI5 -#define PCIC2_IPR_POS 3 -#define PCIC2_PRIORITY 2 - -/* PCIC(3) */ -#define PCIC3_IRQ 67 -#define PCIC3_IPR_ADDR INTC_INT2PRI5 -#define PCIC3_IPR_POS 2 -#define PCIC3_PRIORITY 2 - -/* PCIC(4) */ -#define PCIC4_IRQ 68 -#define PCIC4_IPR_ADDR INTC_INT2PRI5 -#define PCIC4_IPR_POS 1 -#define PCIC4_PRIORITY 2 - -/* PCIC(5) */ -#define PCICERR_IRQ 69 -#define PCICPWD3_IRQ 70 -#define PCICPWD2_IRQ 71 -#define PCICPWD1_IRQ 72 -#define PCICPWD0_IRQ 73 -#define PCIC5_IPR_ADDR INTC_INT2PRI5 -#define PCIC5_IPR_POS 0 -#define PCIC5_PRIORITY 2 - -/* SIOF */ -#define SIOF_IRQ 80 -#define SIOF_IPR_ADDR INTC_INT2PRI6 -#define SIOF_IPR_POS 3 -#define SIOF_PRIORITY 3 - -/* HSPI */ -#define HSPI_IRQ 84 -#define HSPI_IPR_ADDR INTC_INT2PRI6 -#define HSPI_IPR_POS 2 -#define HSPI_PRIORITY 3 - -/* MMCIF */ -#define MMCIF_FSTAT_IRQ 88 -#define MMCIF_TRAN_IRQ 89 -#define MMCIF_ERR_IRQ 90 -#define MMCIF_FRDY_IRQ 91 -#define MMCIF_IPR_ADDR INTC_INT2PRI6 -#define MMCIF_IPR_POS 1 -#define HSPI_PRIORITY 3 - -/* SSI */ -#define SSI_IRQ 100 -#define SSI_IPR_ADDR INTC_INT2PRI6 -#define SSI_IPR_POS 0 -#define SSI_PRIORITY 3 - -/* FLCTL */ -#define FLCTL_FLSTE_IRQ 104 -#define FLCTL_FLTEND_IRQ 105 -#define FLCTL_FLTRQ0_IRQ 106 -#define FLCTL_FLTRQ1_IRQ 107 -#define FLCTL_IPR_ADDR INTC_INT2PRI7 -#define FLCTL_IPR_POS 3 -#define FLCTL_PRIORITY 3 - -/* GPIO */ -#define GPIO0_IRQ 108 -#define GPIO1_IRQ 109 -#define GPIO2_IRQ 110 -#define GPIO3_IRQ 111 -#define GPIO_IPR_ADDR INTC_INT2PRI7 -#define GPIO_IPR_POS 2 -#define GPIO_PRIORITY 3 - -#define INTC_TMU0_MSK 0 -#define INTC_TMU3_MSK 1 -#define INTC_RTC_MSK 2 -#define INTC_SCIF0_MSK 3 -#define INTC_SCIF1_MSK 4 -#define INTC_WDT_MSK 5 -#define INTC_HUID_MSK 7 -#define INTC_DMAC0_MSK 8 -#define INTC_DMAC1_MSK 9 -#define INTC_CMT_MSK 12 -#define INTC_HAC_MSK 13 -#define INTC_PCIC0_MSK 14 -#define INTC_PCIC1_MSK 15 -#define INTC_PCIC2_MSK 16 -#define INTC_PCIC3_MSK 17 -#define INTC_PCIC4_MSK 18 -#define INTC_PCIC5_MSK 19 -#define INTC_SIOF_MSK 20 -#define INTC_HSPI_MSK 21 -#define INTC_MMCIF_MSK 22 -#define INTC_SSI_MSK 23 -#define INTC_FLCTL_MSK 24 -#define INTC_GPIO_MSK 25 - -#endif /* __ASM_SH_IRQ_SH7780_H */ diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h index 6cd3e9e2a76..fd576088e47 100644 --- a/include/asm-sh/irq.h +++ b/include/asm-sh/irq.h @@ -1,233 +1,9 @@ #ifndef __ASM_SH_IRQ_H #define __ASM_SH_IRQ_H -/* - * - * linux/include/asm-sh/irq.h - * - * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi - * Copyright (C) 2000 Kazumoto Kojima - * Copyright (C) 2003 Paul Mundt - * - */ - #include <asm/machvec.h> #include <asm/ptrace.h> /* for pt_regs */ -#ifndef CONFIG_CPU_SUBTYPE_SH7780 - -#define INTC_DMAC0_MSK 0 - -#if defined(CONFIG_CPU_SH3) -#define INTC_IPRA 0xfffffee2UL -#define INTC_IPRB 0xfffffee4UL -#elif defined(CONFIG_CPU_SH4) -#define INTC_IPRA 0xffd00004UL -#define INTC_IPRB 0xffd00008UL -#define INTC_IPRC 0xffd0000cUL -#define INTC_IPRD 0xffd00010UL -#endif - -#define TIMER_IRQ 16 -#define TIMER_IPR_ADDR INTC_IPRA -#define TIMER_IPR_POS 3 -#define TIMER_PRIORITY 2 - -#define TIMER1_IRQ 17 -#define TIMER1_IPR_ADDR INTC_IPRA -#define TIMER1_IPR_POS 2 -#define TIMER1_PRIORITY 4 - -#define RTC_IRQ 22 -#define RTC_IPR_ADDR INTC_IPRA -#define RTC_IPR_POS 0 -#define RTC_PRIORITY TIMER_PRIORITY - -#if defined(CONFIG_CPU_SH3) -#define DMTE0_IRQ 48 -#define DMTE1_IRQ 49 -#define DMTE2_IRQ 50 -#define DMTE3_IRQ 51 -#define DMA_IPR_ADDR INTC_IPRE -#define DMA_IPR_POS 3 -#define DMA_PRIORITY 7 -#if defined(CONFIG_CPU_SUBTYPE_SH7300) -/* TMU2 */ -#define TIMER2_IRQ 18 -#define TIMER2_IPR_ADDR INTC_IPRA -#define TIMER2_IPR_POS 1 -#define TIMER2_PRIORITY 2 - -/* WDT */ -#define WDT_IRQ 27 -#define WDT_IPR_ADDR INTC_IPRB -#define WDT_IPR_POS 3 -#define WDT_PRIORITY 2 - -/* SIM (SIM Card Module) */ -#define SIM_ERI_IRQ 23 -#define SIM_RXI_IRQ 24 -#define SIM_TXI_IRQ 25 -#define SIM_TEND_IRQ 26 -#define SIM_IPR_ADDR INTC_IPRB -#define SIM_IPR_POS 1 -#define SIM_PRIORITY 2 - -/* VIO (Video I/O) */ -#define VIO_IRQ 52 -#define VIO_IPR_ADDR INTC_IPRE -#define VIO_IPR_POS 2 -#define VIO_PRIORITY 2 - -/* MFI (Multi Functional Interface) */ -#define MFI_IRQ 56 -#define MFI_IPR_ADDR INTC_IPRE -#define MFI_IPR_POS 1 -#define MFI_PRIORITY 2 - -/* VPU (Video Processing Unit) */ -#define VPU_IRQ 60 -#define VPU_IPR_ADDR INTC_IPRE -#define VPU_IPR_POS 0 -#define VPU_PRIORITY 2 - -/* KEY (Key Scan Interface) */ -#define KEY_IRQ 79 -#define KEY_IPR_ADDR INTC_IPRF -#define KEY_IPR_POS 3 -#define KEY_PRIORITY 2 - -/* CMT (Compare Match Timer) */ -#define CMT_IRQ 104 -#define CMT_IPR_ADDR INTC_IPRF -#define CMT_IPR_POS 0 -#define CMT_PRIORITY 2 - -/* DMAC(1) */ -#define DMTE0_IRQ 48 -#define DMTE1_IRQ 49 -#define DMTE2_IRQ 50 -#define DMTE3_IRQ 51 -#define DMA1_IPR_ADDR INTC_IPRE -#define DMA1_IPR_POS 3 -#define DMA1_PRIORITY 7 - -/* DMAC(2) */ -#define DMTE4_IRQ 76 -#define DMTE5_IRQ 77 -#define DMA2_IPR_ADDR INTC_IPRF -#define DMA2_IPR_POS 2 -#define DMA2_PRIORITY 7 - -/* SIOF0 */ -#define SIOF0_IRQ 84 -#define SIOF0_IPR_ADDR INTC_IPRH -#define SIOF0_IPR_POS 3 -#define SIOF0_PRIORITY 3 - -/* FLCTL (Flash Memory Controller) */ -#define FLSTE_IRQ 92 -#define FLTEND_IRQ 93 -#define FLTRQ0_IRQ 94 -#define FLTRQ1_IRQ 95 -#define FLCTL_IPR_ADDR INTC_IPRH -#define FLCTL_IPR_POS 1 -#define FLCTL_PRIORITY 3 - -/* IIC (IIC Bus Interface) */ -#define IIC_ALI_IRQ 96 -#define IIC_TACKI_IRQ 97 -#define IIC_WAITI_IRQ 98 -#define IIC_DTEI_IRQ 99 -#define IIC_IPR_ADDR INTC_IPRH -#define IIC_IPR_POS 0 -#define IIC_PRIORITY 3 - -/* SIO0 */ -#define SIO0_IRQ 88 -#define SIO0_IPR_ADDR INTC_IPRI -#define SIO0_IPR_POS 3 -#define SIO0_PRIORITY 3 - -/* SIU (Sound Interface Unit) */ -#define SIU_IRQ 108 -#define SIU_IPR_ADDR INTC_IPRJ -#define SIU_IPR_POS 1 -#define SIU_PRIORITY 3 - -#endif -#elif defined(CONFIG_CPU_SH4) -#define DMTE0_IRQ 34 -#define DMTE1_IRQ 35 -#define DMTE2_IRQ 36 -#define DMTE3_IRQ 37 -#define DMTE4_IRQ 44 /* 7751R only */ -#define DMTE5_IRQ 45 /* 7751R only */ -#define DMTE6_IRQ 46 /* 7751R only */ -#define DMTE7_IRQ 47 /* 7751R only */ -#define DMAE_IRQ 38 -#define DMA_IPR_ADDR INTC_IPRC -#define DMA_IPR_POS 2 -#define DMA_PRIORITY 7 -#endif - -#if defined (CONFIG_CPU_SUBTYPE_SH7707) || defined (CONFIG_CPU_SUBTYPE_SH7708) || \ - defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750) || \ - defined (CONFIG_CPU_SUBTYPE_SH7751) || defined (CONFIG_CPU_SUBTYPE_SH7706) -#define SCI_ERI_IRQ 23 -#define SCI_RXI_IRQ 24 -#define SCI_TXI_IRQ 25 -#define SCI_IPR_ADDR INTC_IPRB -#define SCI_IPR_POS 1 -#define SCI_PRIORITY 3 -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7300) -#define SCIF0_IRQ 80 -#define SCIF0_IPR_ADDR INTC_IPRG -#define SCIF0_IPR_POS 3 -#define SCIF0_PRIORITY 3 -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7706) || \ - defined(CONFIG_CPU_SUBTYPE_SH7707) || \ - defined(CONFIG_CPU_SUBTYPE_SH7709) -#define SCIF_ERI_IRQ 56 -#define SCIF_RXI_IRQ 57 -#define SCIF_BRI_IRQ 58 -#define SCIF_TXI_IRQ 59 -#define SCIF_IPR_ADDR INTC_IPRE -#define SCIF_IPR_POS 1 -#define SCIF_PRIORITY 3 - -#define IRDA_ERI_IRQ 52 -#define IRDA_RXI_IRQ 53 -#define IRDA_BRI_IRQ 54 -#define IRDA_TXI_IRQ 55 -#define IRDA_IPR_ADDR INTC_IPRE -#define IRDA_IPR_POS 2 -#define IRDA_PRIORITY 3 -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || \ - defined(CONFIG_CPU_SUBTYPE_ST40STB1) || defined(CONFIG_CPU_SUBTYPE_SH4_202) -#define SCIF_ERI_IRQ 40 -#define SCIF_RXI_IRQ 41 -#define SCIF_BRI_IRQ 42 -#define SCIF_TXI_IRQ 43 -#define SCIF_IPR_ADDR INTC_IPRC -#define SCIF_IPR_POS 1 -#define SCIF_PRIORITY 3 -#if defined(CONFIG_CPU_SUBTYPE_ST40STB1) -#define SCIF1_ERI_IRQ 23 -#define SCIF1_RXI_IRQ 24 -#define SCIF1_BRI_IRQ 25 -#define SCIF1_TXI_IRQ 26 -#define SCIF1_IPR_ADDR INTC_IPRB -#define SCIF1_IPR_POS 1 -#define SCIF1_PRIORITY 3 -#endif /* ST40STB1 */ - -#endif /* 775x / SH4-202 / ST40STB1 */ -#endif /* 7780 */ - /* NR_IRQS is made from three components: * 1. ONCHIP_NR_IRQS - number of IRLS + on-chip peripherial modules * 2. PINT_NR_IRQS - number of PINT interrupts @@ -265,6 +41,10 @@ # define ONCHIP_NR_IRQS 109 #elif defined(CONFIG_CPU_SUBTYPE_SH7780) # define ONCHIP_NR_IRQS 111 +#elif defined(CONFIG_CPU_SUBTYPE_SH7206) +# define ONCHIP_NR_IRQS 256 +#elif defined(CONFIG_CPU_SUBTYPE_SH7619) +# define ONCHIP_NR_IRQS 128 #elif defined(CONFIG_SH_UNKNOWN) /* Most be last */ # define ONCHIP_NR_IRQS 144 #endif @@ -312,9 +92,11 @@ /* NR_IRQS. 1+2+3 */ #define NR_IRQS (ONCHIP_NR_IRQS + PINT_NR_IRQS + OFFCHIP_NR_IRQS) -extern void disable_irq(unsigned int); -extern void disable_irq_nosync(unsigned int); -extern void enable_irq(unsigned int); +/* + * Convert back and forth between INTEVT and IRQ values. + */ +#define evt2irq(evt) (((evt) >> 5) - 16) +#define irq2evt(irq) (((irq) + 16) << 5) /* * Simple Mask Register Support @@ -327,362 +109,36 @@ extern unsigned short *irq_mask_register; */ void init_IRQ_pint(void); +/* + * The shift value is now the number of bits to shift, not the number of + * bits/4. This is to make it easier to read the value directly from the + * datasheets. The IPR address, addr, will be set from ipr_idx via the + * map_ipridx_to_addr function. + */ struct ipr_data { unsigned int irq; - unsigned int addr; /* Address of Interrupt Priority Register */ - int shift; /* Shifts of the 16-bit data */ + int ipr_idx; /* Index for the IPR registered */ + int shift; /* Number of bits to shift the data */ int priority; /* The priority */ + unsigned int addr; /* Address of Interrupt Priority Register */ }; /* - * Function for "on chip support modules". + * Given an IPR IDX, map the value to an IPR register address. */ -extern void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs); -extern void make_imask_irq(unsigned int irq); - -#if defined(CONFIG_CPU_SUBTYPE_SH7300) -#undef INTC_IPRA -#undef INTC_IPRB -#define INTC_IPRA 0xA414FEE2UL -#define INTC_IPRB 0xA414FEE4UL -#define INTC_IPRC 0xA4140016UL -#define INTC_IPRD 0xA4140018UL -#define INTC_IPRE 0xA414001AUL -#define INTC_IPRF 0xA4080000UL -#define INTC_IPRG 0xA4080002UL -#define INTC_IPRH 0xA4080004UL -#define INTC_IPRI 0xA4080006UL -#define INTC_IPRJ 0xA4080008UL - -#define INTC_IMR0 0xA4080040UL -#define INTC_IMR1 0xA4080042UL -#define INTC_IMR2 0xA4080044UL -#define INTC_IMR3 0xA4080046UL -#define INTC_IMR4 0xA4080048UL -#define INTC_IMR5 0xA408004AUL -#define INTC_IMR6 0xA408004CUL -#define INTC_IMR7 0xA408004EUL -#define INTC_IMR8 0xA4080050UL -#define INTC_IMR9 0xA4080052UL -#define INTC_IMR10 0xA4080054UL - -#define INTC_IMCR0 0xA4080060UL -#define INTC_IMCR1 0xA4080062UL -#define INTC_IMCR2 0xA4080064UL -#define INTC_IMCR3 0xA4080066UL -#define INTC_IMCR4 0xA4080068UL -#define INTC_IMCR5 0xA408006AUL -#define INTC_IMCR6 0xA408006CUL -#define INTC_IMCR7 0xA408006EUL -#define INTC_IMCR8 0xA4080070UL -#define INTC_IMCR9 0xA4080072UL -#define INTC_IMCR10 0xA4080074UL - -#define INTC_ICR0 0xA414FEE0UL -#define INTC_ICR1 0xA4140010UL - -#define INTC_IRR0 0xA4140004UL - -#define PORT_PACR 0xA4050100UL -#define PORT_PBCR 0xA4050102UL -#define PORT_PCCR 0xA4050104UL -#define PORT_PDCR 0xA4050106UL -#define PORT_PECR 0xA4050108UL -#define PORT_PFCR 0xA405010AUL -#define PORT_PGCR 0xA405010CUL -#define PORT_PHCR 0xA405010EUL -#define PORT_PJCR 0xA4050110UL -#define PORT_PKCR 0xA4050112UL -#define PORT_PLCR 0xA4050114UL -#define PORT_SCPCR 0xA4050116UL -#define PORT_PMCR 0xA4050118UL -#define PORT_PNCR 0xA405011AUL -#define PORT_PQCR 0xA405011CUL - -#define PORT_PSELA 0xA4050140UL -#define PORT_PSELB 0xA4050142UL -#define PORT_PSELC 0xA4050144UL - -#define PORT_HIZCRA 0xA4050146UL -#define PORT_HIZCRB 0xA4050148UL -#define PORT_DRVCR 0xA4050150UL - -#define PORT_PADR 0xA4050120UL -#define PORT_PBDR 0xA4050122UL -#define PORT_PCDR 0xA4050124UL -#define PORT_PDDR 0xA4050126UL -#define PORT_PEDR 0xA4050128UL -#define PORT_PFDR 0xA405012AUL -#define PORT_PGDR 0xA405012CUL -#define PORT_PHDR 0xA405012EUL -#define PORT_PJDR 0xA4050130UL -#define PORT_PKDR 0xA4050132UL -#define PORT_PLDR 0xA4050134UL -#define PORT_SCPDR 0xA4050136UL -#define PORT_PMDR 0xA4050138UL -#define PORT_PNDR 0xA405013AUL -#define PORT_PQDR 0xA405013CUL - -#define IRQ0_IRQ 32 -#define IRQ1_IRQ 33 -#define IRQ2_IRQ 34 -#define IRQ3_IRQ 35 -#define IRQ4_IRQ 36 -#define IRQ5_IRQ 37 - -#define IRQ0_IPR_ADDR INTC_IPRC -#define IRQ1_IPR_ADDR INTC_IPRC -#define IRQ2_IPR_ADDR INTC_IPRC -#define IRQ3_IPR_ADDR INTC_IPRC -#define IRQ4_IPR_ADDR INTC_IPRD -#define IRQ5_IPR_ADDR INTC_IPRD - -#define IRQ0_IPR_POS 0 -#define IRQ1_IPR_POS 1 -#define IRQ2_IPR_POS 2 -#define IRQ3_IPR_POS 3 -#define IRQ4_IPR_POS 0 -#define IRQ5_IPR_POS 1 +unsigned int map_ipridx_to_addr(int idx); -#define IRQ0_PRIORITY 1 -#define IRQ1_PRIORITY 1 -#define IRQ2_PRIORITY 1 -#define IRQ3_PRIORITY 1 -#define IRQ4_PRIORITY 1 -#define IRQ5_PRIORITY 1 - -extern int ipr_irq_demux(int irq); -#define __irq_demux(irq) ipr_irq_demux(irq) - -#elif defined(CONFIG_CPU_SUBTYPE_SH7604) -#define INTC_IPRA 0xfffffee2UL -#define INTC_IPRB 0xfffffe60UL - -#define INTC_VCRA 0xfffffe62UL -#define INTC_VCRB 0xfffffe64UL -#define INTC_VCRC 0xfffffe66UL -#define INTC_VCRD 0xfffffe68UL - -#define INTC_VCRWDT 0xfffffee4UL -#define INTC_VCRDIV 0xffffff0cUL -#define INTC_VCRDMA0 0xffffffa0UL -#define INTC_VCRDMA1 0xffffffa8UL - -#define INTC_ICR 0xfffffee0UL -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7706) || \ - defined(CONFIG_CPU_SUBTYPE_SH7707) || \ - defined(CONFIG_CPU_SUBTYPE_SH7709) || \ - defined(CONFIG_CPU_SUBTYPE_SH7710) -#define INTC_IRR0 0xa4000004UL -#define INTC_IRR1 0xa4000006UL -#define INTC_IRR2 0xa4000008UL - -#define INTC_ICR0 0xfffffee0UL -#define INTC_ICR1 0xa4000010UL -#define INTC_ICR2 0xa4000012UL -#define INTC_INTER 0xa4000014UL - -#define INTC_IPRC 0xa4000016UL -#define INTC_IPRD 0xa4000018UL -#define INTC_IPRE 0xa400001aUL -#if defined(CONFIG_CPU_SUBTYPE_SH7707) -#define INTC_IPRF 0xa400001cUL -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) -#define INTC_IPRF 0xa4080000UL -#define INTC_IPRG 0xa4080002UL -#define INTC_IPRH 0xa4080004UL -#elif defined(CONFIG_CPU_SUBTYPE_SH7710) -/* Interrupt Controller Registers */ -#undef INTC_IPRA -#undef INTC_IPRB -#define INTC_IPRA 0xA414FEE2UL -#define INTC_IPRB 0xA414FEE4UL -#define INTC_IPRF 0xA4080000UL -#define INTC_IPRG 0xA4080002UL -#define INTC_IPRH 0xA4080004UL -#define INTC_IPRI 0xA4080006UL - -#undef INTC_ICR0 -#undef INTC_ICR1 -#define INTC_ICR0 0xA414FEE0UL -#define INTC_ICR1 0xA4140010UL - -#define INTC_IRR0 0xa4000004UL -#define INTC_IRR1 0xa4000006UL -#define INTC_IRR2 0xa4000008UL -#define INTC_IRR3 0xa400000AUL -#define INTC_IRR4 0xa400000CUL -#define INTC_IRR5 0xa4080020UL -#define INTC_IRR7 0xa4080024UL -#define INTC_IRR8 0xa4080026UL - -/* Interrupt numbers */ -#define TIMER2_IRQ 18 -#define TIMER2_IPR_ADDR INTC_IPRA -#define TIMER2_IPR_POS 1 -#define TIMER2_PRIORITY 2 - -/* WDT */ -#define WDT_IRQ 27 -#define WDT_IPR_ADDR INTC_IPRB -#define WDT_IPR_POS 3 -#define WDT_PRIORITY 2 - -#define SCIF0_ERI_IRQ 52 -#define SCIF0_RXI_IRQ 53 -#define SCIF0_BRI_IRQ 54 -#define SCIF0_TXI_IRQ 55 -#define SCIF0_IPR_ADDR INTC_IPRE -#define SCIF0_IPR_POS 2 -#define SCIF0_PRIORITY 3 - -#define DMTE4_IRQ 76 -#define DMTE5_IRQ 77 -#define DMA2_IPR_ADDR INTC_IPRF -#define DMA2_IPR_POS 2 -#define DMA2_PRIORITY 7 - -#define IPSEC_IRQ 79 -#define IPSEC_IPR_ADDR INTC_IPRF -#define IPSEC_IPR_POS 3 -#define IPSEC_PRIORITY 3 - -/* EDMAC */ -#define EDMAC0_IRQ 80 -#define EDMAC0_IPR_ADDR INTC_IPRG -#define EDMAC0_IPR_POS 3 -#define EDMAC0_PRIORITY 3 - -#define EDMAC1_IRQ 81 -#define EDMAC1_IPR_ADDR INTC_IPRG -#define EDMAC1_IPR_POS 2 -#define EDMAC1_PRIORITY 3 - -#define EDMAC2_IRQ 82 -#define EDMAC2_IPR_ADDR INTC_IPRG -#define EDMAC2_IPR_POS 1 -#define EDMAC2_PRIORITY 3 - -/* SIOF */ -#define SIOF0_ERI_IRQ 96 -#define SIOF0_TXI_IRQ 97 -#define SIOF0_RXI_IRQ 98 -#define SIOF0_CCI_IRQ 99 -#define SIOF0_IPR_ADDR INTC_IPRH -#define SIOF0_IPR_POS 0 -#define SIOF0_PRIORITY 7 - -#define SIOF1_ERI_IRQ 100 -#define SIOF1_TXI_IRQ 101 -#define SIOF1_RXI_IRQ 102 -#define SIOF1_CCI_IRQ 103 -#define SIOF1_IPR_ADDR INTC_IPRI -#define SIOF1_IPR_POS 1 -#define SIOF1_PRIORITY 7 -#endif /* CONFIG_CPU_SUBTYPE_SH7710 */ - -#if defined(CONFIG_CPU_SUBTYPE_SH7710) -#define PORT_PACR 0xa4050100UL -#define PORT_PBCR 0xa4050102UL -#define PORT_PCCR 0xa4050104UL -#define PORT_PETCR 0xa4050106UL -#define PORT_PADR 0xa4050120UL -#define PORT_PBDR 0xa4050122UL -#define PORT_PCDR 0xa4050124UL -#else -#define PORT_PACR 0xa4000100UL -#define PORT_PBCR 0xa4000102UL -#define PORT_PCCR 0xa4000104UL -#define PORT_PFCR 0xa400010aUL -#define PORT_PADR 0xa4000120UL -#define PORT_PBDR 0xa4000122UL -#define PORT_PCDR 0xa4000124UL -#define PORT_PFDR 0xa400012aUL -#endif - -#define IRQ0_IRQ 32 -#define IRQ1_IRQ 33 -#define IRQ2_IRQ 34 -#define IRQ3_IRQ 35 -#define IRQ4_IRQ 36 -#define IRQ5_IRQ 37 - -#define IRQ0_IPR_ADDR INTC_IPRC -#define IRQ1_IPR_ADDR INTC_IPRC -#define IRQ2_IPR_ADDR INTC_IPRC -#define IRQ3_IPR_ADDR INTC_IPRC -#define IRQ4_IPR_ADDR INTC_IPRD -#define IRQ5_IPR_ADDR INTC_IPRD - -#define IRQ0_IPR_POS 0 -#define IRQ1_IPR_POS 1 -#define IRQ2_IPR_POS 2 -#define IRQ3_IPR_POS 3 -#define IRQ4_IPR_POS 0 -#define IRQ5_IPR_POS 1 - -#define IRQ0_PRIORITY 1 -#define IRQ1_PRIORITY 1 -#define IRQ2_PRIORITY 1 -#define IRQ3_PRIORITY 1 -#define IRQ4_PRIORITY 1 -#define IRQ5_PRIORITY 1 - -#define PINT0_IRQ 40 -#define PINT8_IRQ 41 - -#define PINT0_IPR_ADDR INTC_IPRD -#define PINT8_IPR_ADDR INTC_IPRD - -#define PINT0_IPR_POS 3 -#define PINT8_IPR_POS 2 -#define PINT0_PRIORITY 2 -#define PINT8_PRIORITY 2 - -extern int ipr_irq_demux(int irq); -#define __irq_demux(irq) ipr_irq_demux(irq) -#endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */ - -#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || \ - defined(CONFIG_CPU_SUBTYPE_ST40STB1) || defined(CONFIG_CPU_SUBTYPE_SH4_202) -#define INTC_ICR 0xffd00000 -#define INTC_ICR_NMIL (1<<15) -#define INTC_ICR_MAI (1<<14) -#define INTC_ICR_NMIB (1<<9) -#define INTC_ICR_NMIE (1<<8) -#define INTC_ICR_IRLM (1<<7) -#endif - -#ifdef CONFIG_CPU_SUBTYPE_SH7780 -#include <asm/irq-sh7780.h> -#endif - -/* SH with INTC2-style interrupts */ -#ifdef CONFIG_CPU_HAS_INTC2_IRQ -#if defined(CONFIG_CPU_SUBTYPE_ST40STB1) -#define INTC2_BASE 0xfe080000 -#define INTC2_FIRST_IRQ 64 -#define INTC2_INTREQ_OFFSET 0x20 -#define INTC2_INTMSK_OFFSET 0x40 -#define INTC2_INTMSKCLR_OFFSET 0x60 -#define NR_INTC2_IRQS 25 -#elif defined(CONFIG_CPU_SUBTYPE_SH7760) -#define INTC2_BASE 0xfe080000 -#define INTC2_FIRST_IRQ 48 /* INTEVT 0x800 */ -#define INTC2_INTREQ_OFFSET 0x20 -#define INTC2_INTMSK_OFFSET 0x40 -#define INTC2_INTMSKCLR_OFFSET 0x60 -#define NR_INTC2_IRQS 64 -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) -#define INTC2_BASE 0xffd40000 -#define INTC2_FIRST_IRQ 21 -#define INTC2_INTMSK_OFFSET (0x38) -#define INTC2_INTMSKCLR_OFFSET (0x3c) -#define NR_INTC2_IRQS 60 -#endif +/* + * Enable individual interrupt mode for external IPR IRQs. + */ +void ipr_irq_enable_irlm(void); -#define INTC2_INTPRI_OFFSET 0x00 +/* + * Function for "on chip support modules". + */ +void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs); +void make_imask_irq(unsigned int irq); +void init_IRQ_ipr(void); struct intc2_data { unsigned short irq; @@ -693,20 +149,14 @@ struct intc2_data { void make_intc2_irq(struct intc2_data *, unsigned int nr_irqs); void init_IRQ_intc2(void); -#endif - -extern int shmse_irq_demux(int irq); static inline int generic_irq_demux(int irq) { return irq; } -#ifndef __irq_demux -#define __irq_demux(irq) (irq) -#endif #define irq_canonicalize(irq) (irq) -#define irq_demux(irq) __irq_demux(sh_mv.mv_irq_demux(irq)) +#define irq_demux(irq) sh_mv.mv_irq_demux(irq) #ifdef CONFIG_4KSTACKS extern void irq_ctx_init(int cpu); @@ -717,12 +167,4 @@ extern void irq_ctx_exit(int cpu); # define irq_ctx_exit(cpu) do { } while (0) #endif -#if defined(CONFIG_CPU_SUBTYPE_SH73180) -#include <asm/irq-sh73180.h> -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7343) -#include <asm/irq-sh7343.h> -#endif - #endif /* __ASM_SH_IRQ_H */ diff --git a/include/asm-sh/irqflags.h b/include/asm-sh/irqflags.h new file mode 100644 index 00000000000..9dedc1b693e --- /dev/null +++ b/include/asm-sh/irqflags.h @@ -0,0 +1,123 @@ +#ifndef __ASM_SH_IRQFLAGS_H +#define __ASM_SH_IRQFLAGS_H + +static inline void raw_local_irq_enable(void) +{ + unsigned long __dummy0, __dummy1; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "and %1, %0\n\t" +#ifdef CONFIG_CPU_HAS_SR_RB + "stc r6_bank, %1\n\t" + "or %1, %0\n\t" +#endif + "ldc %0, sr\n\t" + : "=&r" (__dummy0), "=r" (__dummy1) + : "1" (~0x000000f0) + : "memory" + ); +} + +static inline void raw_local_irq_disable(void) +{ + unsigned long flags; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "or #0xf0, %0\n\t" + "ldc %0, sr\n\t" + : "=&z" (flags) + : /* no inputs */ + : "memory" + ); +} + +static inline void set_bl_bit(void) +{ + unsigned long __dummy0, __dummy1; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "or %2, %0\n\t" + "and %3, %0\n\t" + "ldc %0, sr\n\t" + : "=&r" (__dummy0), "=r" (__dummy1) + : "r" (0x10000000), "r" (0xffffff0f) + : "memory" + ); +} + +static inline void clear_bl_bit(void) +{ + unsigned long __dummy0, __dummy1; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "and %2, %0\n\t" + "ldc %0, sr\n\t" + : "=&r" (__dummy0), "=r" (__dummy1) + : "1" (~0x10000000) + : "memory" + ); +} + +static inline unsigned long __raw_local_save_flags(void) +{ + unsigned long flags; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "and #0xf0, %0\n\t" + : "=&z" (flags) + : /* no inputs */ + : "memory" + ); + + return flags; +} + +#define raw_local_save_flags(flags) \ + do { (flags) = __raw_local_save_flags(); } while (0) + +static inline int raw_irqs_disabled_flags(unsigned long flags) +{ + return (flags != 0); +} + +static inline int raw_irqs_disabled(void) +{ + unsigned long flags = __raw_local_save_flags(); + + return raw_irqs_disabled_flags(flags); +} + +static inline unsigned long __raw_local_irq_save(void) +{ + unsigned long flags, __dummy; + + __asm__ __volatile__ ( + "stc sr, %1\n\t" + "mov %1, %0\n\t" + "or #0xf0, %0\n\t" + "ldc %0, sr\n\t" + "mov %1, %0\n\t" + "and #0xf0, %0\n\t" + : "=&z" (flags), "=&r" (__dummy) + : /* no inputs */ + : "memory" + ); + + return flags; +} + +#define raw_local_irq_save(flags) \ + do { (flags) = __raw_local_irq_save(); } while (0) + +static inline void raw_local_irq_restore(unsigned long flags) +{ + if ((flags & 0xf0) != 0xf0) + raw_local_irq_enable(); +} + +#endif /* __ASM_SH_IRQFLAGS_H */ diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h index c7088efe579..46f04e23bd4 100644 --- a/include/asm-sh/mmu_context.h +++ b/include/asm-sh/mmu_context.h @@ -10,7 +10,6 @@ #include <asm/cpu/mmu_context.h> #include <asm/tlbflush.h> -#include <asm/pgalloc.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -42,10 +41,8 @@ extern unsigned long mmu_context_cache; /* * Get MMU context if needed. */ -static __inline__ void -get_mmu_context(struct mm_struct *mm) +static inline void get_mmu_context(struct mm_struct *mm) { - extern void flush_tlb_all(void); unsigned long mc = mmu_context_cache; /* Check if we have old version of context. */ @@ -61,6 +58,7 @@ get_mmu_context(struct mm_struct *mm) * Flush all TLB and start new cycle. */ flush_tlb_all(); + /* * Fix version; Note that we avoid version #0 * to distingush NO_CONTEXT. @@ -75,11 +73,10 @@ get_mmu_context(struct mm_struct *mm) * Initialize the context related info for a new mm_struct * instance. */ -static __inline__ int init_new_context(struct task_struct *tsk, +static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { mm->context.id = NO_CONTEXT; - return 0; } @@ -87,12 +84,12 @@ static __inline__ int init_new_context(struct task_struct *tsk, * Destroy context related info for an mm_struct that is about * to be put to rest. */ -static __inline__ void destroy_context(struct mm_struct *mm) +static inline void destroy_context(struct mm_struct *mm) { /* Do nothing */ } -static __inline__ void set_asid(unsigned long asid) +static inline void set_asid(unsigned long asid) { unsigned long __dummy; @@ -105,7 +102,7 @@ static __inline__ void set_asid(unsigned long asid) "r" (0xffffff00)); } -static __inline__ unsigned long get_asid(void) +static inline unsigned long get_asid(void) { unsigned long asid; @@ -120,24 +117,29 @@ static __inline__ unsigned long get_asid(void) * After we have set current->mm to a new value, this activates * the context for the new mm so we see the new mappings. */ -static __inline__ void activate_context(struct mm_struct *mm) +static inline void activate_context(struct mm_struct *mm) { get_mmu_context(mm); set_asid(mm->context.id & MMU_CONTEXT_ASID_MASK); } -/* MMU_TTB can be used for optimizing the fault handling. - (Currently not used) */ -static __inline__ void switch_mm(struct mm_struct *prev, - struct mm_struct *next, - struct task_struct *tsk) +/* MMU_TTB is used for optimizing the fault handling. */ +static inline void set_TTB(pgd_t *pgd) { - if (likely(prev != next)) { - unsigned long __pgdir = (unsigned long)next->pgd; + ctrl_outl((unsigned long)pgd, MMU_TTB); +} - __asm__ __volatile__("mov.l %0, %1" - : /* no output */ - : "r" (__pgdir), "m" (__m(MMU_TTB))); +static inline pgd_t *get_TTB(void) +{ + return (pgd_t *)ctrl_inl(MMU_TTB); +} + +static inline void switch_mm(struct mm_struct *prev, + struct mm_struct *next, + struct task_struct *tsk) +{ + if (likely(prev != next)) { + set_TTB(next->pgd); activate_context(next); } } @@ -147,7 +149,7 @@ static __inline__ void switch_mm(struct mm_struct *prev, #define activate_mm(prev, next) \ switch_mm((prev),(next),NULL) -static __inline__ void +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index ca8b26d9047..380fd62dd05 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -13,9 +13,16 @@ [ P4 control ] 0xE0000000 */ - /* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT 12 +#if defined(CONFIG_PAGE_SIZE_4KB) +# define PAGE_SHIFT 12 +#elif defined(CONFIG_PAGE_SIZE_8KB) +# define PAGE_SHIFT 13 +#elif defined(CONFIG_PAGE_SIZE_64KB) +# define PAGE_SHIFT 16 +#else +# error "Bogus kernel page size?" +#endif #ifdef __ASSEMBLY__ #define PAGE_SIZE (1 << PAGE_SHIFT) @@ -28,8 +35,14 @@ #if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) #define HPAGE_SHIFT 16 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K) +#define HPAGE_SHIFT 18 #elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) #define HPAGE_SHIFT 20 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4MB) +#define HPAGE_SHIFT 22 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB) +#define HPAGE_SHIFT 26 #endif #ifdef CONFIG_HUGETLB_PAGE @@ -69,15 +82,25 @@ extern void __copy_user_page(void *to, void *from, void *orig_to); /* * These are used to make use of C type-checking.. */ -typedef struct { unsigned long pte; } pte_t; -typedef struct { unsigned long pgd; } pgd_t; +#ifdef CONFIG_X2TLB +typedef struct { unsigned long pte_low, pte_high; } pte_t; +typedef struct { unsigned long long pgprot; } pgprot_t; +#define pte_val(x) \ + ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) +#define __pte(x) \ + ({ pte_t __pte = {(x), ((unsigned long long)(x)) >> 32}; __pte; }) +#else +typedef struct { unsigned long pte_low; } pte_t; typedef struct { unsigned long pgprot; } pgprot_t; +#define pte_val(x) ((x).pte_low) +#define __pte(x) ((pte_t) { (x) } ) +#endif + +typedef struct { unsigned long pgd; } pgd_t; -#define pte_val(x) ((x).pte) #define pgd_val(x) ((x).pgd) #define pgprot_val(x) ((x).pgprot) -#define __pte(x) ((pte_t) { (x) } ) #define __pgd(x) ((pgd_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } ) diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h index e841465ab4d..888e4529e6f 100644 --- a/include/asm-sh/pgalloc.h +++ b/include/asm-sh/pgalloc.h @@ -1,13 +1,16 @@ #ifndef __ASM_SH_PGALLOC_H #define __ASM_SH_PGALLOC_H -#define pmd_populate_kernel(mm, pmd, pte) \ - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) +static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, + pte_t *pte) +{ + set_pmd(pmd, __pmd((unsigned long)pte)); +} static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte) { - set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte))); + set_pmd(pmd, __pmd((unsigned long)page_address(pte))); } /* @@ -15,7 +18,16 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, */ static inline pgd_t *pgd_alloc(struct mm_struct *mm) { - return (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO); + pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT); + + if (pgd) { + memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + } + + return pgd; } static inline void pgd_free(pgd_t *pgd) diff --git a/include/asm-sh/pgtable-2level.h b/include/asm-sh/pgtable-2level.h deleted file mode 100644 index b525db6f61c..00000000000 --- a/include/asm-sh/pgtable-2level.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef __ASM_SH_PGTABLE_2LEVEL_H -#define __ASM_SH_PGTABLE_2LEVEL_H - -/* - * traditional two-level paging structure: - */ - -#define PGDIR_SHIFT 22 -#define PTRS_PER_PGD 1024 - -/* - * this is two-level, so we don't really have any - * PMD directory physically. - */ -#define PMD_SHIFT 22 -#define PTRS_PER_PMD 1 - -#define PTRS_PER_PTE 1024 - -#ifndef __ASSEMBLY__ -#define pte_ERROR(e) \ - printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) -#define pmd_ERROR(e) \ - printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e)) -#define pgd_ERROR(e) \ - printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) - -/* - * The "pgd_xxx()" functions here are trivial for a folded two-level - * setup: the pgd is never bad, and a pmd always exists (as it's folded - * into the pgd entry) - */ -static inline int pgd_none(pgd_t pgd) { return 0; } -static inline int pgd_bad(pgd_t pgd) { return 0; } -static inline int pgd_present(pgd_t pgd) { return 1; } -static inline void pgd_clear (pgd_t * pgdp) { } - -/* - * Certain architectures need to do special things when PTEs - * within a page table are directly modified. Thus, the following - * hook is made available. - */ -#define set_pte(pteptr, pteval) (*(pteptr) = pteval) -#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) - -/* - * (pmds are folded into pgds so this doesn't get actually called, - * but the define is needed for a generic inline function.) - */ -#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) -#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval) - -#define pgd_page_vaddr(pgd) \ -((unsigned long) __va(pgd_val(pgd) & PAGE_MASK)) - -#define pgd_page(pgd) \ - (phys_to_page(pgd_val(pgd))) - -static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) -{ - return (pmd_t *) dir; -} - -#define pte_pfn(x) ((unsigned long)(((x).pte >> PAGE_SHIFT))) -#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) -#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) - -#endif /* !__ASSEMBLY__ */ - -#endif /* __ASM_SH_PGTABLE_2LEVEL_H */ diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index 2c8682ad101..c84901dbd8e 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h @@ -15,15 +15,10 @@ #include <asm-generic/pgtable-nopmd.h> #include <asm/page.h> -#define PTRS_PER_PGD 1024 - #ifndef __ASSEMBLY__ #include <asm/addrspace.h> #include <asm/fixmap.h> -extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; -extern void paging_init(void); - /* * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. @@ -33,15 +28,28 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #endif /* !__ASSEMBLY__ */ -/* traditional two-level paging structure */ -#define PGDIR_SHIFT 22 -#define PTRS_PER_PMD 1 -#define PTRS_PER_PTE 1024 -#define PMD_SIZE (1UL << PMD_SHIFT) -#define PMD_MASK (~(PMD_SIZE-1)) -#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +/* + * traditional two-level paging structure + */ +/* PTE bits */ +#ifdef CONFIG_X2TLB +# define PTE_MAGNITUDE 3 /* 64-bit PTEs on extended mode SH-X2 TLB */ +#else +# define PTE_MAGNITUDE 2 /* 32-bit PTEs */ +#endif +#define PTE_SHIFT PAGE_SHIFT +#define PTE_BITS (PTE_SHIFT - PTE_MAGNITUDE) + +/* PGD bits */ +#define PGDIR_SHIFT (PTE_SHIFT + PTE_BITS) +#define PGDIR_BITS (32 - PGDIR_SHIFT) +#define PGDIR_SIZE (1 << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) +/* Entries per level */ +#define PTRS_PER_PTE (PAGE_SIZE / 4) +#define PTRS_PER_PGD (PAGE_SIZE / 4) + #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) #define FIRST_USER_ADDRESS 0 @@ -49,7 +57,7 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; /* * First 1MB map is used by fixed purpose. - * Currently only 4-enty (16kB) is used (see arch/sh/mm/cache.c) + * Currently only 4-entry (16kB) is used (see arch/sh/mm/cache.c) */ #define VMALLOC_START (P3SEG+0x00100000) #define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) @@ -57,7 +65,8 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; /* * Linux PTEL encoding. * - * Hardware and software bit definitions for the PTEL value: + * Hardware and software bit definitions for the PTEL value (see below for + * notes on SH-X2 MMUs and 64-bit PTEs): * * - Bits 0 and 7 are reserved on SH-3 (_PAGE_WT and _PAGE_SZ1 on SH-4). * @@ -76,20 +85,57 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; * * - Bits 31, 30, and 29 remain unused by everyone and can be used for future * software flags, although care must be taken to update _PAGE_CLEAR_FLAGS. + * + * XXX: Leave the _PAGE_FILE and _PAGE_WT overhaul for a rainy day. + * + * SH-X2 MMUs and extended PTEs + * + * SH-X2 supports an extended mode TLB with split data arrays due to the + * number of bits needed for PR and SZ (now EPR and ESZ) encodings. The PR and + * SZ bit placeholders still exist in data array 1, but are implemented as + * reserved bits, with the real logic existing in data array 2. + * + * The downside to this is that we can no longer fit everything in to a 32-bit + * PTE encoding, so a 64-bit pte_t is necessary for these parts. On the plus + * side, this gives us quite a few spare bits to play with for future usage. */ +/* Legacy and compat mode bits */ #define _PAGE_WT 0x001 /* WT-bit on SH-4, 0 on SH-3 */ #define _PAGE_HW_SHARED 0x002 /* SH-bit : shared among processes */ #define _PAGE_DIRTY 0x004 /* D-bit : page changed */ #define _PAGE_CACHABLE 0x008 /* C-bit : cachable */ -#define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */ -#define _PAGE_RW 0x020 /* PR0-bit : write access allowed */ -#define _PAGE_USER 0x040 /* PR1-bit : user space access allowed */ -#define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */ +#ifndef CONFIG_X2TLB +# define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */ +# define _PAGE_RW 0x020 /* PR0-bit : write access allowed */ +# define _PAGE_USER 0x040 /* PR1-bit : user space access allowed*/ +# define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */ +#endif #define _PAGE_PRESENT 0x100 /* V-bit : page is valid */ #define _PAGE_PROTNONE 0x200 /* software: if not present */ #define _PAGE_ACCESSED 0x400 /* software: page referenced */ #define _PAGE_FILE _PAGE_WT /* software: pagecache or swap? */ +/* Extended mode bits */ +#define _PAGE_EXT_ESZ0 0x0010 /* ESZ0-bit: Size of page */ +#define _PAGE_EXT_ESZ1 0x0020 /* ESZ1-bit: Size of page */ +#define _PAGE_EXT_ESZ2 0x0040 /* ESZ2-bit: Size of page */ +#define _PAGE_EXT_ESZ3 0x0080 /* ESZ3-bit: Size of page */ + +#define _PAGE_EXT_USER_EXEC 0x0100 /* EPR0-bit: User space executable */ +#define _PAGE_EXT_USER_WRITE 0x0200 /* EPR1-bit: User space writable */ +#define _PAGE_EXT_USER_READ 0x0400 /* EPR2-bit: User space readable */ + +#define _PAGE_EXT_KERN_EXEC 0x0800 /* EPR3-bit: Kernel space executable */ +#define _PAGE_EXT_KERN_WRITE 0x1000 /* EPR4-bit: Kernel space writable */ +#define _PAGE_EXT_KERN_READ 0x2000 /* EPR5-bit: Kernel space readable */ + +/* Wrapper for extended mode pgprot twiddling */ +#ifdef CONFIG_X2TLB +# define _PAGE_EXT(x) ((unsigned long long)(x) << 32) +#else +# define _PAGE_EXT(x) (0) +#endif + /* software: moves to PTEA.TC (Timing Control) */ #define _PAGE_PCC_AREA5 0x00000000 /* use BSC registers for area5 */ #define _PAGE_PCC_AREA6 0x80000000 /* use BSC registers for area6 */ @@ -114,37 +160,160 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define _PAGE_FLAGS_HARDWARE_MASK (0x1fffffff & ~(_PAGE_CLEAR_FLAGS)) -/* Hardware flags: SZ0=1 (4k-byte) */ -#define _PAGE_FLAGS_HARD _PAGE_SZ0 +/* Hardware flags, page size encoding */ +#if defined(CONFIG_X2TLB) +# if defined(CONFIG_PAGE_SIZE_4KB) +# define _PAGE_FLAGS_HARD _PAGE_EXT(_PAGE_EXT_ESZ0) +# elif defined(CONFIG_PAGE_SIZE_8KB) +# define _PAGE_FLAGS_HARD _PAGE_EXT(_PAGE_EXT_ESZ1) +# elif defined(CONFIG_PAGE_SIZE_64KB) +# define _PAGE_FLAGS_HARD _PAGE_EXT(_PAGE_EXT_ESZ2) +# endif +#else +# if defined(CONFIG_PAGE_SIZE_4KB) +# define _PAGE_FLAGS_HARD _PAGE_SZ0 +# elif defined(CONFIG_PAGE_SIZE_64KB) +# define _PAGE_FLAGS_HARD _PAGE_SZ1 +# endif +#endif -#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) -#define _PAGE_SZHUGE (_PAGE_SZ1) -#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) -#define _PAGE_SZHUGE (_PAGE_SZ0 | _PAGE_SZ1) +#if defined(CONFIG_X2TLB) +# if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) +# define _PAGE_SZHUGE (_PAGE_EXT_ESZ2) +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K) +# define _PAGE_SZHUGE (_PAGE_EXT_ESZ0 | _PAGE_EXT_ESZ2) +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) +# define _PAGE_SZHUGE (_PAGE_EXT_ESZ0 | _PAGE_EXT_ESZ1 | _PAGE_EXT_ESZ2) +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_4MB) +# define _PAGE_SZHUGE (_PAGE_EXT_ESZ3) +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB) +# define _PAGE_SZHUGE (_PAGE_EXT_ESZ2 | _PAGE_EXT_ESZ3) +# endif +#else +# if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) +# define _PAGE_SZHUGE (_PAGE_SZ1) +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) +# define _PAGE_SZHUGE (_PAGE_SZ0 | _PAGE_SZ1) +# endif +#endif + +/* + * Stub out _PAGE_SZHUGE if we don't have a good definition for it, + * to make pte_mkhuge() happy. + */ +#ifndef _PAGE_SZHUGE +# define _PAGE_SZHUGE (_PAGE_FLAGS_HARD) #endif -#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) -#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) -#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY) +#define _PAGE_CHG_MASK \ + (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY) #ifndef __ASSEMBLY__ -#ifdef CONFIG_MMU -#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_FLAGS_HARD) -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_FLAGS_HARD) -#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_FLAGS_HARD) -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_FLAGS_HARD) -#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) +#if defined(CONFIG_X2TLB) /* SH-X2 TLB */ +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD) + +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ + _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_USER_READ | \ + _PAGE_EXT_USER_WRITE)) + +#define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ + _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_USER_EXEC | \ + _PAGE_EXT_USER_READ)) + +#define PAGE_COPY PAGE_EXECREAD + +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ + _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_USER_READ)) + +#define PAGE_WRITEONLY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ + _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_USER_WRITE)) + +#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ + _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_USER_WRITE | \ + _PAGE_EXT_USER_READ | \ + _PAGE_EXT_USER_EXEC)) + +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \ + _PAGE_DIRTY | _PAGE_ACCESSED | \ + _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_KERN_EXEC)) + #define PAGE_KERNEL_NOCACHE \ - __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) -#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) + __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | \ + _PAGE_ACCESSED | _PAGE_HW_SHARED | \ + _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_KERN_EXEC)) + +#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \ + _PAGE_DIRTY | _PAGE_ACCESSED | \ + _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_EXEC)) + +#define PAGE_KERNEL_PCC(slot, type) \ + __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_KERN_EXEC) \ + (slot ? _PAGE_PCC_AREA5 : _PAGE_PCC_AREA6) | \ + (type)) + +#elif defined(CONFIG_MMU) /* SH-X TLB */ +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD) + +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \ + _PAGE_CACHABLE | _PAGE_ACCESSED | \ + _PAGE_FLAGS_HARD) + +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD) + +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD) + +#define PAGE_EXECREAD PAGE_READONLY +#define PAGE_RWX PAGE_SHARED +#define PAGE_WRITEONLY PAGE_SHARED + +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | \ + _PAGE_DIRTY | _PAGE_ACCESSED | \ + _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) + +#define PAGE_KERNEL_NOCACHE \ + __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \ + _PAGE_ACCESSED | _PAGE_HW_SHARED | \ + _PAGE_FLAGS_HARD) + +#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \ + _PAGE_DIRTY | _PAGE_ACCESSED | \ + _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) + #define PAGE_KERNEL_PCC(slot, type) \ - __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_FLAGS_HARD | (slot ? _PAGE_PCC_AREA5 : _PAGE_PCC_AREA6) | (type)) + __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD | \ + (slot ? _PAGE_PCC_AREA5 : _PAGE_PCC_AREA6) | \ + (type)) #else /* no mmu */ #define PAGE_NONE __pgprot(0) #define PAGE_SHARED __pgprot(0) #define PAGE_COPY __pgprot(0) +#define PAGE_EXECREAD __pgprot(0) +#define PAGE_RWX __pgprot(0) #define PAGE_READONLY __pgprot(0) +#define PAGE_WRITEONLY __pgprot(0) #define PAGE_KERNEL __pgprot(0) #define PAGE_KERNEL_NOCACHE __pgprot(0) #define PAGE_KERNEL_RO __pgprot(0) @@ -154,27 +323,32 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #endif /* __ASSEMBLY__ */ /* - * As i386 and MIPS, SuperH can't do page protection for execute, and - * considers that the same as a read. Also, write permissions imply - * read permissions. This is the closest we can get.. + * SH-X and lower (legacy) SuperH parts (SH-3, SH-4, some SH-4A) can't do page + * protection for execute, and considers it the same as a read. Also, write + * permission implies read permission. This is the closest we can get.. + * + * SH-X2 (SH7785) and later parts take this to the opposite end of the extreme, + * not only supporting separate execute, read, and write bits, but having + * completely separate permission bits for user and kernel space. */ + /*xwr*/ #define __P000 PAGE_NONE #define __P001 PAGE_READONLY #define __P010 PAGE_COPY #define __P011 PAGE_COPY -#define __P100 PAGE_READONLY -#define __P101 PAGE_READONLY +#define __P100 PAGE_EXECREAD +#define __P101 PAGE_EXECREAD #define __P110 PAGE_COPY #define __P111 PAGE_COPY #define __S000 PAGE_NONE #define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED +#define __S010 PAGE_WRITEONLY #define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY -#define __S101 PAGE_READONLY -#define __S110 PAGE_SHARED -#define __S111 PAGE_SHARED +#define __S100 PAGE_EXECREAD +#define __S101 PAGE_EXECREAD +#define __S110 PAGE_RWX +#define __S111 PAGE_RWX #ifndef __ASSEMBLY__ @@ -183,7 +357,17 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; * within a page table are directly modified. Thus, the following * hook is made available. */ +#ifdef CONFIG_X2TLB +static inline void set_pte(pte_t *ptep, pte_t pte) +{ + ptep->pte_high = pte.pte_high; + smp_wmb(); + ptep->pte_low = pte.pte_low; +} +#else #define set_pte(pteptr, pteval) (*(pteptr) = pteval) +#endif + #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) /* @@ -192,18 +376,18 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; */ #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) -#define pte_pfn(x) ((unsigned long)(((x).pte >> PAGE_SHIFT))) +#define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT))) #define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) #define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) #define pte_none(x) (!pte_val(x)) #define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) -#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) +#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) #define pmd_none(x) (!pmd_val(x)) -#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) +#define pmd_present(x) (pmd_val(x)) #define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) -#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) +#define pmd_bad(x) (pmd_val(x) & ~PAGE_MASK) #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) #define pte_page(x) phys_to_page(pte_val(x)&PTE_PHYS_MASK) @@ -212,28 +396,52 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; * The following only work if pte_present() is true. * Undefined behaviour if not.. */ -static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; } -static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; } -static inline int pte_dirty(pte_t pte){ return pte_val(pte) & _PAGE_DIRTY; } -static inline int pte_young(pte_t pte){ return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } -static inline int pte_write(pte_t pte){ return pte_val(pte) & _PAGE_RW; } -static inline int pte_not_present(pte_t pte){ return !(pte_val(pte) & _PAGE_PRESENT); } - -static inline pte_t pte_rdprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; } -static inline pte_t pte_exprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; } -static inline pte_t pte_mkclean(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; } -static inline pte_t pte_mkold(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; } -static inline pte_t pte_wrprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_RW)); return pte; } -static inline pte_t pte_mkread(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; } -static inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; } -static inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; } -static inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; } -static inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; } -#ifdef CONFIG_HUGETLB_PAGE -static inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; } +#define pte_not_present(pte) (!(pte_val(pte) & _PAGE_PRESENT)) +#define pte_dirty(pte) (pte_val(pte) & _PAGE_DIRTY) +#define pte_young(pte) (pte_val(pte) & _PAGE_ACCESSED) +#define pte_file(pte) (pte_val(pte) & _PAGE_FILE) + +#ifdef CONFIG_X2TLB +#define pte_read(pte) ((pte).pte_high & _PAGE_EXT_USER_READ) +#define pte_exec(pte) ((pte).pte_high & _PAGE_EXT_USER_EXEC) +#define pte_write(pte) ((pte).pte_high & _PAGE_EXT_USER_WRITE) +#else +#define pte_read(pte) (pte_val(pte) & _PAGE_USER) +#define pte_exec(pte) (pte_val(pte) & _PAGE_USER) +#define pte_write(pte) (pte_val(pte) & _PAGE_RW) #endif +#define PTE_BIT_FUNC(h,fn,op) \ +static inline pte_t pte_##fn(pte_t pte) { pte.pte_##h op; return pte; } + +#ifdef CONFIG_X2TLB +/* + * We cheat a bit in the SH-X2 TLB case. As the permission bits are + * individually toggled (and user permissions are entirely decoupled from + * kernel permissions), we attempt to couple them a bit more sanely here. + */ +PTE_BIT_FUNC(high, rdprotect, &= ~_PAGE_EXT_USER_READ); +PTE_BIT_FUNC(high, mkread, |= _PAGE_EXT_USER_READ | _PAGE_EXT_KERN_READ); +PTE_BIT_FUNC(high, wrprotect, &= ~_PAGE_EXT_USER_WRITE); +PTE_BIT_FUNC(high, mkwrite, |= _PAGE_EXT_USER_WRITE | _PAGE_EXT_KERN_WRITE); +PTE_BIT_FUNC(high, exprotect, &= ~_PAGE_EXT_USER_EXEC); +PTE_BIT_FUNC(high, mkexec, |= _PAGE_EXT_USER_EXEC | _PAGE_EXT_KERN_EXEC); +PTE_BIT_FUNC(high, mkhuge, |= _PAGE_SZHUGE); +#else +PTE_BIT_FUNC(low, rdprotect, &= ~_PAGE_USER); +PTE_BIT_FUNC(low, mkread, |= _PAGE_USER); +PTE_BIT_FUNC(low, wrprotect, &= ~_PAGE_RW); +PTE_BIT_FUNC(low, mkwrite, |= _PAGE_RW); +PTE_BIT_FUNC(low, exprotect, &= ~_PAGE_USER); +PTE_BIT_FUNC(low, mkexec, |= _PAGE_USER); +PTE_BIT_FUNC(low, mkhuge, |= _PAGE_SZHUGE); +#endif + +PTE_BIT_FUNC(low, mkclean, &= ~_PAGE_DIRTY); +PTE_BIT_FUNC(low, mkdirty, |= _PAGE_DIRTY); +PTE_BIT_FUNC(low, mkold, &= ~_PAGE_ACCESSED); +PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED); + /* * Macro and implementation to make a page protection as uncachable. */ @@ -258,13 +466,14 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot) #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) -{ set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))); return pte; } - -#define pmd_page_vaddr(pmd) \ -((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) +{ + set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | + pgprot_val(newprot))); + return pte; +} -#define pmd_page(pmd) \ - (phys_to_page(pmd_val(pmd))) +#define pmd_page_vaddr(pmd) pmd_val(pmd) +#define pmd_page(pmd) (virt_to_page(pmd_val(pmd))) /* to find an entry in a page-table-directory. */ #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) @@ -283,8 +492,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #define pte_unmap(pte) do { } while (0) #define pte_unmap_nested(pte) do { } while (0) +#ifdef CONFIG_X2TLB +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %p(%08lx%08lx).\n", __FILE__, __LINE__, \ + &(e), (e).pte_high, (e).pte_low) +#else #define pte_ERROR(e) \ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) +#endif + #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) @@ -337,6 +553,9 @@ extern unsigned int kobjsize(const void *objp); extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); #endif +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +extern void paging_init(void); + #include <asm-generic/pgtable.h> #endif /* !__ASSEMBLY__ */ diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h index 45bb74e35d3..6f1dd7ca1b1 100644 --- a/include/asm-sh/processor.h +++ b/include/asm-sh/processor.h @@ -36,7 +36,10 @@ */ enum cpu_type { /* SH-2 types */ - CPU_SH7604, + CPU_SH7604, CPU_SH7619, + + /* SH-2A types */ + CPU_SH7206, /* SH-3 types */ CPU_SH7705, CPU_SH7706, CPU_SH7707, @@ -47,7 +50,10 @@ enum cpu_type { /* SH-4 types */ CPU_SH7750, CPU_SH7750S, CPU_SH7750R, CPU_SH7751, CPU_SH7751R, CPU_SH7760, CPU_ST40RA, CPU_ST40GX1, CPU_SH4_202, CPU_SH4_501, + + /* SH-4A types */ CPU_SH73180, CPU_SH7343, CPU_SH7770, CPU_SH7780, CPU_SH7781, + CPU_SH7785, /* Unknown subtype */ CPU_SH_NONE @@ -130,12 +136,11 @@ union sh_fpu_union { }; struct thread_struct { + /* Saved registers when thread is descheduled */ unsigned long sp; unsigned long pc; - unsigned long trap_no, error_code; - unsigned long address; - /* Hardware debugging registers may come here */ + /* Hardware debugging registers */ unsigned long ubc_pc; /* floating point info */ @@ -150,12 +155,7 @@ typedef struct { extern int ubc_usercnt; #define INIT_THREAD { \ - sizeof(init_stack) + (long) &init_stack, /* sp */ \ - 0, /* pc */ \ - 0, 0, \ - 0, \ - 0, \ - {{{0,}},} /* fpu state */ \ + .sp = sizeof(init_stack) + (long) &init_stack, \ } /* @@ -259,8 +259,8 @@ void show_trace(struct task_struct *tsk, unsigned long *sp, struct pt_regs *regs); extern unsigned long get_wchan(struct task_struct *p); -#define KSTK_EIP(tsk) ((tsk)->thread.pc) -#define KSTK_ESP(tsk) ((tsk)->thread.sp) +#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc) +#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[15]) #define cpu_sleep() __asm__ __volatile__ ("sleep" : : : "memory") #define cpu_relax() barrier() diff --git a/include/asm-sh/push-switch.h b/include/asm-sh/push-switch.h new file mode 100644 index 00000000000..dfc6bad567f --- /dev/null +++ b/include/asm-sh/push-switch.h @@ -0,0 +1,28 @@ +#ifndef __ASM_SH_PUSH_SWITCH_H +#define __ASM_SH_PUSH_SWITCH_H + +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> + +struct push_switch { + /* switch state */ + unsigned int state:1; + /* debounce timer */ + struct timer_list debounce; + /* workqueue */ + struct work_struct work; +}; + +struct push_switch_platform_info { + /* IRQ handler */ + irqreturn_t (*irq_handler)(int irq, void *data); + /* Special IRQ flags */ + unsigned int irq_flags; + /* Bit location of switch */ + unsigned int bit; + /* Symbolic switch name */ + const char *name; +}; + +#endif /* __ASM_SH_PUSH_SWITCH_H */ diff --git a/include/asm-sh/rwsem.h b/include/asm-sh/rwsem.h index 9d2aea5e848..4931ba817d7 100644 --- a/include/asm-sh/rwsem.h +++ b/include/asm-sh/rwsem.h @@ -25,11 +25,21 @@ struct rw_semaphore { #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) spinlock_t wait_lock; struct list_head wait_list; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif }; +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname } +#else +# define __RWSEM_DEP_MAP_INIT(lockname) +#endif + #define __RWSEM_INITIALIZER(name) \ { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ - LIST_HEAD_INIT((name).wait_list) } + LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) } #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) @@ -39,6 +49,16 @@ extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); +extern void __init_rwsem(struct rw_semaphore *sem, const char *name, + struct lock_class_key *key); + +#define init_rwsem(sem) \ +do { \ + static struct lock_class_key __key; \ + \ + __init_rwsem((sem), #sem, &__key); \ +} while (0) + static inline void init_rwsem(struct rw_semaphore *sem) { sem->count = RWSEM_UNLOCKED_VALUE; @@ -141,6 +161,11 @@ static inline void __downgrade_write(struct rw_semaphore *sem) rwsem_downgrade_wake(sem); } +static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) +{ + __down_write(sem); +} + /* * implement exchange and add functionality */ diff --git a/include/asm-sh/se7206.h b/include/asm-sh/se7206.h new file mode 100644 index 00000000000..698eb80389a --- /dev/null +++ b/include/asm-sh/se7206.h @@ -0,0 +1,13 @@ +#ifndef __ASM_SH_SE7206_H +#define __ASM_SH_SE7206_H + +#define PA_SMSC 0x30000000 +#define PA_MRSHPC 0x34000000 +#define PA_LED 0x31400000 + +void init_se7206_IRQ(void); + +#define __IO_PREFIX se7206 +#include <asm/io_generic.h> + +#endif /* __ASM_SH_SE7206_H */ diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h index 3340126f4e0..b1e42e7f998 100644 --- a/include/asm-sh/system.h +++ b/include/asm-sh/system.h @@ -6,6 +6,7 @@ * Copyright (C) 2002 Paul Mundt */ +#include <linux/irqflags.h> #include <asm/types.h> /* @@ -131,103 +132,6 @@ static inline unsigned long tas(volatile int *m) #define set_mb(var, value) do { xchg(&var, value); } while (0) -/* Interrupt Control */ -#ifdef CONFIG_CPU_HAS_SR_RB -static inline void local_irq_enable(void) -{ - unsigned long __dummy0, __dummy1; - - __asm__ __volatile__("stc sr, %0\n\t" - "and %1, %0\n\t" - "stc r6_bank, %1\n\t" - "or %1, %0\n\t" - "ldc %0, sr" - : "=&r" (__dummy0), "=r" (__dummy1) - : "1" (~0x000000f0) - : "memory"); -} -#else -static inline void local_irq_enable(void) -{ - unsigned long __dummy0, __dummy1; - - __asm__ __volatile__ ( - "stc sr, %0\n\t" - "and %1, %0\n\t" - "ldc %0, sr\n\t" - : "=&r" (__dummy0), "=r" (__dummy1) - : "1" (~0x000000f0) - : "memory"); -} -#endif - -static inline void local_irq_disable(void) -{ - unsigned long __dummy; - __asm__ __volatile__("stc sr, %0\n\t" - "or #0xf0, %0\n\t" - "ldc %0, sr" - : "=&z" (__dummy) - : /* no inputs */ - : "memory"); -} - -static inline void set_bl_bit(void) -{ - unsigned long __dummy0, __dummy1; - - __asm__ __volatile__ ("stc sr, %0\n\t" - "or %2, %0\n\t" - "and %3, %0\n\t" - "ldc %0, sr" - : "=&r" (__dummy0), "=r" (__dummy1) - : "r" (0x10000000), "r" (0xffffff0f) - : "memory"); -} - -static inline void clear_bl_bit(void) -{ - unsigned long __dummy0, __dummy1; - - __asm__ __volatile__ ("stc sr, %0\n\t" - "and %2, %0\n\t" - "ldc %0, sr" - : "=&r" (__dummy0), "=r" (__dummy1) - : "1" (~0x10000000) - : "memory"); -} - -#define local_save_flags(x) \ - __asm__("stc sr, %0; and #0xf0, %0" : "=&z" (x) :/**/: "memory" ) - -#define irqs_disabled() \ -({ \ - unsigned long flags; \ - local_save_flags(flags); \ - (flags != 0); \ -}) - -static inline unsigned long local_irq_save(void) -{ - unsigned long flags, __dummy; - - __asm__ __volatile__("stc sr, %1\n\t" - "mov %1, %0\n\t" - "or #0xf0, %0\n\t" - "ldc %0, sr\n\t" - "mov %1, %0\n\t" - "and #0xf0, %0" - : "=&z" (flags), "=&r" (__dummy) - :/**/ - : "memory" ); - return flags; -} - -#define local_irq_restore(x) do { \ - if ((x & 0x000000f0) != 0x000000f0) \ - local_irq_enable(); \ -} while (0) - /* * Jump to P2 area. * When handling TLB or caches, we need to do it from P2 area. @@ -264,9 +168,6 @@ do { \ : "=&r" (__dummy)); \ } while (0) -/* For spinlocks etc */ -#define local_irq_save(x) x = local_irq_save() - static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val) { unsigned long flags, retval; diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h index 3ebc3f9039e..0c01dc55081 100644 --- a/include/asm-sh/thread_info.h +++ b/include/asm-sh/thread_info.h @@ -90,13 +90,7 @@ static inline struct thread_info *current_thread_info(void) #endif #define free_thread_info(ti) kfree(ti) -#else /* !__ASSEMBLY__ */ - -/* how to get the thread information struct from ASM */ -#define GET_THREAD_INFO(reg) \ - stc r7_bank, reg - -#endif +#endif /* __ASSEMBLY__ */ /* * thread information flags diff --git a/include/asm-sh/timer.h b/include/asm-sh/timer.h index 5df842bcf7b..17b5e76a4c3 100644 --- a/include/asm-sh/timer.h +++ b/include/asm-sh/timer.h @@ -18,11 +18,32 @@ struct sys_timer { struct sys_device dev; struct sys_timer_ops *ops; + +#ifdef CONFIG_NO_IDLE_HZ + struct dyn_tick_timer *dyn_tick; +#endif }; +#ifdef CONFIG_NO_IDLE_HZ +#define DYN_TICK_ENABLED (1 << 1) + +struct dyn_tick_timer { + spinlock_t lock; + unsigned int state; /* Current state */ + int (*enable)(void); /* Enables dynamic tick */ + int (*disable)(void); /* Disables dynamic tick */ + void (*reprogram)(unsigned long); /* Reprograms the timer */ + int (*handler)(int, void *); +}; + +void timer_dyn_reprogram(void); +#else +#define timer_dyn_reprogram() do { } while (0) +#endif + #define TICK_SIZE (tick_nsec / 1000) -extern struct sys_timer tmu_timer; +extern struct sys_timer tmu_timer, cmt_timer, mtu2_timer; extern struct sys_timer *sys_timer; #ifndef CONFIG_GENERIC_TIME diff --git a/include/asm-sh/titan.h b/include/asm-sh/titan.h index 270a4f4bc8a..03f3583c891 100644 --- a/include/asm-sh/titan.h +++ b/include/asm-sh/titan.h @@ -1,9 +1,8 @@ /* * Platform defintions for Titan */ - -#ifndef _ASM_SH_TITAN_TITAN_H -#define _ASM_SH_TITAN_TITAN_H +#ifndef _ASM_SH_TITAN_H +#define _ASM_SH_TITAN_H #define __IO_PREFIX titan #include <asm/io_generic.h> @@ -15,29 +14,4 @@ #define TITAN_IRQ_MPCIB 11 /* mPCI B */ #define TITAN_IRQ_USB 11 /* USB */ -/* - * The external interrupt lines, these take up ints 0 - 15 inclusive - * depending on the priority for the interrupt. In fact the priority - * is the interrupt :-) - */ -#define IRL0_IRQ 0 -#define IRL0_IPR_ADDR INTC_IPRD -#define IRL0_IPR_POS 3 -#define IRL0_PRIORITY 8 - -#define IRL1_IRQ 1 -#define IRL1_IPR_ADDR INTC_IPRD -#define IRL1_IPR_POS 2 -#define IRL1_PRIORITY 8 - -#define IRL2_IRQ 2 -#define IRL2_IPR_ADDR INTC_IPRD -#define IRL2_IPR_POS 1 -#define IRL2_PRIORITY 8 - -#define IRL3_IRQ 3 -#define IRL3_IPR_ADDR INTC_IPRD -#define IRL3_IPR_POS 0 -#define IRL3_PRIORITY 8 - -#endif +#endif /* __ASM_SH_TITAN_H */ diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h index 1c2abde122c..0cae1d24876 100644 --- a/include/asm-sh/unistd.h +++ b/include/asm-sh/unistd.h @@ -349,12 +349,30 @@ do { \ return (type) (res); \ } while (0) +#if defined(__sh2__) || defined(__SH2E__) || defined(__SH2A__) +#define SYSCALL_ARG0 "trapa #0x20" +#define SYSCALL_ARG1 "trapa #0x21" +#define SYSCALL_ARG2 "trapa #0x22" +#define SYSCALL_ARG3 "trapa #0x23" +#define SYSCALL_ARG4 "trapa #0x24" +#define SYSCALL_ARG5 "trapa #0x25" +#define SYSCALL_ARG6 "trapa #0x26" +#else +#define SYSCALL_ARG0 "trapa #0x10" +#define SYSCALL_ARG1 "trapa #0x11" +#define SYSCALL_ARG2 "trapa #0x12" +#define SYSCALL_ARG3 "trapa #0x13" +#define SYSCALL_ARG4 "trapa #0x14" +#define SYSCALL_ARG5 "trapa #0x15" +#define SYSCALL_ARG6 "trapa #0x16" +#endif + /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ #define _syscall0(type,name) \ type name(void) \ { \ register long __sc0 __asm__ ("r3") = __NR_##name; \ -__asm__ __volatile__ ("trapa #0x10" \ +__asm__ __volatile__ (SYSCALL_ARG0 \ : "=z" (__sc0) \ : "0" (__sc0) \ : "memory" ); \ @@ -366,7 +384,7 @@ type name(type1 arg1) \ { \ register long __sc0 __asm__ ("r3") = __NR_##name; \ register long __sc4 __asm__ ("r4") = (long) arg1; \ -__asm__ __volatile__ ("trapa #0x11" \ +__asm__ __volatile__ (SYSCALL_ARG1 \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4) \ : "memory"); \ @@ -379,7 +397,7 @@ type name(type1 arg1,type2 arg2) \ register long __sc0 __asm__ ("r3") = __NR_##name; \ register long __sc4 __asm__ ("r4") = (long) arg1; \ register long __sc5 __asm__ ("r5") = (long) arg2; \ -__asm__ __volatile__ ("trapa #0x12" \ +__asm__ __volatile__ (SYSCALL_ARG2 \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5) \ : "memory"); \ @@ -393,7 +411,7 @@ register long __sc0 __asm__ ("r3") = __NR_##name; \ register long __sc4 __asm__ ("r4") = (long) arg1; \ register long __sc5 __asm__ ("r5") = (long) arg2; \ register long __sc6 __asm__ ("r6") = (long) arg3; \ -__asm__ __volatile__ ("trapa #0x13" \ +__asm__ __volatile__ (SYSCALL_ARG3 \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) \ : "memory"); \ @@ -408,7 +426,7 @@ register long __sc4 __asm__ ("r4") = (long) arg1; \ register long __sc5 __asm__ ("r5") = (long) arg2; \ register long __sc6 __asm__ ("r6") = (long) arg3; \ register long __sc7 __asm__ ("r7") = (long) arg4; \ -__asm__ __volatile__ ("trapa #0x14" \ +__asm__ __volatile__ (SYSCALL_ARG4 \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6), \ "r" (__sc7) \ @@ -425,7 +443,7 @@ register long __sc5 __asm__ ("r5") = (long) arg2; \ register long __sc6 __asm__ ("r6") = (long) arg3; \ register long __sc7 __asm__ ("r7") = (long) arg4; \ register long __sc0 __asm__ ("r0") = (long) arg5; \ -__asm__ __volatile__ ("trapa #0x15" \ +__asm__ __volatile__ (SYSCALL_ARG5 \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6), "r" (__sc7), \ "r" (__sc3) \ @@ -443,7 +461,7 @@ register long __sc6 __asm__ ("r6") = (long) arg3; \ register long __sc7 __asm__ ("r7") = (long) arg4; \ register long __sc0 __asm__ ("r0") = (long) arg5; \ register long __sc1 __asm__ ("r1") = (long) arg6; \ -__asm__ __volatile__ ("trapa #0x16" \ +__asm__ __volatile__ (SYSCALL_ARG6 \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6), "r" (__sc7), \ "r" (__sc3), "r" (__sc1) \ diff --git a/include/asm-x86_64/atomic.h b/include/asm-x86_64/atomic.h index 007e88d6d43..93849f7abc2 100644 --- a/include/asm-x86_64/atomic.h +++ b/include/asm-x86_64/atomic.h @@ -21,7 +21,7 @@ * on us. We need to use _exactly_ the address the user gave us, * not some alias that contains the same information. */ -typedef struct { volatile int counter; } atomic_t; +typedef struct { int counter; } atomic_t; #define ATOMIC_INIT(i) { (i) } diff --git a/include/asm-x86_64/spinlock_types.h b/include/asm-x86_64/spinlock_types.h index 59efe849f35..4da9345c150 100644 --- a/include/asm-x86_64/spinlock_types.h +++ b/include/asm-x86_64/spinlock_types.h @@ -6,13 +6,13 @@ #endif typedef struct { - volatile unsigned int slock; + unsigned int slock; } raw_spinlock_t; #define __RAW_SPIN_LOCK_UNLOCKED { 1 } typedef struct { - volatile unsigned int lock; + unsigned int lock; } raw_rwlock_t; #define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } diff --git a/include/linux/aio.h b/include/linux/aio.h index 0d71c0041f1..9e350fd44d7 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -194,7 +194,7 @@ struct kioctx { struct aio_ring_info ring_info; - struct work_struct wq; + struct delayed_work wq; }; /* prototypes */ diff --git a/include/linux/connector.h b/include/linux/connector.h index 4c02119c6ab..3ea1cd58de9 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h @@ -133,7 +133,7 @@ struct cn_callback_data { struct cn_callback_entry { struct list_head callback_entry; struct cn_callback *cb; - struct work_struct work; + struct delayed_work work; struct cn_queue_dev *pdev; struct cn_callback_id id; @@ -170,7 +170,7 @@ void cn_queue_free_dev(struct cn_queue_dev *dev); int cn_cb_equal(struct cb_id *, struct cb_id *); -void cn_queue_wrapper(void *data); +void cn_queue_wrapper(struct work_struct *work); extern int cn_already_initialized; diff --git a/include/linux/i2o.h b/include/linux/i2o.h index c115e9e840b..1fb02e17f6f 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -461,7 +461,7 @@ struct i2o_driver { int (*reply) (struct i2o_controller *, u32, struct i2o_message *); /* Event handler */ - void (*event) (struct i2o_event *); + work_func_t event; struct workqueue_struct *event_queue; /* Event queue */ diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index efe0ee4cc80..06c58c423fe 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -158,7 +158,7 @@ static inline void con_schedule_flip(struct tty_struct *t) if (t->buf.tail != NULL) t->buf.tail->commit = t->buf.tail->used; spin_unlock_irqrestore(&t->buf.lock, flags); - schedule_work(&t->buf.work); + schedule_delayed_work(&t->buf.work, 0); } #endif diff --git a/include/linux/libata.h b/include/linux/libata.h index 202283b5df9..ab275483032 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -575,8 +575,9 @@ struct ata_port { struct ata_host *host; struct device *dev; - struct work_struct port_task; - struct work_struct hotplug_task; + void *port_task_data; + struct delayed_work port_task; + struct delayed_work hotplug_task; struct work_struct scsi_rescan_task; unsigned int hsm_task_state; @@ -755,7 +756,7 @@ extern void ata_host_resume(struct ata_host *host); extern int ata_ratelimit(void); extern int ata_busy_sleep(struct ata_port *ap, unsigned long timeout_pat, unsigned long timeout); -extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), +extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data, unsigned long delay); extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, unsigned long interval_msec, diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 528e7d3fecb..c15ae1986b9 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -110,7 +110,7 @@ struct mmc_host { struct mmc_card *card_busy; /* the MMC card claiming host */ struct mmc_card *card_selected; /* the selected MMC card */ - struct work_struct detect; + struct delayed_work detect; unsigned long private[0] ____cacheline_aligned; }; diff --git a/include/linux/ncp_fs_sb.h b/include/linux/ncp_fs_sb.h index b089d950628..a503052138b 100644 --- a/include/linux/ncp_fs_sb.h +++ b/include/linux/ncp_fs_sb.h @@ -127,10 +127,10 @@ struct ncp_server { } unexpected_packet; }; -extern void ncp_tcp_rcv_proc(void *server); -extern void ncp_tcp_tx_proc(void *server); -extern void ncpdgram_rcv_proc(void *server); -extern void ncpdgram_timeout_proc(void *server); +extern void ncp_tcp_rcv_proc(struct work_struct *work); +extern void ncp_tcp_tx_proc(struct work_struct *work); +extern void ncpdgram_rcv_proc(struct work_struct *work); +extern void ncpdgram_timeout_proc(struct work_struct *work); extern void ncpdgram_timeout_call(unsigned long server); extern void ncp_tcp_data_ready(struct sock* sk, int len); extern void ncp_tcp_write_space(struct sock* sk); diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 2cc9867b162..29930b71a9a 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -32,7 +32,7 @@ struct netpoll_info { struct netpoll *rx_np; /* netpoll that registered an rx_hook */ struct sk_buff_head arp_tx; /* list of arp requests to reply to */ struct sk_buff_head txq; - struct work_struct tx_work; + struct delayed_work tx_work; }; void netpoll_poll(struct netpoll *np); diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 7ccfc7ef0a8..95796e6924f 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -51,7 +51,7 @@ struct nfs_client { unsigned long cl_lease_time; unsigned long cl_last_renewal; - struct work_struct cl_renewd; + struct delayed_work cl_renewd; struct rpc_wait_queue cl_rpcwaitq; diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h index 62a7169aed8..3a28742d86f 100644 --- a/include/linux/reiserfs_fs_sb.h +++ b/include/linux/reiserfs_fs_sb.h @@ -249,7 +249,8 @@ struct reiserfs_journal { int j_errno; /* when flushing ordered buffers, throttle new ordered writers */ - struct work_struct j_work; + struct delayed_work j_work; + struct super_block *j_work_sb; atomic_t j_async_throttle; }; diff --git a/include/linux/relay.h b/include/linux/relay.h index 24accb48384..0e3d91b7699 100644 --- a/include/linux/relay.h +++ b/include/linux/relay.h @@ -38,7 +38,7 @@ struct rchan_buf size_t subbufs_consumed; /* count of sub-buffers consumed */ struct rchan *chan; /* associated channel */ wait_queue_head_t read_wait; /* reader wait queue */ - struct work_struct wake_readers; /* reader wake-up work struct */ + struct delayed_work wake_readers; /* reader wake-up work struct */ struct dentry *dentry; /* channel file dentry */ struct kref kref; /* channel buffer refcount */ struct page **page_array; /* array of current buffer pages */ diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index a2eb9b4a9de..4a68125b6de 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -30,7 +30,7 @@ struct rpc_inode { #define RPC_PIPE_WAIT_FOR_OPEN 1 int flags; struct rpc_pipe_ops *ops; - struct work_struct queue_timeout; + struct delayed_work queue_timeout; }; static inline struct rpc_inode * diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 60394fbc4c7..3e04c1512fc 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -177,7 +177,7 @@ struct rpc_xprt { unsigned long connect_timeout, bind_timeout, reestablish_timeout; - struct work_struct connect_worker; + struct delayed_work connect_worker; unsigned short port; /* diff --git a/include/linux/tty.h b/include/linux/tty.h index 65321f911c1..f717f089823 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -53,7 +53,7 @@ struct tty_buffer { }; struct tty_bufhead { - struct work_struct work; + struct delayed_work work; struct semaphore pty_sem; spinlock_t lock; struct tty_buffer *head; /* Queue head */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 0cd73edeef1..aab5b1b7202 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -388,7 +388,7 @@ struct usb_device { int pm_usage_cnt; /* usage counter for autosuspend */ #ifdef CONFIG_PM - struct work_struct autosuspend; /* for delayed autosuspends */ + struct delayed_work autosuspend; /* for delayed autosuspends */ struct mutex pm_mutex; /* protects PM operations */ unsigned auto_pm:1; /* autosuspend/resume in progress */ diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 9bca3539a1e..4a3ea83c6d1 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -11,12 +11,23 @@ struct workqueue_struct; +struct work_struct; +typedef void (*work_func_t)(struct work_struct *work); + struct work_struct { - unsigned long pending; + /* the first word is the work queue pointer and the flags rolled into + * one */ + unsigned long management; +#define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ +#define WORK_STRUCT_NOAUTOREL 1 /* F if work item automatically released on exec */ +#define WORK_STRUCT_FLAG_MASK (3UL) +#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK) struct list_head entry; - void (*func)(void *); - void *data; - void *wq_data; + work_func_t func; +}; + +struct delayed_work { + struct work_struct work; struct timer_list timer; }; @@ -24,36 +35,117 @@ struct execute_work { struct work_struct work; }; -#define __WORK_INITIALIZER(n, f, d) { \ +#define __WORK_INITIALIZER(n, f) { \ + .management = 0, \ + .entry = { &(n).entry, &(n).entry }, \ + .func = (f), \ + } + +#define __WORK_INITIALIZER_NAR(n, f) { \ + .management = (1 << WORK_STRUCT_NOAUTOREL), \ .entry = { &(n).entry, &(n).entry }, \ .func = (f), \ - .data = (d), \ + } + +#define __DELAYED_WORK_INITIALIZER(n, f) { \ + .work = __WORK_INITIALIZER((n).work, (f)), \ + .timer = TIMER_INITIALIZER(NULL, 0, 0), \ + } + +#define __DELAYED_WORK_INITIALIZER_NAR(n, f) { \ + .work = __WORK_INITIALIZER_NAR((n).work, (f)), \ .timer = TIMER_INITIALIZER(NULL, 0, 0), \ } -#define DECLARE_WORK(n, f, d) \ - struct work_struct n = __WORK_INITIALIZER(n, f, d) +#define DECLARE_WORK(n, f) \ + struct work_struct n = __WORK_INITIALIZER(n, f) + +#define DECLARE_WORK_NAR(n, f) \ + struct work_struct n = __WORK_INITIALIZER_NAR(n, f) + +#define DECLARE_DELAYED_WORK(n, f) \ + struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f) + +#define DECLARE_DELAYED_WORK_NAR(n, f) \ + struct dwork_struct n = __DELAYED_WORK_INITIALIZER_NAR(n, f) /* - * initialize a work-struct's func and data pointers: + * initialize a work item's function pointer */ -#define PREPARE_WORK(_work, _func, _data) \ +#define PREPARE_WORK(_work, _func) \ do { \ - (_work)->func = _func; \ - (_work)->data = _data; \ + (_work)->func = (_func); \ } while (0) +#define PREPARE_DELAYED_WORK(_work, _func) \ + PREPARE_WORK(&(_work)->work, (_func)) + /* - * initialize all of a work-struct: + * initialize all of a work item in one go */ -#define INIT_WORK(_work, _func, _data) \ +#define INIT_WORK(_work, _func) \ do { \ + (_work)->management = 0; \ INIT_LIST_HEAD(&(_work)->entry); \ - (_work)->pending = 0; \ - PREPARE_WORK((_work), (_func), (_data)); \ + PREPARE_WORK((_work), (_func)); \ + } while (0) + +#define INIT_WORK_NAR(_work, _func) \ + do { \ + (_work)->management = (1 << WORK_STRUCT_NOAUTOREL); \ + INIT_LIST_HEAD(&(_work)->entry); \ + PREPARE_WORK((_work), (_func)); \ + } while (0) + +#define INIT_DELAYED_WORK(_work, _func) \ + do { \ + INIT_WORK(&(_work)->work, (_func)); \ + init_timer(&(_work)->timer); \ + } while (0) + +#define INIT_DELAYED_WORK_NAR(_work, _func) \ + do { \ + INIT_WORK_NAR(&(_work)->work, (_func)); \ init_timer(&(_work)->timer); \ } while (0) +/** + * work_pending - Find out whether a work item is currently pending + * @work: The work item in question + */ +#define work_pending(work) \ + test_bit(WORK_STRUCT_PENDING, &(work)->management) + +/** + * delayed_work_pending - Find out whether a delayable work item is currently + * pending + * @work: The work item in question + */ +#define delayed_work_pending(work) \ + test_bit(WORK_STRUCT_PENDING, &(work)->work.management) + +/** + * work_release - Release a work item under execution + * @work: The work item to release + * + * This is used to release a work item that has been initialised with automatic + * release mode disabled (WORK_STRUCT_NOAUTOREL is set). This gives the work + * function the opportunity to grab auxiliary data from the container of the + * work_struct before clearing the pending bit as the work_struct may be + * subject to deallocation the moment the pending bit is cleared. + * + * In such a case, this should be called in the work function after it has + * fetched any data it may require from the containter of the work_struct. + * After this function has been called, the work_struct may be scheduled for + * further execution or it may be deallocated unless other precautions are + * taken. + * + * This should also be used to release a delayed work item. + */ +#define work_release(work) \ + clear_bit(WORK_STRUCT_PENDING, &(work)->management) + + extern struct workqueue_struct *__create_workqueue(const char *name, int singlethread); #define create_workqueue(name) __create_workqueue((name), 0) @@ -62,39 +154,38 @@ extern struct workqueue_struct *__create_workqueue(const char *name, extern void destroy_workqueue(struct workqueue_struct *wq); extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work)); -extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay)); +extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay)); extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, - struct work_struct *work, unsigned long delay); + struct delayed_work *work, unsigned long delay); extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq)); extern int FASTCALL(schedule_work(struct work_struct *work)); -extern int FASTCALL(schedule_delayed_work(struct work_struct *work, unsigned long delay)); +extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay)); -extern int schedule_delayed_work_on(int cpu, struct work_struct *work, unsigned long delay); -extern int schedule_on_each_cpu(void (*func)(void *info), void *info); +extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay); +extern int schedule_on_each_cpu(work_func_t func); extern void flush_scheduled_work(void); extern int current_is_keventd(void); extern int keventd_up(void); extern void init_workqueues(void); -void cancel_rearming_delayed_work(struct work_struct *work); +void cancel_rearming_delayed_work(struct delayed_work *work); void cancel_rearming_delayed_workqueue(struct workqueue_struct *, - struct work_struct *); -int execute_in_process_context(void (*fn)(void *), void *, - struct execute_work *); + struct delayed_work *); +int execute_in_process_context(work_func_t fn, struct execute_work *); /* * Kill off a pending schedule_delayed_work(). Note that the work callback * function may still be running on return from cancel_delayed_work(). Run * flush_scheduled_work() to wait on it. */ -static inline int cancel_delayed_work(struct work_struct *work) +static inline int cancel_delayed_work(struct delayed_work *work) { int ret; ret = del_timer_sync(&work->timer); if (ret) - clear_bit(0, &work->pending); + clear_bit(WORK_STRUCT_PENDING, &work->work.management); return ret; } diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h index 617b672b113..89119277553 100644 --- a/include/net/ieee80211softmac.h +++ b/include/net/ieee80211softmac.h @@ -108,8 +108,8 @@ struct ieee80211softmac_assoc_info { /* Scan retries remaining */ int scan_retry; - struct work_struct work; - struct work_struct timeout; + struct delayed_work work; + struct delayed_work timeout; }; struct ieee80211softmac_bss_info { diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 5f48748fe01..f7be1ac7360 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -84,7 +84,7 @@ struct inet_timewait_death_row { }; extern void inet_twdr_hangman(unsigned long data); -extern void inet_twdr_twkill_work(void *data); +extern void inet_twdr_twkill_work(struct work_struct *work); extern void inet_twdr_twcal_tick(unsigned long data); #if (BITS_PER_LONG == 64) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index f8cbe40f52c..c089f93ba59 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1030,7 +1030,7 @@ void sctp_inq_init(struct sctp_inq *); void sctp_inq_free(struct sctp_inq *); void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); -void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *); +void sctp_inq_set_th_handler(struct sctp_inq *, work_func_t); /* This is the structure we use to hold outbound chunks. You push * chunks in and they automatically pop out the other end as bundled diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index ede639812f8..623a0fc0dae 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -262,9 +262,10 @@ struct pcmcia_socket { u8 present:1, /* PCMCIA card is present in socket */ busy:1, /* "master" ioctl is used */ dead:1, /* pcmcia module is being unloaded */ - device_add_pending:1, /* a pseudo-multifunction-device + device_add_pending:1, /* a multifunction-device * add event is pending */ - reserved:4; + mfc_pfc:1, /* the pending event adds a mfc (1) or pfc (0) */ + reserved:3; } pcmcia_state; struct work_struct device_add; /* for adding further pseudo-multifunction diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 1d77b63c5ea..9233ed5de66 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -201,9 +201,14 @@ struct domain_device { void *lldd_dev; }; +struct sas_discovery_event { + struct work_struct work; + struct asd_sas_port *port; +}; + struct sas_discovery { spinlock_t disc_event_lock; - struct work_struct disc_work[DISC_NUM_EVENTS]; + struct sas_discovery_event disc_work[DISC_NUM_EVENTS]; unsigned long pending; u8 fanout_sas_addr[8]; u8 eeds_a[8]; @@ -249,14 +254,19 @@ struct asd_sas_port { void *lldd_port; /* not touched by the sas class code */ }; +struct asd_sas_event { + struct work_struct work; + struct asd_sas_phy *phy; +}; + /* The phy pretty much is controlled by the LLDD. * The class only reads those fields. */ struct asd_sas_phy { /* private: */ /* protected by ha->event_lock */ - struct work_struct port_events[PORT_NUM_EVENTS]; - struct work_struct phy_events[PHY_NUM_EVENTS]; + struct asd_sas_event port_events[PORT_NUM_EVENTS]; + struct asd_sas_event phy_events[PHY_NUM_EVENTS]; unsigned long port_events_pending; unsigned long phy_events_pending; @@ -308,10 +318,15 @@ struct scsi_core { int queue_thread_kill; }; +struct sas_ha_event { + struct work_struct work; + struct sas_ha_struct *ha; +}; + struct sas_ha_struct { /* private: */ spinlock_t event_lock; - struct work_struct ha_events[HA_NUM_EVENTS]; + struct sas_ha_event ha_events[HA_NUM_EVENTS]; unsigned long pending; struct scsi_core core; @@ -339,6 +354,8 @@ struct sas_ha_struct { void (*notify_phy_event)(struct asd_sas_phy *, enum phy_event); void *lldd_ha; /* not touched by sas class code */ + + struct list_head eh_done_q; }; #define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata) @@ -527,13 +544,16 @@ struct sas_task { void *lldd_task; /* for use by LLDDs */ void *uldd_task; + + struct work_struct abort_work; }; -#define SAS_TASK_STATE_PENDING 1 -#define SAS_TASK_STATE_DONE 2 -#define SAS_TASK_STATE_ABORTED 4 +#define SAS_TASK_STATE_PENDING 1 +#define SAS_TASK_STATE_DONE 2 +#define SAS_TASK_STATE_ABORTED 4 +#define SAS_TASK_INITIATOR_ABORTED 8 static inline struct sas_task *sas_alloc_task(gfp_t flags) { @@ -593,6 +613,7 @@ struct sas_domain_function_template { extern int sas_register_ha(struct sas_ha_struct *); extern int sas_unregister_ha(struct sas_ha_struct *); +int sas_phy_reset(struct sas_phy *phy, int hard_reset); extern int sas_queuecommand(struct scsi_cmnd *, void (*scsi_done)(struct scsi_cmnd *)); extern int sas_target_alloc(struct scsi_target *); @@ -625,4 +646,6 @@ void sas_unregister_dev(struct domain_device *); void sas_init_dev(struct domain_device *); +void sas_task_abort(struct work_struct *); + #endif /* _SASLIB_H_ */ diff --git a/include/scsi/libsrp.h b/include/scsi/libsrp.h new file mode 100644 index 00000000000..d143171896a --- /dev/null +++ b/include/scsi/libsrp.h @@ -0,0 +1,77 @@ +#ifndef __LIBSRP_H__ +#define __LIBSRP_H__ + +#include <linux/list.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_host.h> +#include <scsi/srp.h> + +enum iue_flags { + V_DIOVER, + V_WRITE, + V_LINKED, + V_FLYING, +}; + +struct srp_buf { + dma_addr_t dma; + void *buf; +}; + +struct srp_queue { + void *pool; + void *items; + struct kfifo *queue; + spinlock_t lock; +}; + +struct srp_target { + struct Scsi_Host *shost; + struct device *dev; + + spinlock_t lock; + struct list_head cmd_queue; + + size_t srp_iu_size; + struct srp_queue iu_queue; + size_t rx_ring_size; + struct srp_buf **rx_ring; + + void *ldata; +}; + +struct iu_entry { + struct srp_target *target; + + struct list_head ilist; + dma_addr_t remote_token; + unsigned long flags; + + struct srp_buf *sbuf; +}; + +typedef int (srp_rdma_t)(struct scsi_cmnd *, struct scatterlist *, int, + struct srp_direct_buf *, int, + enum dma_data_direction, unsigned int); +extern int srp_target_alloc(struct srp_target *, struct device *, size_t, size_t); +extern void srp_target_free(struct srp_target *); + +extern struct iu_entry *srp_iu_get(struct srp_target *); +extern void srp_iu_put(struct iu_entry *); + +extern int srp_cmd_queue(struct Scsi_Host *, struct srp_cmd *, void *, u64); +extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *, + srp_rdma_t, int, int); + + +static inline struct srp_target *host_to_srp_target(struct Scsi_Host *host) +{ + return (struct srp_target *) host->hostdata; +} + +static inline int srp_cmd_direction(struct srp_cmd *cmd) +{ + return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; +} + +#endif diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index be117f812de..d6948d0e8cd 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -8,6 +8,7 @@ struct request; struct scatterlist; +struct Scsi_Host; struct scsi_device; @@ -72,6 +73,9 @@ struct scsi_cmnd { unsigned short use_sg; /* Number of pieces of scatter-gather */ unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + /* offset in cmd we are at (for multi-transfer tgt cmds) */ + unsigned offset; + unsigned underflow; /* Return error if less than this amount is transferred */ @@ -119,7 +123,10 @@ struct scsi_cmnd { }; extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); +extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t); extern void scsi_put_command(struct scsi_cmnd *); +extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *, + struct device *); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_finish_command(struct scsi_cmnd *cmd); extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd); @@ -128,4 +135,7 @@ extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count, size_t *offset, size_t *len); extern void scsi_kunmap_atomic_sg(void *virt); +extern struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *, gfp_t); +extern void scsi_free_sgtable(struct scatterlist *, int); + #endif /* _SCSI_SCSI_CMND_H */ diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index b401c82036b..ebf31b16dc4 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -223,13 +223,13 @@ extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *, struct scsi_device *); /** - * shost_for_each_device - iterate over all devices of a host - * @sdev: iterator - * @host: host whiches devices we want to iterate over + * shost_for_each_device - iterate over all devices of a host + * @sdev: the &struct scsi_device to use as a cursor + * @shost: the &struct scsi_host to iterate over * - * This traverses over each devices of @shost. The devices have - * a reference that must be released by scsi_host_put when breaking - * out of the loop. + * Iterator that returns each device attached to @shost. This loop + * takes a reference on each device and releases it at the end. If + * you break out of the loop, you must call scsi_device_put(sdev). */ #define shost_for_each_device(sdev, shost) \ for ((sdev) = __scsi_iterate_devices((shost), NULL); \ @@ -237,17 +237,17 @@ extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *, (sdev) = __scsi_iterate_devices((shost), (sdev))) /** - * __shost_for_each_device - iterate over all devices of a host (UNLOCKED) - * @sdev: iterator - * @host: host whiches devices we want to iterate over + * __shost_for_each_device - iterate over all devices of a host (UNLOCKED) + * @sdev: the &struct scsi_device to use as a cursor + * @shost: the &struct scsi_host to iterate over * - * This traverses over each devices of @shost. It does _not_ take a - * reference on the scsi_device, thus it the whole loop must be protected - * by shost->host_lock. + * Iterator that returns each device attached to @shost. It does _not_ + * take a reference on the scsi_device, so the whole loop must be + * protected by shost->host_lock. * - * Note: The only reason why drivers would want to use this is because - * they're need to access the device list in irq context. Otherwise you - * really want to use shost_for_each_device instead. + * Note: The only reason to use this is because you need to access the + * device list in interrupt context. Otherwise you really want to use + * shost_for_each_device instead. */ #define __shost_for_each_device(sdev, shost) \ list_for_each_entry((sdev), &((shost)->__devices), siblings) diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 39c6f8cc20c..7f1f411d07a 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -7,6 +7,7 @@ #include <linux/workqueue.h> #include <linux/mutex.h> +struct request_queue; struct block_device; struct completion; struct module; @@ -124,6 +125,39 @@ struct scsi_host_template { void (*done)(struct scsi_cmnd *)); /* + * The transfer functions are used to queue a scsi command to + * the LLD. When the driver is finished processing the command + * the done callback is invoked. + * + * return values: see queuecommand + * + * If the LLD accepts the cmd, it should set the result to an + * appropriate value when completed before calling the done function. + * + * STATUS: REQUIRED FOR TARGET DRIVERS + */ + /* TODO: rename */ + int (* transfer_response)(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); + /* + * This is called to inform the LLD to transfer cmd->request_bufflen + * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg + * speciefies the number of scatterlist entried in the command + * and cmd->request_buffer contains the scatterlist. + * + * If the command cannot be processed in one transfer_data call + * becuase a scatterlist within the LLD's limits cannot be + * created then transfer_data will be called multiple times. + * It is initially called from process context, and later + * calls are from the interrup context. + */ + int (* transfer_data)(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); + + /* Used as callback for the completion of task management request. */ + int (* tsk_mgmt_response)(u64 mid, int result); + + /* * This is an error handling strategy routine. You don't need to * define one of these if you don't want to - there is a default * routine that is present that should work in most cases. For those @@ -241,6 +275,24 @@ struct scsi_host_template { void (* target_destroy)(struct scsi_target *); /* + * If a host has the ability to discover targets on its own instead + * of scanning the entire bus, it can fill in this function and + * call scsi_scan_host(). This function will be called periodically + * until it returns 1 with the scsi_host and the elapsed time of + * the scan in jiffies. + * + * Status: OPTIONAL + */ + int (* scan_finished)(struct Scsi_Host *, unsigned long); + + /* + * If the host wants to be called before the scan starts, but + * after the midlayer has set up ready for the scan, it can fill + * in this function. + */ + void (* scan_start)(struct Scsi_Host *); + + /* * fill in this function to allow the queue depth of this host * to be changeable (on a per device basis). returns either * the current queue depth setting (may be different from what @@ -552,6 +604,9 @@ struct Scsi_Host { /* task mgmt function in progress */ unsigned tmf_in_progress:1; + /* Asynchronous scan in progress */ + unsigned async_scan:1; + /* * Optional work queue to be utilized by the transport */ @@ -568,6 +623,12 @@ struct Scsi_Host { */ unsigned int max_host_blocked; + /* + * q used for scsi_tgt msgs, async events or any other requests that + * need to be processed in userspace + */ + struct request_queue *uspace_req_q; + /* legacy crap */ unsigned long base; unsigned long io_port; @@ -648,11 +709,6 @@ extern const char *scsi_host_state_name(enum scsi_host_state); extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); -static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) -{ - shost->host_lock = lock; -} - static inline struct device *scsi_get_device(struct Scsi_Host *shost) { return shost->shost_gendev.parent; @@ -671,6 +727,9 @@ extern void scsi_unblock_requests(struct Scsi_Host *); extern void scsi_block_requests(struct Scsi_Host *); struct class_container; + +extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, + void (*) (struct request_queue *)); /* * These two functions are used to allocate and free a pseudo device * which will connect to the host adapter itself rather than any diff --git a/include/scsi/scsi_tgt.h b/include/scsi/scsi_tgt.h new file mode 100644 index 00000000000..4f4427937af --- /dev/null +++ b/include/scsi/scsi_tgt.h @@ -0,0 +1,19 @@ +/* + * SCSI target definitions + */ + +#include <linux/dma-mapping.h> + +struct Scsi_Host; +struct scsi_cmnd; +struct scsi_lun; + +extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *); +extern int scsi_tgt_alloc_queue(struct Scsi_Host *); +extern void scsi_tgt_free_queue(struct Scsi_Host *); +extern int scsi_tgt_queue_command(struct scsi_cmnd *, struct scsi_lun *, u64); +extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, int, u64, struct scsi_lun *, + void *); +extern struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *, + enum dma_data_direction, gfp_t); +extern void scsi_host_put_command(struct Scsi_Host *, struct scsi_cmnd *); diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h new file mode 100644 index 00000000000..46d5e70d721 --- /dev/null +++ b/include/scsi/scsi_tgt_if.h @@ -0,0 +1,90 @@ +/* + * SCSI target kernel/user interface + * + * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org> + * Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#ifndef __SCSI_TARGET_IF_H +#define __SCSI_TARGET_IF_H + +/* user -> kernel */ +#define TGT_UEVENT_CMD_RSP 0x0001 +#define TGT_UEVENT_TSK_MGMT_RSP 0x0002 + +/* kernel -> user */ +#define TGT_KEVENT_CMD_REQ 0x1001 +#define TGT_KEVENT_CMD_DONE 0x1002 +#define TGT_KEVENT_TSK_MGMT_REQ 0x1003 + +struct tgt_event_hdr { + uint16_t version; + uint16_t status; + uint16_t type; + uint16_t len; +} __attribute__ ((aligned (sizeof(uint64_t)))); + +struct tgt_event { + struct tgt_event_hdr hdr; + + union { + /* user-> kernel */ + struct { + int host_no; + uint32_t len; + int result; + aligned_u64 uaddr; + uint8_t rw; + aligned_u64 tag; + } cmd_rsp; + struct { + int host_no; + aligned_u64 mid; + int result; + } tsk_mgmt_rsp; + + + /* kernel -> user */ + struct { + int host_no; + uint32_t data_len; + uint8_t scb[16]; + uint8_t lun[8]; + int attribute; + aligned_u64 tag; + } cmd_req; + struct { + int host_no; + aligned_u64 tag; + int result; + } cmd_done; + struct { + int host_no; + int function; + aligned_u64 tag; + uint8_t lun[8]; + aligned_u64 mid; + } tsk_mgmt_req; + } p; +} __attribute__ ((aligned (sizeof(uint64_t)))); + +#define TGT_RING_SIZE (1UL << 16) +#define TGT_RING_PAGES (TGT_RING_SIZE >> PAGE_SHIFT) +#define TGT_EVENT_PER_PAGE (PAGE_SIZE / sizeof(struct tgt_event)) +#define TGT_MAX_EVENTS (TGT_EVENT_PER_PAGE * TGT_RING_PAGES) + +#endif diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index fd352323378..798f7c7ee42 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -206,9 +206,9 @@ struct fc_rport { /* aka fc_starget_attrs */ u8 flags; struct list_head peers; struct device dev; - struct work_struct dev_loss_work; + struct delayed_work dev_loss_work; struct work_struct scan_work; - struct work_struct fail_io_work; + struct delayed_work fail_io_work; struct work_struct stgt_delete_work; struct work_struct rport_delete_work; } __attribute__((aligned(sizeof(unsigned long)))); diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 4b95c89c95c..d5c218ddc52 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -176,7 +176,7 @@ struct iscsi_cls_session { /* recovery fields */ int recovery_tmo; - struct work_struct recovery_work; + struct delayed_work recovery_work; int target_id; diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h index 53024377f3b..59633a82de4 100644 --- a/include/scsi/scsi_transport_sas.h +++ b/include/scsi/scsi_transport_sas.h @@ -73,6 +73,8 @@ struct sas_phy { /* for the list of phys belonging to a port */ struct list_head port_siblings; + + struct work_struct reset_work; }; #define dev_to_phy(d) \ diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 4c43521cc49..33720397a90 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -511,7 +511,7 @@ struct snd_ac97 { #ifdef CONFIG_SND_AC97_POWER_SAVE unsigned int power_up; /* power states */ struct workqueue_struct *power_workq; - struct work_struct power_work; + struct delayed_work power_work; #endif struct device dev; }; diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h index 11702aa0bea..2ee061625fd 100644 --- a/include/sound/ak4114.h +++ b/include/sound/ak4114.h @@ -182,7 +182,7 @@ struct ak4114 { unsigned char rcs0; unsigned char rcs1; struct workqueue_struct *workqueue; - struct work_struct work; + struct delayed_work work; void *change_callback_private; void (*change_callback)(struct ak4114 *ak4114, unsigned char c0, unsigned char c1); }; diff --git a/ipc/util.c b/ipc/util.c index cd8bb14a431..a9b7a227b8d 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -514,6 +514,11 @@ void ipc_rcu_getref(void *ptr) container_of(ptr, struct ipc_rcu_hdr, data)->refcount++; } +static void ipc_do_vfree(struct work_struct *work) +{ + vfree(container_of(work, struct ipc_rcu_sched, work)); +} + /** * ipc_schedule_free - free ipc + rcu space * @head: RCU callback structure for queued work @@ -528,7 +533,7 @@ static void ipc_schedule_free(struct rcu_head *head) struct ipc_rcu_sched *sched = container_of(&(grace->data[0]), struct ipc_rcu_sched, data[0]); - INIT_WORK(&sched->work, vfree, sched); + INIT_WORK(&sched->work, ipc_do_vfree); schedule_work(&sched->work); } diff --git a/kernel/kmod.c b/kernel/kmod.c index 2b76dee2849..8d2bea09a4e 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -114,6 +114,7 @@ EXPORT_SYMBOL(request_module); #endif /* CONFIG_KMOD */ struct subprocess_info { + struct work_struct work; struct completion *complete; char *path; char **argv; @@ -221,9 +222,10 @@ static int wait_for_helper(void *data) } /* This is run by khelper thread */ -static void __call_usermodehelper(void *data) +static void __call_usermodehelper(struct work_struct *work) { - struct subprocess_info *sub_info = data; + struct subprocess_info *sub_info = + container_of(work, struct subprocess_info, work); pid_t pid; int wait = sub_info->wait; @@ -264,6 +266,8 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp, { DECLARE_COMPLETION_ONSTACK(done); struct subprocess_info sub_info = { + .work = __WORK_INITIALIZER(sub_info.work, + __call_usermodehelper), .complete = &done, .path = path, .argv = argv, @@ -272,7 +276,6 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp, .wait = wait, .retval = 0, }; - DECLARE_WORK(work, __call_usermodehelper, &sub_info); if (!khelper_wq) return -EBUSY; @@ -280,7 +283,7 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp, if (path[0] == '\0') return 0; - queue_work(khelper_wq, &work); + queue_work(khelper_wq, &sub_info.work); wait_for_completion(&done); return sub_info.retval; } @@ -291,6 +294,8 @@ int call_usermodehelper_pipe(char *path, char **argv, char **envp, { DECLARE_COMPLETION(done); struct subprocess_info sub_info = { + .work = __WORK_INITIALIZER(sub_info.work, + __call_usermodehelper), .complete = &done, .path = path, .argv = argv, @@ -298,7 +303,6 @@ int call_usermodehelper_pipe(char *path, char **argv, char **envp, .retval = 0, }; struct file *f; - DECLARE_WORK(work, __call_usermodehelper, &sub_info); if (!khelper_wq) return -EBUSY; @@ -318,7 +322,7 @@ int call_usermodehelper_pipe(char *path, char **argv, char **envp, } sub_info.stdin = f; - queue_work(khelper_wq, &work); + queue_work(khelper_wq, &sub_info.work); wait_for_completion(&done); return sub_info.retval; } diff --git a/kernel/kthread.c b/kernel/kthread.c index 4f9c60ef95e..1db8c72d0d3 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -31,6 +31,8 @@ struct kthread_create_info /* Result passed back to kthread_create() from keventd. */ struct task_struct *result; struct completion done; + + struct work_struct work; }; struct kthread_stop_info @@ -111,9 +113,10 @@ static int kthread(void *_create) } /* We are keventd: create a thread. */ -static void keventd_create_kthread(void *_create) +static void keventd_create_kthread(struct work_struct *work) { - struct kthread_create_info *create = _create; + struct kthread_create_info *create = + container_of(work, struct kthread_create_info, work); int pid; /* We want our own signal handler (we take no signals by default). */ @@ -154,20 +157,20 @@ struct task_struct *kthread_create(int (*threadfn)(void *data), ...) { struct kthread_create_info create; - DECLARE_WORK(work, keventd_create_kthread, &create); create.threadfn = threadfn; create.data = data; init_completion(&create.started); init_completion(&create.done); + INIT_WORK(&create.work, keventd_create_kthread); /* * The workqueue needs to start up first: */ if (!helper_wq) - work.func(work.data); + create.work.func(&create.work); else { - queue_work(helper_wq, &work); + queue_work(helper_wq, &create.work); wait_for_completion(&create.done); } if (!IS_ERR(create.result)) { diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c index f1f900ac316..678ec736076 100644 --- a/kernel/power/poweroff.c +++ b/kernel/power/poweroff.c @@ -16,12 +16,12 @@ * callback we use. */ -static void do_poweroff(void *dummy) +static void do_poweroff(struct work_struct *dummy) { kernel_power_off(); } -static DECLARE_WORK(poweroff_work, do_poweroff, NULL); +static DECLARE_WORK(poweroff_work, do_poweroff); static void handle_poweroff(int key, struct tty_struct *tty) { diff --git a/kernel/relay.c b/kernel/relay.c index f04bbdb56ac..2b92e8ece85 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -308,9 +308,10 @@ static struct rchan_callbacks default_channel_callbacks = { * reason waking is deferred is that calling directly from write * causes problems if you're writing from say the scheduler. */ -static void wakeup_readers(void *private) +static void wakeup_readers(struct work_struct *work) { - struct rchan_buf *buf = private; + struct rchan_buf *buf = + container_of(work, struct rchan_buf, wake_readers.work); wake_up_interruptible(&buf->read_wait); } @@ -328,7 +329,7 @@ static inline void __relay_reset(struct rchan_buf *buf, unsigned int init) if (init) { init_waitqueue_head(&buf->read_wait); kref_init(&buf->kref); - INIT_WORK(&buf->wake_readers, NULL, NULL); + INIT_DELAYED_WORK(&buf->wake_readers, NULL); } else { cancel_delayed_work(&buf->wake_readers); flush_scheduled_work(); @@ -549,7 +550,8 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length) buf->padding[old_subbuf]; smp_mb(); if (waitqueue_active(&buf->read_wait)) { - PREPARE_WORK(&buf->wake_readers, wakeup_readers, buf); + PREPARE_DELAYED_WORK(&buf->wake_readers, + wakeup_readers); schedule_delayed_work(&buf->wake_readers, 1); } } diff --git a/kernel/sys.c b/kernel/sys.c index 98489d82801..c87b461de38 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -880,7 +880,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user return 0; } -static void deferred_cad(void *dummy) +static void deferred_cad(struct work_struct *dummy) { kernel_restart(NULL); } @@ -892,7 +892,7 @@ static void deferred_cad(void *dummy) */ void ctrl_alt_del(void) { - static DECLARE_WORK(cad_work, deferred_cad, NULL); + static DECLARE_WORK(cad_work, deferred_cad); if (C_A_D) schedule_work(&cad_work); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 17c2f03d2c2..8d1e7cb8a51 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -80,6 +80,29 @@ static inline int is_single_threaded(struct workqueue_struct *wq) return list_empty(&wq->list); } +static inline void set_wq_data(struct work_struct *work, void *wq) +{ + unsigned long new, old, res; + + /* assume the pending flag is already set and that the task has already + * been queued on this workqueue */ + new = (unsigned long) wq | (1UL << WORK_STRUCT_PENDING); + res = work->management; + if (res != new) { + do { + old = res; + new = (unsigned long) wq; + new |= (old & WORK_STRUCT_FLAG_MASK); + res = cmpxchg(&work->management, old, new); + } while (res != old); + } +} + +static inline void *get_wq_data(struct work_struct *work) +{ + return (void *) (work->management & WORK_STRUCT_WQ_DATA_MASK); +} + /* Preempt must be disabled. */ static void __queue_work(struct cpu_workqueue_struct *cwq, struct work_struct *work) @@ -87,7 +110,7 @@ static void __queue_work(struct cpu_workqueue_struct *cwq, unsigned long flags; spin_lock_irqsave(&cwq->lock, flags); - work->wq_data = cwq; + set_wq_data(work, cwq); list_add_tail(&work->entry, &cwq->worklist); cwq->insert_sequence++; wake_up(&cwq->more_work); @@ -108,7 +131,7 @@ int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work) { int ret = 0, cpu = get_cpu(); - if (!test_and_set_bit(0, &work->pending)) { + if (!test_and_set_bit(WORK_STRUCT_PENDING, &work->management)) { if (unlikely(is_single_threaded(wq))) cpu = singlethread_cpu; BUG_ON(!list_empty(&work->entry)); @@ -122,38 +145,42 @@ EXPORT_SYMBOL_GPL(queue_work); static void delayed_work_timer_fn(unsigned long __data) { - struct work_struct *work = (struct work_struct *)__data; - struct workqueue_struct *wq = work->wq_data; + struct delayed_work *dwork = (struct delayed_work *)__data; + struct workqueue_struct *wq = get_wq_data(&dwork->work); int cpu = smp_processor_id(); if (unlikely(is_single_threaded(wq))) cpu = singlethread_cpu; - __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); + __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), &dwork->work); } /** * queue_delayed_work - queue work on a workqueue after delay * @wq: workqueue to use - * @work: work to queue + * @work: delayable work to queue * @delay: number of jiffies to wait before queueing * * Returns 0 if @work was already on a queue, non-zero otherwise. */ int fastcall queue_delayed_work(struct workqueue_struct *wq, - struct work_struct *work, unsigned long delay) + struct delayed_work *dwork, unsigned long delay) { int ret = 0; - struct timer_list *timer = &work->timer; + struct timer_list *timer = &dwork->timer; + struct work_struct *work = &dwork->work; + + if (delay == 0) + return queue_work(wq, work); - if (!test_and_set_bit(0, &work->pending)) { + if (!test_and_set_bit(WORK_STRUCT_PENDING, &work->management)) { BUG_ON(timer_pending(timer)); BUG_ON(!list_empty(&work->entry)); /* This stores wq for the moment, for the timer_fn */ - work->wq_data = wq; + set_wq_data(work, wq); timer->expires = jiffies + delay; - timer->data = (unsigned long)work; + timer->data = (unsigned long)dwork; timer->function = delayed_work_timer_fn; add_timer(timer); ret = 1; @@ -172,19 +199,20 @@ EXPORT_SYMBOL_GPL(queue_delayed_work); * Returns 0 if @work was already on a queue, non-zero otherwise. */ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, - struct work_struct *work, unsigned long delay) + struct delayed_work *dwork, unsigned long delay) { int ret = 0; - struct timer_list *timer = &work->timer; + struct timer_list *timer = &dwork->timer; + struct work_struct *work = &dwork->work; - if (!test_and_set_bit(0, &work->pending)) { + if (!test_and_set_bit(WORK_STRUCT_PENDING, &work->management)) { BUG_ON(timer_pending(timer)); BUG_ON(!list_empty(&work->entry)); /* This stores wq for the moment, for the timer_fn */ - work->wq_data = wq; + set_wq_data(work, wq); timer->expires = jiffies + delay; - timer->data = (unsigned long)work; + timer->data = (unsigned long)dwork; timer->function = delayed_work_timer_fn; add_timer_on(timer, cpu); ret = 1; @@ -212,15 +240,15 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq) while (!list_empty(&cwq->worklist)) { struct work_struct *work = list_entry(cwq->worklist.next, struct work_struct, entry); - void (*f) (void *) = work->func; - void *data = work->data; + work_func_t f = work->func; list_del_init(cwq->worklist.next); spin_unlock_irqrestore(&cwq->lock, flags); - BUG_ON(work->wq_data != cwq); - clear_bit(0, &work->pending); - f(data); + BUG_ON(get_wq_data(work) != cwq); + if (!test_bit(WORK_STRUCT_NOAUTOREL, &work->management)) + work_release(work); + f(work); spin_lock_irqsave(&cwq->lock, flags); cwq->remove_sequence++; @@ -468,38 +496,37 @@ EXPORT_SYMBOL(schedule_work); /** * schedule_delayed_work - put work task in global workqueue after delay - * @work: job to be done - * @delay: number of jiffies to wait + * @dwork: job to be done + * @delay: number of jiffies to wait or 0 for immediate execution * * After waiting for a given time this puts a job in the kernel-global * workqueue. */ -int fastcall schedule_delayed_work(struct work_struct *work, unsigned long delay) +int fastcall schedule_delayed_work(struct delayed_work *dwork, unsigned long delay) { - return queue_delayed_work(keventd_wq, work, delay); + return queue_delayed_work(keventd_wq, dwork, delay); } EXPORT_SYMBOL(schedule_delayed_work); /** * schedule_delayed_work_on - queue work in global workqueue on CPU after delay * @cpu: cpu to use - * @work: job to be done + * @dwork: job to be done * @delay: number of jiffies to wait * * After waiting for a given time this puts a job in the kernel-global * workqueue on the specified CPU. */ int schedule_delayed_work_on(int cpu, - struct work_struct *work, unsigned long delay) + struct delayed_work *dwork, unsigned long delay) { - return queue_delayed_work_on(cpu, keventd_wq, work, delay); + return queue_delayed_work_on(cpu, keventd_wq, dwork, delay); } EXPORT_SYMBOL(schedule_delayed_work_on); /** * schedule_on_each_cpu - call a function on each online CPU from keventd * @func: the function to call - * @info: a pointer to pass to func() * * Returns zero on success. * Returns -ve errno on failure. @@ -508,7 +535,7 @@ EXPORT_SYMBOL(schedule_delayed_work_on); * * schedule_on_each_cpu() is very slow. */ -int schedule_on_each_cpu(void (*func)(void *info), void *info) +int schedule_on_each_cpu(work_func_t func) { int cpu; struct work_struct *works; @@ -519,7 +546,7 @@ int schedule_on_each_cpu(void (*func)(void *info), void *info) mutex_lock(&workqueue_mutex); for_each_online_cpu(cpu) { - INIT_WORK(per_cpu_ptr(works, cpu), func, info); + INIT_WORK(per_cpu_ptr(works, cpu), func); __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), per_cpu_ptr(works, cpu)); } @@ -539,12 +566,12 @@ EXPORT_SYMBOL(flush_scheduled_work); * cancel_rearming_delayed_workqueue - reliably kill off a delayed * work whose handler rearms the delayed work. * @wq: the controlling workqueue structure - * @work: the delayed work struct + * @dwork: the delayed work struct */ void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq, - struct work_struct *work) + struct delayed_work *dwork) { - while (!cancel_delayed_work(work)) + while (!cancel_delayed_work(dwork)) flush_workqueue(wq); } EXPORT_SYMBOL(cancel_rearming_delayed_workqueue); @@ -552,18 +579,17 @@ EXPORT_SYMBOL(cancel_rearming_delayed_workqueue); /** * cancel_rearming_delayed_work - reliably kill off a delayed keventd * work whose handler rearms the delayed work. - * @work: the delayed work struct + * @dwork: the delayed work struct */ -void cancel_rearming_delayed_work(struct work_struct *work) +void cancel_rearming_delayed_work(struct delayed_work *dwork) { - cancel_rearming_delayed_workqueue(keventd_wq, work); + cancel_rearming_delayed_workqueue(keventd_wq, dwork); } EXPORT_SYMBOL(cancel_rearming_delayed_work); /** * execute_in_process_context - reliably execute the routine with user context * @fn: the function to execute - * @data: data to pass to the function * @ew: guaranteed storage for the execute work structure (must * be available when the work executes) * @@ -573,15 +599,14 @@ EXPORT_SYMBOL(cancel_rearming_delayed_work); * Returns: 0 - function was executed * 1 - function was scheduled for execution */ -int execute_in_process_context(void (*fn)(void *data), void *data, - struct execute_work *ew) +int execute_in_process_context(work_func_t fn, struct execute_work *ew) { if (!in_interrupt()) { - fn(data); + fn(&ew->work); return 0; } - INIT_WORK(&ew->work, fn, data); + INIT_WORK(&ew->work, fn); schedule_work(&ew->work); return 1; diff --git a/mm/nommu.c b/mm/nommu.c index 8bdde9508f3..6a2a8aada40 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -497,15 +497,17 @@ static int validate_mmap_request(struct file *file, (flags & MAP_TYPE) != MAP_SHARED) return -EINVAL; - if (PAGE_ALIGN(len) == 0) - return addr; - - if (len > TASK_SIZE) + if (!len) return -EINVAL; + /* Careful about overflows.. */ + len = PAGE_ALIGN(len); + if (!len || len > TASK_SIZE) + return -ENOMEM; + /* offset overflow? */ if ((pgoff + (len >> PAGE_SHIFT)) < pgoff) - return -EINVAL; + return -EOVERFLOW; if (file) { /* validate file mapping requests */ diff --git a/mm/slab.c b/mm/slab.c index 3c4a7e34edd..5de81473df3 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -313,7 +313,7 @@ static int drain_freelist(struct kmem_cache *cache, static void free_block(struct kmem_cache *cachep, void **objpp, int len, int node); static int enable_cpucache(struct kmem_cache *cachep); -static void cache_reap(void *unused); +static void cache_reap(struct work_struct *unused); /* * This function must be completely optimized away if a constant is passed to @@ -753,7 +753,7 @@ int slab_is_available(void) return g_cpucache_up == FULL; } -static DEFINE_PER_CPU(struct work_struct, reap_work); +static DEFINE_PER_CPU(struct delayed_work, reap_work); static inline struct array_cache *cpu_cache_get(struct kmem_cache *cachep) { @@ -916,16 +916,16 @@ static void next_reap_node(void) */ static void __devinit start_cpu_timer(int cpu) { - struct work_struct *reap_work = &per_cpu(reap_work, cpu); + struct delayed_work *reap_work = &per_cpu(reap_work, cpu); /* * When this gets called from do_initcalls via cpucache_init(), * init_workqueues() has already run, so keventd will be setup * at that time. */ - if (keventd_up() && reap_work->func == NULL) { + if (keventd_up() && reap_work->work.func == NULL) { init_reap_node(cpu); - INIT_WORK(reap_work, cache_reap, NULL); + INIT_DELAYED_WORK(reap_work, cache_reap); schedule_delayed_work_on(cpu, reap_work, HZ + 3 * cpu); } } @@ -3815,7 +3815,7 @@ void drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3, * If we cannot acquire the cache chain mutex then just give up - we'll try * again on the next iteration. */ -static void cache_reap(void *unused) +static void cache_reap(struct work_struct *unused) { struct kmem_cache *searchp; struct kmem_list3 *l3; diff --git a/mm/swap.c b/mm/swap.c index 2e0e871f542..d9a3770d8f3 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -216,7 +216,7 @@ void lru_add_drain(void) } #ifdef CONFIG_NUMA -static void lru_add_drain_per_cpu(void *dummy) +static void lru_add_drain_per_cpu(struct work_struct *dummy) { lru_add_drain(); } @@ -226,7 +226,7 @@ static void lru_add_drain_per_cpu(void *dummy) */ int lru_add_drain_all(void) { - return schedule_on_each_cpu(lru_add_drain_per_cpu, NULL); + return schedule_on_each_cpu(lru_add_drain_per_cpu); } #else diff --git a/net/atm/lec.c b/net/atm/lec.c index 5946ec63724..3fc0abeeaf3 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -1454,7 +1454,7 @@ static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr, #define LEC_ARP_REFRESH_INTERVAL (3*HZ) -static void lec_arp_check_expire(void *data); +static void lec_arp_check_expire(struct work_struct *work); static void lec_arp_expire_arp(unsigned long data); /* @@ -1477,7 +1477,7 @@ static void lec_arp_init(struct lec_priv *priv) INIT_HLIST_HEAD(&priv->lec_no_forward); INIT_HLIST_HEAD(&priv->mcast_fwds); spin_lock_init(&priv->lec_arp_lock); - INIT_WORK(&priv->lec_arp_work, lec_arp_check_expire, priv); + INIT_DELAYED_WORK(&priv->lec_arp_work, lec_arp_check_expire); schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL); } @@ -1875,10 +1875,11 @@ static void lec_arp_expire_vcc(unsigned long data) * to ESI_FORWARD_DIRECT. This causes the flush period to end * regardless of the progress of the flush protocol. */ -static void lec_arp_check_expire(void *data) +static void lec_arp_check_expire(struct work_struct *work) { unsigned long flags; - struct lec_priv *priv = data; + struct lec_priv *priv = + container_of(work, struct lec_priv, lec_arp_work.work); struct hlist_node *node, *next; struct lec_arp_table *entry; unsigned long now; diff --git a/net/atm/lec.h b/net/atm/lec.h index 24cc95f8674..99136babd53 100644 --- a/net/atm/lec.h +++ b/net/atm/lec.h @@ -92,7 +92,7 @@ struct lec_priv { spinlock_t lec_arp_lock; struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ struct atm_vcc *lecd; - struct work_struct lec_arp_work; /* C10 */ + struct delayed_work lec_arp_work; /* C10 */ unsigned int maximum_unknown_frame_count; /* * Within the period of time defined by this variable, the client will send diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 3eeeb7a86e7..d4c935692cc 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -237,9 +237,9 @@ static void bt_release(struct device *dev) kfree(data); } -static void add_conn(void *data) +static void add_conn(struct work_struct *work) { - struct hci_conn *conn = data; + struct hci_conn *conn = container_of(work, struct hci_conn, work); int i; if (device_register(&conn->dev) < 0) { @@ -272,14 +272,14 @@ void hci_conn_add_sysfs(struct hci_conn *conn) dev_set_drvdata(&conn->dev, conn); - INIT_WORK(&conn->work, add_conn, (void *) conn); + INIT_WORK(&conn->work, add_conn); schedule_work(&conn->work); } -static void del_conn(void *data) +static void del_conn(struct work_struct *work) { - struct hci_conn *conn = data; + struct hci_conn *conn = container_of(work, struct hci_conn, work); device_del(&conn->dev); } @@ -287,7 +287,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn) { BT_DBG("conn %p", conn); - INIT_WORK(&conn->work, del_conn, (void *) conn); + INIT_WORK(&conn->work, del_conn); schedule_work(&conn->work); } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f753c40c11d..55bb2634c08 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -77,12 +77,16 @@ static int port_cost(struct net_device *dev) * Called from work queue to allow for calling functions that * might sleep (such as speed check), and to debounce. */ -static void port_carrier_check(void *arg) +static void port_carrier_check(struct work_struct *work) { - struct net_device *dev = arg; struct net_bridge_port *p; + struct net_device *dev; struct net_bridge *br; + dev = container_of(work, struct net_bridge_port, + carrier_check.work)->dev; + work_release(work); + rtnl_lock(); p = dev->br_port; if (!p) @@ -276,7 +280,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, p->port_no = index; br_init_port(p); p->state = BR_STATE_DISABLED; - INIT_WORK(&p->carrier_check, port_carrier_check, dev); + INIT_DELAYED_WORK_NAR(&p->carrier_check, port_carrier_check); br_stp_port_timer_init(p); kobject_init(&p->kobj); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 74258d86f25..3a534e94c7f 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -82,7 +82,7 @@ struct net_bridge_port struct timer_list hold_timer; struct timer_list message_age_timer; struct kobject kobj; - struct work_struct carrier_check; + struct delayed_work carrier_check; struct rcu_head rcu; }; diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 4b36114744c..549a2ce951b 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -34,8 +34,8 @@ enum lw_bits { static unsigned long linkwatch_flags; static unsigned long linkwatch_nextevent; -static void linkwatch_event(void *dummy); -static DECLARE_WORK(linkwatch_work, linkwatch_event, NULL); +static void linkwatch_event(struct work_struct *dummy); +static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); static LIST_HEAD(lweventlist); static DEFINE_SPINLOCK(lweventlist_lock); @@ -127,7 +127,7 @@ void linkwatch_run_queue(void) } -static void linkwatch_event(void *dummy) +static void linkwatch_event(struct work_struct *dummy) { /* Limit the number of linkwatch events to one * per second so that a runaway driver does not @@ -171,10 +171,9 @@ void linkwatch_fire_event(struct net_device *dev) unsigned long delay = linkwatch_nextevent - jiffies; /* If we wrap around we'll delay it by at most HZ. */ - if (!delay || delay > HZ) - schedule_work(&linkwatch_work); - else - schedule_delayed_work(&linkwatch_work, delay); + if (delay > HZ) + delay = 0; + schedule_delayed_work(&linkwatch_work, delay); } } } diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 3c58846fcaa..b3c559b9ac3 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -50,9 +50,10 @@ static atomic_t trapped; static void zap_completion_queue(void); static void arp_reply(struct sk_buff *skb); -static void queue_process(void *p) +static void queue_process(struct work_struct *work) { - struct netpoll_info *npinfo = p; + struct netpoll_info *npinfo = + container_of(work, struct netpoll_info, tx_work.work); struct sk_buff *skb; while ((skb = skb_dequeue(&npinfo->txq))) { @@ -72,8 +73,6 @@ static void queue_process(void *p) schedule_delayed_work(&npinfo->tx_work, HZ/10); return; } - - netif_tx_unlock_bh(dev); } } @@ -263,7 +262,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) if (status != NETDEV_TX_OK) { skb_queue_tail(&npinfo->txq, skb); - schedule_work(&npinfo->tx_work); + schedule_delayed_work(&npinfo->tx_work,0); } } @@ -628,7 +627,7 @@ int netpoll_setup(struct netpoll *np) spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); skb_queue_head_init(&npinfo->txq); - INIT_WORK(&npinfo->tx_work, queue_process, npinfo); + INIT_DELAYED_WORK(&npinfo->tx_work, queue_process); atomic_set(&npinfo->refcnt, 1); } else { diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 7b52f2a03ee..4c9e26775f7 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -32,8 +32,7 @@ struct inet_timewait_death_row dccp_death_row = { .tw_timer = TIMER_INITIALIZER(inet_twdr_hangman, 0, (unsigned long)&dccp_death_row), .twkill_work = __WORK_INITIALIZER(dccp_death_row.twkill_work, - inet_twdr_twkill_work, - &dccp_death_row), + inet_twdr_twkill_work), /* Short-time timewait calendar */ .twcal_hand = -1, diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index 614aa8d3298..eec1a1dd91d 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -58,9 +58,11 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft } void -ieee80211softmac_assoc_timeout(void *d) +ieee80211softmac_assoc_timeout(struct work_struct *work) { - struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d; + struct ieee80211softmac_device *mac = + container_of(work, struct ieee80211softmac_device, + associnfo.timeout.work); struct ieee80211softmac_network *n; mutex_lock(&mac->associnfo.mutex); @@ -186,9 +188,11 @@ ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void /* This function is called to handle userspace requests (asynchronously) */ void -ieee80211softmac_assoc_work(void *d) +ieee80211softmac_assoc_work(struct work_struct *work) { - struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d; + struct ieee80211softmac_device *mac = + container_of(work, struct ieee80211softmac_device, + associnfo.work.work); struct ieee80211softmac_network *found = NULL; struct ieee80211_network *net = NULL, *best = NULL; int bssvalid; @@ -412,7 +416,7 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev, network->authenticated = 0; /* we don't want to do this more than once ... */ network->auth_desynced_once = 1; - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); break; } default: @@ -476,7 +480,7 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev, dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); return 0; } - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index ec449009c3c..8ed3e59b802 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c @@ -26,7 +26,7 @@ #include "ieee80211softmac_priv.h" -static void ieee80211softmac_auth_queue(void *data); +static void ieee80211softmac_auth_queue(struct work_struct *work); /* Queues an auth request to the desired AP */ int @@ -54,14 +54,14 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, auth->mac = mac; auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT; auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST; - INIT_WORK(&auth->work, &ieee80211softmac_auth_queue, (void *)auth); + INIT_DELAYED_WORK(&auth->work, ieee80211softmac_auth_queue); /* Lock (for list) */ spin_lock_irqsave(&mac->lock, flags); /* add to list */ list_add_tail(&auth->list, &mac->auth_queue); - schedule_work(&auth->work); + schedule_delayed_work(&auth->work, 0); spin_unlock_irqrestore(&mac->lock, flags); return 0; @@ -70,14 +70,15 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, /* Sends an auth request to the desired AP and handles timeouts */ static void -ieee80211softmac_auth_queue(void *data) +ieee80211softmac_auth_queue(struct work_struct *work) { struct ieee80211softmac_device *mac; struct ieee80211softmac_auth_queue_item *auth; struct ieee80211softmac_network *net; unsigned long flags; - auth = (struct ieee80211softmac_auth_queue_item *)data; + auth = container_of(work, struct ieee80211softmac_auth_queue_item, + work.work); net = auth->net; mac = auth->mac; @@ -118,9 +119,11 @@ ieee80211softmac_auth_queue(void *data) /* Sends a response to an auth challenge (for shared key auth). */ static void -ieee80211softmac_auth_challenge_response(void *_aq) +ieee80211softmac_auth_challenge_response(struct work_struct *work) { - struct ieee80211softmac_auth_queue_item *aq = _aq; + struct ieee80211softmac_auth_queue_item *aq = + container_of(work, struct ieee80211softmac_auth_queue_item, + work.work); /* Send our response */ ieee80211softmac_send_mgt_frame(aq->mac, aq->net, IEEE80211_STYPE_AUTH, aq->state); @@ -234,8 +237,8 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) * we have obviously already sent the initial auth * request. */ cancel_delayed_work(&aq->work); - INIT_WORK(&aq->work, &ieee80211softmac_auth_challenge_response, (void *)aq); - schedule_work(&aq->work); + INIT_DELAYED_WORK(&aq->work, &ieee80211softmac_auth_challenge_response); + schedule_delayed_work(&aq->work, 0); spin_unlock_irqrestore(&mac->lock, flags); return 0; case IEEE80211SOFTMAC_AUTH_SHARED_PASS: @@ -400,6 +403,6 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de ieee80211softmac_deauth_from_net(mac, net); /* let's try to re-associate */ - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c index f34fa2ef666..b9015656cfb 100644 --- a/net/ieee80211/softmac/ieee80211softmac_event.c +++ b/net/ieee80211/softmac/ieee80211softmac_event.c @@ -73,10 +73,12 @@ static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = { static void -ieee80211softmac_notify_callback(void *d) +ieee80211softmac_notify_callback(struct work_struct *work) { - struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d; - kfree(d); + struct ieee80211softmac_event *pevent = + container_of(work, struct ieee80211softmac_event, work.work); + struct ieee80211softmac_event event = *pevent; + kfree(pevent); event.fun(event.mac->dev, event.event_type, event.context); } @@ -99,7 +101,7 @@ ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac, return -ENOMEM; eventptr->event_type = event; - INIT_WORK(&eventptr->work, ieee80211softmac_notify_callback, eventptr); + INIT_DELAYED_WORK(&eventptr->work, ieee80211softmac_notify_callback); eventptr->fun = fun; eventptr->context = context; eventptr->mac = mac; @@ -170,7 +172,7 @@ ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int eve /* User may have subscribed to ANY event, so * we tell them which event triggered it. */ eventptr->event_type = event; - schedule_work(&eventptr->work); + schedule_delayed_work(&eventptr->work, 0); } } } diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c index 33aff4f4a47..256207b71dc 100644 --- a/net/ieee80211/softmac/ieee80211softmac_module.c +++ b/net/ieee80211/softmac/ieee80211softmac_module.c @@ -58,8 +58,8 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv) INIT_LIST_HEAD(&softmac->events); mutex_init(&softmac->associnfo.mutex); - INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac); - INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac); + INIT_DELAYED_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work); + INIT_DELAYED_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout); softmac->start_scan = ieee80211softmac_start_scan_implementation; softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation; softmac->stop_scan = ieee80211softmac_stop_scan_implementation; diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h index 3ae894f0c8f..4c2bba34d32 100644 --- a/net/ieee80211/softmac/ieee80211softmac_priv.h +++ b/net/ieee80211/softmac/ieee80211softmac_priv.h @@ -78,7 +78,7 @@ /* private definitions and prototypes */ /*** prototypes from _scan.c */ -void ieee80211softmac_scan(void *sm); +void ieee80211softmac_scan(struct work_struct *work); /* for internal use if scanning is needed */ int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac); void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac); @@ -149,7 +149,7 @@ int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *au int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth); /*** prototypes from _assoc.c */ -void ieee80211softmac_assoc_work(void *d); +void ieee80211softmac_assoc_work(struct work_struct *work); int ieee80211softmac_handle_assoc_response(struct net_device * dev, struct ieee80211_assoc_response * resp, struct ieee80211_network * network); @@ -157,7 +157,7 @@ int ieee80211softmac_handle_disassoc(struct net_device * dev, struct ieee80211_disassoc * disassoc); int ieee80211softmac_handle_reassoc_req(struct net_device * dev, struct ieee80211_reassoc_request * reassoc); -void ieee80211softmac_assoc_timeout(void *d); +void ieee80211softmac_assoc_timeout(struct work_struct *work); void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason); void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac); @@ -207,7 +207,7 @@ struct ieee80211softmac_auth_queue_item { struct ieee80211softmac_device *mac; /* SoftMAC device */ u8 retry; /* Retry limit */ u8 state; /* Auth State */ - struct work_struct work; /* Work queue */ + struct delayed_work work; /* Work queue */ }; /* scanning information */ @@ -219,7 +219,8 @@ struct ieee80211softmac_scaninfo { stop:1; u8 skip_flags; struct completion finished; - struct work_struct softmac_scan; + struct delayed_work softmac_scan; + struct ieee80211softmac_device *mac; }; /* private event struct */ @@ -227,7 +228,7 @@ struct ieee80211softmac_event { struct list_head list; int event_type; void *event_context; - struct work_struct work; + struct delayed_work work; notify_function_ptr fun; void *context; struct ieee80211softmac_device *mac; diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c index 5507feab32d..0c85d6c24cd 100644 --- a/net/ieee80211/softmac/ieee80211softmac_scan.c +++ b/net/ieee80211/softmac/ieee80211softmac_scan.c @@ -90,12 +90,14 @@ ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm) /* internal scanning implementation follows */ -void ieee80211softmac_scan(void *d) +void ieee80211softmac_scan(struct work_struct *work) { int invalid_channel; u8 current_channel_idx; - struct ieee80211softmac_device *sm = (struct ieee80211softmac_device *)d; - struct ieee80211softmac_scaninfo *si = sm->scaninfo; + struct ieee80211softmac_scaninfo *si = + container_of(work, struct ieee80211softmac_scaninfo, + softmac_scan.work); + struct ieee80211softmac_device *sm = si->mac; unsigned long flags; while (!(si->stop) && (si->current_channel_idx < si->number_channels)) { @@ -146,7 +148,8 @@ static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee802 struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC); if (unlikely(!info)) return NULL; - INIT_WORK(&info->softmac_scan, ieee80211softmac_scan, mac); + INIT_DELAYED_WORK(&info->softmac_scan, ieee80211softmac_scan); + info->mac = mac; init_completion(&info->finished); return info; } @@ -187,7 +190,7 @@ int ieee80211softmac_start_scan_implementation(struct net_device *dev) sm->scaninfo->started = 1; sm->scaninfo->stop = 0; INIT_COMPLETION(sm->scaninfo->finished); - schedule_work(&sm->scaninfo->softmac_scan); + schedule_delayed_work(&sm->scaninfo->softmac_scan, 0); spin_unlock_irqrestore(&sm->lock, flags); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c index 5b7b5b41554..480d72c7a42 100644 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c @@ -122,7 +122,7 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev, sm->associnfo.associating = 1; /* queue lower level code to do work (if necessary) */ - schedule_work(&sm->associnfo.work); + schedule_delayed_work(&sm->associnfo.work, 0); out: mutex_unlock(&sm->associnfo.mutex); @@ -356,7 +356,7 @@ ieee80211softmac_wx_set_wap(struct net_device *net_dev, /* force reassociation */ mac->associnfo.bssvalid = 0; if (mac->associnfo.associated) - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); } else if (is_zero_ether_addr(data->ap_addr.sa_data)) { /* the bssid we have is no longer fixed */ mac->associnfo.bssfixed = 0; @@ -373,7 +373,7 @@ ieee80211softmac_wx_set_wap(struct net_device *net_dev, /* tell the other code that this bssid should be used no matter what */ mac->associnfo.bssfixed = 1; /* queue associate if new bssid or (old one again and not associated) */ - schedule_work(&mac->associnfo.work); + schedule_delayed_work(&mac->associnfo.work, 0); } out: diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index cdd805344c6..8c74f9168b7 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -197,9 +197,10 @@ EXPORT_SYMBOL_GPL(inet_twdr_hangman); extern void twkill_slots_invalid(void); -void inet_twdr_twkill_work(void *data) +void inet_twdr_twkill_work(struct work_struct *work) { - struct inet_timewait_death_row *twdr = data; + struct inet_timewait_death_row *twdr = + container_of(work, struct inet_timewait_death_row, twkill_work); int i; if ((INET_TWDR_TWKILL_SLOTS - 1) > (sizeof(twdr->thread_slots) * 8)) diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index f261616e460..9b933381ebb 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c @@ -221,10 +221,10 @@ static void update_defense_level(void) * Timer for checking the defense */ #define DEFENSE_TIMER_PERIOD 1*HZ -static void defense_work_handler(void *data); -static DECLARE_WORK(defense_work, defense_work_handler, NULL); +static void defense_work_handler(struct work_struct *work); +static DECLARE_DELAYED_WORK(defense_work, defense_work_handler); -static void defense_work_handler(void *data) +static void defense_work_handler(struct work_struct *work) { update_defense_level(); if (atomic_read(&ip_vs_dropentry)) diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 6dddf59c1fb..4a3889dd194 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -45,8 +45,7 @@ struct inet_timewait_death_row tcp_death_row = { .tw_timer = TIMER_INITIALIZER(inet_twdr_hangman, 0, (unsigned long)&tcp_death_row), .twkill_work = __WORK_INITIALIZER(tcp_death_row.twkill_work, - inet_twdr_twkill_work, - &tcp_death_row), + inet_twdr_twkill_work), /* Short-time timewait calendar */ .twcal_hand = -1, diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index d50a02030ad..262bda808d9 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -61,7 +61,7 @@ static void ircomm_tty_flush_buffer(struct tty_struct *tty); static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch); static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout); static void ircomm_tty_hangup(struct tty_struct *tty); -static void ircomm_tty_do_softint(void *private_); +static void ircomm_tty_do_softint(struct work_struct *work); static void ircomm_tty_shutdown(struct ircomm_tty_cb *self); static void ircomm_tty_stop(struct tty_struct *tty); @@ -389,7 +389,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) self->flow = FLOW_STOP; self->line = line; - INIT_WORK(&self->tqueue, ircomm_tty_do_softint, self); + INIT_WORK(&self->tqueue, ircomm_tty_do_softint); self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED; self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED; self->close_delay = 5*HZ/10; @@ -594,15 +594,16 @@ static void ircomm_tty_flush_buffer(struct tty_struct *tty) } /* - * Function ircomm_tty_do_softint (private_) + * Function ircomm_tty_do_softint (work) * * We use this routine to give the write wakeup to the user at at a * safe time (as fast as possible after write have completed). This * can be compared to the Tx interrupt. */ -static void ircomm_tty_do_softint(void *private_) +static void ircomm_tty_do_softint(struct work_struct *work) { - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) private_; + struct ircomm_tty_cb *self = + container_of(work, struct ircomm_tty_cb, tqueue); struct tty_struct *tty; unsigned long flags; struct sk_buff *skb, *ctrl_skb; diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 39471d3b31b..ad0057db0f9 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -61,7 +61,7 @@ #include <net/sctp/sm.h> /* Forward declarations for internal functions. */ -static void sctp_assoc_bh_rcv(struct sctp_association *asoc); +static void sctp_assoc_bh_rcv(struct work_struct *work); /* 1st Level Abstractions. */ @@ -269,9 +269,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a /* Create an input queue. */ sctp_inq_init(&asoc->base.inqueue); - sctp_inq_set_th_handler(&asoc->base.inqueue, - (void (*)(void *))sctp_assoc_bh_rcv, - asoc); + sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_assoc_bh_rcv); /* Create an output queue. */ sctp_outq_init(asoc, &asoc->outqueue); @@ -946,8 +944,11 @@ out: } /* Do delayed input processing. This is scheduled by sctp_rcv(). */ -static void sctp_assoc_bh_rcv(struct sctp_association *asoc) +static void sctp_assoc_bh_rcv(struct work_struct *work) { + struct sctp_association *asoc = + container_of(work, struct sctp_association, + base.inqueue.immediate); struct sctp_endpoint *ep; struct sctp_chunk *chunk; struct sock *sk; diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 33a42e90c32..129756908da 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -61,7 +61,7 @@ #include <net/sctp/sm.h> /* Forward declarations for internal helpers. */ -static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep); +static void sctp_endpoint_bh_rcv(struct work_struct *work); /* * Initialize the base fields of the endpoint structure. @@ -89,8 +89,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, sctp_inq_init(&ep->base.inqueue); /* Set its top-half handler */ - sctp_inq_set_th_handler(&ep->base.inqueue, - (void (*)(void *))sctp_endpoint_bh_rcv, ep); + sctp_inq_set_th_handler(&ep->base.inqueue, sctp_endpoint_bh_rcv); /* Initialize the bind addr area */ sctp_bind_addr_init(&ep->base.bind_addr, 0); @@ -318,8 +317,11 @@ int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep, /* Do delayed input processing. This is scheduled by sctp_rcv(). * This may be called on BH or task time. */ -static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep) +static void sctp_endpoint_bh_rcv(struct work_struct *work) { + struct sctp_endpoint *ep = + container_of(work, struct sctp_endpoint, + base.inqueue.immediate); struct sctp_association *asoc; struct sock *sk; struct sctp_transport *transport; diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index cf6deed7e84..71b07466e88 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -54,7 +54,7 @@ void sctp_inq_init(struct sctp_inq *queue) queue->in_progress = NULL; /* Create a task for delivering data. */ - INIT_WORK(&queue->immediate, NULL, NULL); + INIT_WORK(&queue->immediate, NULL); queue->malloced = 0; } @@ -97,7 +97,7 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk) * on the BH related data structures. */ list_add_tail(&chunk->list, &q->in_chunk_list); - q->immediate.func(q->immediate.data); + q->immediate.func(&q->immediate); } /* Extract a chunk from an SCTP inqueue. @@ -205,9 +205,8 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) * The intent is that this routine will pull stuff out of the * inqueue and process it. */ -void sctp_inq_set_th_handler(struct sctp_inq *q, - void (*callback)(void *), void *arg) +void sctp_inq_set_th_handler(struct sctp_inq *q, work_func_t callback) { - INIT_WORK(&q->immediate, callback, arg); + INIT_WORK(&q->immediate, callback); } diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 00cb388ece0..d96fd466a9a 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -284,8 +284,8 @@ static struct file_operations cache_file_operations; static struct file_operations content_file_operations; static struct file_operations cache_flush_operations; -static void do_cache_clean(void *data); -static DECLARE_WORK(cache_cleaner, do_cache_clean, NULL); +static void do_cache_clean(struct work_struct *work); +static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean); void cache_register(struct cache_detail *cd) { @@ -337,7 +337,7 @@ void cache_register(struct cache_detail *cd) spin_unlock(&cache_list_lock); /* start the cleaning process */ - schedule_work(&cache_cleaner); + schedule_delayed_work(&cache_cleaner, 0); } int cache_unregister(struct cache_detail *cd) @@ -461,7 +461,7 @@ static int cache_clean(void) /* * We want to regularly clean the cache, so we need to schedule some work ... */ -static void do_cache_clean(void *data) +static void do_cache_clean(struct work_struct *work) { int delay = 5; if (cache_clean() == -1) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 9a0b41a97f9..49dba5febbb 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -54,10 +54,11 @@ static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, } static void -rpc_timeout_upcall_queue(void *data) +rpc_timeout_upcall_queue(struct work_struct *work) { LIST_HEAD(free_list); - struct rpc_inode *rpci = (struct rpc_inode *)data; + struct rpc_inode *rpci = + container_of(work, struct rpc_inode, queue_timeout.work); struct inode *inode = &rpci->vfs_inode; void (*destroy_msg)(struct rpc_pipe_msg *); @@ -837,7 +838,8 @@ init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) INIT_LIST_HEAD(&rpci->pipe); rpci->pipelen = 0; init_waitqueue_head(&rpci->waitq); - INIT_WORK(&rpci->queue_timeout, rpc_timeout_upcall_queue, rpci); + INIT_DELAYED_WORK(&rpci->queue_timeout, + rpc_timeout_upcall_queue); rpci->ops = NULL; } } diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index a1ab4eed41f..eff44bcdc95 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -41,7 +41,7 @@ static mempool_t *rpc_buffer_mempool __read_mostly; static void __rpc_default_timer(struct rpc_task *task); static void rpciod_killall(void); -static void rpc_async_schedule(void *); +static void rpc_async_schedule(struct work_struct *); /* * RPC tasks sit here while waiting for conditions to improve. @@ -305,7 +305,7 @@ static void rpc_make_runnable(struct rpc_task *task) if (RPC_IS_ASYNC(task)) { int status; - INIT_WORK(&task->u.tk_work, rpc_async_schedule, (void *)task); + INIT_WORK(&task->u.tk_work, rpc_async_schedule); status = queue_work(task->tk_workqueue, &task->u.tk_work); if (status < 0) { printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); @@ -695,9 +695,9 @@ rpc_execute(struct rpc_task *task) return __rpc_execute(task); } -static void rpc_async_schedule(void *arg) +static void rpc_async_schedule(struct work_struct *work) { - __rpc_execute((struct rpc_task *)arg); + __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); } /** diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 80857470dc1..4f9a5d9791f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -479,9 +479,10 @@ int xprt_adjust_timeout(struct rpc_rqst *req) return status; } -static void xprt_autoclose(void *args) +static void xprt_autoclose(struct work_struct *work) { - struct rpc_xprt *xprt = (struct rpc_xprt *)args; + struct rpc_xprt *xprt = + container_of(work, struct rpc_xprt, task_cleanup); xprt_disconnect(xprt); xprt->ops->close(xprt); @@ -932,7 +933,7 @@ struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t si INIT_LIST_HEAD(&xprt->free); INIT_LIST_HEAD(&xprt->recv); - INIT_WORK(&xprt->task_cleanup, xprt_autoclose, xprt); + INIT_WORK(&xprt->task_cleanup, xprt_autoclose); init_timer(&xprt->timer); xprt->timer.function = xprt_init_autodisconnect; xprt->timer.data = (unsigned long) xprt; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 757fc91ef25..cfe3c15be94 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1060,13 +1060,14 @@ static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) /** * xs_udp_connect_worker - set up a UDP socket - * @args: RPC transport to connect + * @work: RPC transport to connect * * Invoked by a work queue tasklet. */ -static void xs_udp_connect_worker(void *args) +static void xs_udp_connect_worker(struct work_struct *work) { - struct rpc_xprt *xprt = (struct rpc_xprt *) args; + struct rpc_xprt *xprt = + container_of(work, struct rpc_xprt, connect_worker.work); struct socket *sock = xprt->sock; int err, status = -EIO; @@ -1144,13 +1145,14 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) /** * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint - * @args: RPC transport to connect + * @work: RPC transport to connect * * Invoked by a work queue tasklet. */ -static void xs_tcp_connect_worker(void *args) +static void xs_tcp_connect_worker(struct work_struct *work) { - struct rpc_xprt *xprt = (struct rpc_xprt *)args; + struct rpc_xprt *xprt = + container_of(work, struct rpc_xprt, connect_worker.work); struct socket *sock = xprt->sock; int err, status = -EIO; @@ -1262,7 +1264,7 @@ static void xs_connect(struct rpc_task *task) xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO; } else { dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); - schedule_work(&xprt->connect_worker); + schedule_delayed_work(&xprt->connect_worker, 0); /* flush_scheduled_work can sleep... */ if (!RPC_IS_ASYNC(task)) @@ -1375,7 +1377,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); - INIT_WORK(&xprt->connect_worker, xs_udp_connect_worker, xprt); + INIT_DELAYED_WORK(&xprt->connect_worker, xs_udp_connect_worker); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_UDP_CONN_TO; xprt->reestablish_timeout = XS_UDP_REEST_TO; @@ -1420,7 +1422,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; - INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); + INIT_DELAYED_WORK(&xprt->connect_worker, xs_tcp_connect_worker); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_TCP_CONN_TO; xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 64d3938f74c..f6c77bd36fd 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -392,7 +392,7 @@ static void xfrm_policy_gc_kill(struct xfrm_policy *policy) xfrm_pol_put(policy); } -static void xfrm_policy_gc_task(void *data) +static void xfrm_policy_gc_task(struct work_struct *work) { struct xfrm_policy *policy; struct hlist_node *entry, *tmp; @@ -580,7 +580,7 @@ static inline int xfrm_byidx_should_resize(int total) static DEFINE_MUTEX(hash_resize_mutex); -static void xfrm_hash_resize(void *__unused) +static void xfrm_hash_resize(struct work_struct *__unused) { int dir, total; @@ -597,7 +597,7 @@ static void xfrm_hash_resize(void *__unused) mutex_unlock(&hash_resize_mutex); } -static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL); +static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize); /* Generate new index... KAME seems to generate them ordered by cost * of an absolute inpredictability of ordering of rules. This will not pass. */ @@ -2116,7 +2116,7 @@ static void __init xfrm_policy_init(void) panic("XFRM: failed to allocate bydst hash\n"); } - INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL); + INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); register_netdevice_notifier(&xfrm_dev_notifier); } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 864962bbda9..da54a64ccfa 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -115,7 +115,7 @@ static unsigned long xfrm_hash_new_size(void) static DEFINE_MUTEX(hash_resize_mutex); -static void xfrm_hash_resize(void *__unused) +static void xfrm_hash_resize(struct work_struct *__unused) { struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; unsigned long nsize, osize; @@ -168,7 +168,7 @@ out_unlock: mutex_unlock(&hash_resize_mutex); } -static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL); +static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize); DECLARE_WAIT_QUEUE_HEAD(km_waitq); EXPORT_SYMBOL(km_waitq); @@ -207,7 +207,7 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) kfree(x); } -static void xfrm_state_gc_task(void *data) +static void xfrm_state_gc_task(struct work_struct *data) { struct xfrm_state *x; struct hlist_node *entry, *tmp; @@ -1568,6 +1568,6 @@ void __init xfrm_state_init(void) panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); - INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL); + INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task); } diff --git a/security/keys/key.c b/security/keys/key.c index 80de8c3e9cc..70eacbe5abd 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -30,8 +30,8 @@ DEFINE_SPINLOCK(key_user_lock); static LIST_HEAD(key_types_list); static DECLARE_RWSEM(key_types_sem); -static void key_cleanup(void *data); -static DECLARE_WORK(key_cleanup_task, key_cleanup, NULL); +static void key_cleanup(struct work_struct *work); +static DECLARE_WORK(key_cleanup_task, key_cleanup); /* we serialise key instantiation and link */ DECLARE_RWSEM(key_construction_sem); @@ -552,7 +552,7 @@ EXPORT_SYMBOL(key_negate_and_link); * do cleaning up in process context so that we don't have to disable * interrupts all over the place */ -static void key_cleanup(void *data) +static void key_cleanup(struct work_struct *work) { struct rb_node *_n; struct key *key; diff --git a/sound/aoa/aoa-gpio.h b/sound/aoa/aoa-gpio.h index 3a61f311557..ee64f5de896 100644 --- a/sound/aoa/aoa-gpio.h +++ b/sound/aoa/aoa-gpio.h @@ -59,10 +59,10 @@ struct gpio_methods { }; struct gpio_notification { + struct delayed_work work; notify_func_t notify; void *data; void *gpio_private; - struct work_struct work; struct mutex mutex; }; diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c index 40eb47eccf9..2b03bc798bc 100644 --- a/sound/aoa/core/snd-aoa-gpio-feature.c +++ b/sound/aoa/core/snd-aoa-gpio-feature.c @@ -195,9 +195,10 @@ static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt) ftr_gpio_set_lineout(rt, (s>>2)&1); } -static void ftr_handle_notify(void *data) +static void ftr_handle_notify(struct work_struct *work) { - struct gpio_notification *notif = data; + struct gpio_notification *notif = + container_of(work, struct gpio_notification, work.work); mutex_lock(¬if->mutex); if (notif->notify) @@ -253,12 +254,9 @@ static void ftr_gpio_init(struct gpio_runtime *rt) ftr_gpio_all_amps_off(rt); rt->implementation_private = 0; - INIT_WORK(&rt->headphone_notify.work, ftr_handle_notify, - &rt->headphone_notify); - INIT_WORK(&rt->line_in_notify.work, ftr_handle_notify, - &rt->line_in_notify); - INIT_WORK(&rt->line_out_notify.work, ftr_handle_notify, - &rt->line_out_notify); + INIT_DELAYED_WORK(&rt->headphone_notify.work, ftr_handle_notify); + INIT_DELAYED_WORK(&rt->line_in_notify.work, ftr_handle_notify); + INIT_DELAYED_WORK(&rt->line_out_notify.work, ftr_handle_notify); mutex_init(&rt->headphone_notify.mutex); mutex_init(&rt->line_in_notify.mutex); mutex_init(&rt->line_out_notify.mutex); @@ -287,7 +285,7 @@ static irqreturn_t ftr_handle_notify_irq(int xx, void *data) { struct gpio_notification *notif = data; - schedule_work(¬if->work); + schedule_delayed_work(¬if->work, 0); return IRQ_HANDLED; } diff --git a/sound/aoa/core/snd-aoa-gpio-pmf.c b/sound/aoa/core/snd-aoa-gpio-pmf.c index 2836c321839..5ca2220eac7 100644 --- a/sound/aoa/core/snd-aoa-gpio-pmf.c +++ b/sound/aoa/core/snd-aoa-gpio-pmf.c @@ -69,9 +69,10 @@ static void pmf_gpio_all_amps_restore(struct gpio_runtime *rt) pmf_gpio_set_lineout(rt, (s>>2)&1); } -static void pmf_handle_notify(void *data) +static void pmf_handle_notify(struct work_struct *work) { - struct gpio_notification *notif = data; + struct gpio_notification *notif = + container_of(work, struct gpio_notification, work.work); mutex_lock(¬if->mutex); if (notif->notify) @@ -83,12 +84,9 @@ static void pmf_gpio_init(struct gpio_runtime *rt) { pmf_gpio_all_amps_off(rt); rt->implementation_private = 0; - INIT_WORK(&rt->headphone_notify.work, pmf_handle_notify, - &rt->headphone_notify); - INIT_WORK(&rt->line_in_notify.work, pmf_handle_notify, - &rt->line_in_notify); - INIT_WORK(&rt->line_out_notify.work, pmf_handle_notify, - &rt->line_out_notify); + INIT_DELAYED_WORK(&rt->headphone_notify.work, pmf_handle_notify); + INIT_DELAYED_WORK(&rt->line_in_notify.work, pmf_handle_notify); + INIT_DELAYED_WORK(&rt->line_out_notify.work, pmf_handle_notify); mutex_init(&rt->headphone_notify.mutex); mutex_init(&rt->line_in_notify.mutex); mutex_init(&rt->line_out_notify.mutex); @@ -129,7 +127,7 @@ static void pmf_handle_notify_irq(void *data) { struct gpio_notification *notif = data; - schedule_work(¬if->work); + schedule_delayed_work(¬if->work, 0); } static int pmf_set_notify(struct gpio_runtime *rt, diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 12ffffc9e81..d2f2c5078e6 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -35,7 +35,7 @@ MODULE_LICENSE("GPL"); #define AK4114_ADDR 0x00 /* fixed address */ -static void ak4114_stats(void *); +static void ak4114_stats(struct work_struct *work); static void reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char val) { @@ -158,7 +158,7 @@ void snd_ak4114_reinit(struct ak4114 *chip) reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN); /* bring up statistics / event queing */ chip->init = 0; - INIT_WORK(&chip->work, ak4114_stats, chip); + INIT_DELAYED_WORK(&chip->work, ak4114_stats); queue_delayed_work(chip->workqueue, &chip->work, HZ / 10); } @@ -561,9 +561,9 @@ int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags) return res; } -static void ak4114_stats(void *data) +static void ak4114_stats(struct work_struct *work) { - struct ak4114 *chip = (struct ak4114 *)data; + struct ak4114 *chip = container_of(work, struct ak4114, work.work); if (chip->init) return; diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 6577b232535..7abcb10b275 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1927,9 +1927,10 @@ static int snd_ac97_dev_disconnect(struct snd_device *device) static struct snd_ac97_build_ops null_build_ops; #ifdef CONFIG_SND_AC97_POWER_SAVE -static void do_update_power(void *data) +static void do_update_power(struct work_struct *work) { - update_power_regs(data); + update_power_regs( + container_of(work, struct snd_ac97, power_work.work)); } #endif @@ -1989,7 +1990,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, mutex_init(&ac97->page_mutex); #ifdef CONFIG_SND_AC97_POWER_SAVE ac97->power_workq = create_workqueue("ac97"); - INIT_WORK(&ac97->power_work, do_update_power, ac97); + INIT_DELAYED_WORK(&ac97->power_work, do_update_power); #endif #ifdef CONFIG_PCI diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9c3d7ac0806..71482c15a85 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -272,10 +272,11 @@ EXPORT_SYMBOL(snd_hda_queue_unsol_event); /* * process queueud unsolicited events */ -static void process_unsol_events(void *data) +static void process_unsol_events(struct work_struct *work) { - struct hda_bus *bus = data; - struct hda_bus_unsolicited *unsol = bus->unsol; + struct hda_bus_unsolicited *unsol = + container_of(work, struct hda_bus_unsolicited, work); + struct hda_bus *bus = unsol->bus; struct hda_codec *codec; unsigned int rp, caddr, res; @@ -314,7 +315,8 @@ static int init_unsol_queue(struct hda_bus *bus) kfree(unsol); return -ENOMEM; } - INIT_WORK(&unsol->work, process_unsol_events, bus); + INIT_WORK(&unsol->work, process_unsol_events); + unsol->bus = bus; bus->unsol = unsol; return 0; } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index f9416c36396..9ca1baf860b 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -206,6 +206,7 @@ struct hda_bus_unsolicited { /* workqueue */ struct workqueue_struct *workq; struct work_struct work; + struct hda_bus *bus; }; /* diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index fd3590fcaed..2d40cc72f23 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -219,35 +219,15 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int pdacf_config(struct pcmcia_device *link) { struct snd_pdacf *pdacf = link->priv; - tuple_t tuple; - cisparse_t *parse = NULL; - u_short buf[32]; int last_fn, last_ret; snd_printdd(KERN_DEBUG "pdacf_config called\n"); - parse = kmalloc(sizeof(*parse), GFP_KERNEL); - if (! parse) { - snd_printk(KERN_ERR "pdacf_config: cannot allocate\n"); - return -ENOMEM; - } - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - tuple.Attributes = 0; - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, parse)); - link->conf.ConfigBase = parse->config.base; link->conf.ConfigIndex = 0x5; CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); - kfree(parse); - if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0) goto failed; @@ -255,7 +235,6 @@ static int pdacf_config(struct pcmcia_device *link) return 0; cs_failed: - kfree(parse); cs_error(link, last_fn, last_ret); failed: pcmcia_disable_device(link); @@ -299,7 +278,8 @@ static int pdacf_resume(struct pcmcia_device *link) * Module entry points */ static struct pcmcia_device_id snd_pdacf_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45), + /* this is too general PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45), */ + PCMCIA_DEVICE_PROD_ID12("Core Sound","PDAudio-CF",0x396d19d2,0x71717b49), PCMCIA_DEVICE_NULL }; MODULE_DEVICE_TABLE(pcmcia, snd_pdacf_ids); diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 3089fcca800..d7df59e9c64 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -217,34 +217,12 @@ static int vxpocket_config(struct pcmcia_device *link) { struct vx_core *chip = link->priv; struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; - tuple_t tuple; - cisparse_t *parse; - u_short buf[32]; int last_fn, last_ret; snd_printdd(KERN_DEBUG "vxpocket_config called\n"); - parse = kmalloc(sizeof(*parse), GFP_KERNEL); - if (! parse) { - snd_printk(KERN_ERR "vx: cannot allocate\n"); - return -ENOMEM; - } - tuple.Attributes = 0; - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, parse)); - link->conf.ConfigBase = parse->config.base; - link->conf.Present = parse->config.rmask[0]; /* redefine hardware record according to the VERSION1 string */ - tuple.DesiredTuple = CISTPL_VERS_1; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, parse)); - if (! strcmp(parse->version_1.str + parse->version_1.ofs[1], "VX-POCKET")) { + if (!strcmp(link->prod_id[1], "VX-POCKET")) { snd_printdd("VX-pocket is detected\n"); } else { snd_printdd("VX-pocket 440 is detected\n"); @@ -265,14 +243,12 @@ static int vxpocket_config(struct pcmcia_device *link) goto failed; link->dev_node = &vxp->node; - kfree(parse); return 0; cs_failed: cs_error(link, last_fn, last_ret); failed: pcmcia_disable_device(link); - kfree(parse); return -ENODEV; } diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 2fbe1d183fc..8f074c7936e 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -942,10 +942,11 @@ static void check_mute(struct snd_pmac *chip, struct pmac_gpio *gp, int val, int } static struct work_struct device_change; +static struct snd_pmac *device_change_chip; -static void device_change_handler(void *self) +static void device_change_handler(struct work_struct *work) { - struct snd_pmac *chip = self; + struct snd_pmac *chip = device_change_chip; struct pmac_tumbler *mix; int headphone, lineout; @@ -1417,7 +1418,8 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip) chip->resume = tumbler_resume; #endif - INIT_WORK(&device_change, device_change_handler, (void *)chip); + INIT_WORK(&device_change, device_change_handler); + device_change_chip = chip; #ifdef PMAC_SUPPORT_AUTOMUTE if ((mix->headphone_irq >=0 || mix->lineout_irq >= 0) |