diff options
Diffstat (limited to 'drivers')
1269 files changed, 19392 insertions, 10932 deletions
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index e1141402dbed..f4f523bf5939 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -41,6 +41,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index c57b5c707a77..20516e599476 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -41,6 +41,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "actables.h" diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 52aaff3df562..f06a3ee356ba 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -41,6 +41,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acevents.h" diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 00cd95692a91..aee887e3ca5c 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -42,6 +42,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 55accb7018bb..cc70f3fdcdd1 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -269,16 +269,17 @@ acpi_status acpi_hw_clear_acpi_status(void) status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, ACPI_BITMASK_ALL_FIXED_STATUS); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } + + acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); + + if (ACPI_FAILURE(status)) + goto exit; /* Clear the GPE Bits in all GPE registers in all GPE blocks */ status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); - unlock_and_exit: - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); +exit: return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 2ac28bbe8827..d52da3073650 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -46,6 +46,7 @@ #include "accommon.h" #include "actables.h" #include <linux/tboot.h> +#include <linux/module.h> #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwsleep") diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 9c8eb71a12fb..50d21c40b5c1 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -42,6 +42,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index f75f81ad15c9..c2793a82f120 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -42,6 +42,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index c53f0040e490..e7f016d1b226 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -42,6 +42,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 3fd4526f3dba..83bf93024303 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -42,6 +42,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index db7660f8b869..57e6d825ed84 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -42,6 +42,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 2ff657a28f26..fe86b37b16ce 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -41,6 +41,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acresrc.h" diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 4b7085dfc683..e7d13f5d3f2d 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -42,6 +42,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index a9bcd816dc29..a1f8d7509e66 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -41,6 +41,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 97cb36f85ce9..8b087e2d64f4 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -41,6 +41,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 833a38a9c905..ffba0a39c3e8 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -43,6 +43,7 @@ #define DEFINE_ACPI_GLOBALS +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 98ad125e14ff..420ebfe08c72 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -41,6 +41,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acevents.h" diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 916ae097c43c..8d0245ec4315 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -41,6 +41,7 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c index 7489b89c300f..cfc0cc10af39 100644 --- a/drivers/acpi/atomicio.c +++ b/drivers/acpi/atomicio.c @@ -24,7 +24,7 @@ */ #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/export.h> #include <linux/init.h> #include <linux/acpi.h> #include <linux/io.h> @@ -76,7 +76,7 @@ static void __iomem *__acpi_ioremap_fast(phys_addr_t paddr, { struct acpi_iomap *map; - map = __acpi_find_iomap(paddr, size); + map = __acpi_find_iomap(paddr, size/8); if (map) return map->vaddr + (paddr - map->paddr); else diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index af308d03f492..cb9629638def 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -28,7 +28,6 @@ */ #include <linux/kernel.h> -#include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> #include <acpi/acpi_bus.h> diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 437ddbf0c49a..9ecec98bc76e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -911,10 +911,7 @@ void __init acpi_early_init(void) } #endif - status = - acpi_enable_subsystem(~ - (ACPI_NO_HARDWARE_INIT | - ACPI_NO_ACPI_ENABLE)); + status = acpi_enable_subsystem(~ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to enable ACPI\n"); goto error0; @@ -935,8 +932,7 @@ static int __init acpi_bus_init(void) acpi_os_initialize1(); - status = - acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE); + status = acpi_enable_subsystem(ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n"); diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c index 182a9fc36355..b55d6a20dc0e 100644 --- a/drivers/acpi/debugfs.c +++ b/drivers/acpi/debugfs.c @@ -2,6 +2,7 @@ * debugfs.c - ACPI debugfs interface to userspace. */ +#include <linux/export.h> #include <linux/init.h> #include <linux/debugfs.h> #include <acpi/acpi_drivers.h> diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 22f918bacd35..6c47ae9793a7 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/acpi.h> #include <linux/debugfs.h> +#include <linux/module.h> #include "internal.h" MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>"); diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 85d908993809..1442737cedec 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -7,6 +7,7 @@ */ #include <linux/spinlock.h> +#include <linux/export.h> #include <linux/proc_fs.h> #include <linux/init.h> #include <linux/poll.h> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 7c47ed55e528..29a4a5c8ee00 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -6,6 +6,7 @@ * * This file is released under the GPLv2. */ +#include <linux/export.h> #include <linux/init.h> #include <linux/list.h> #include <linux/device.h> diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index f5f986991b52..251c7b6273a9 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -1,5 +1,6 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/export.h> #include <linux/suspend.h> #include <linux/bcd.h> #include <asm/uaccess.h> diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 02d2a4c9084d..3a0428e8435c 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -7,6 +7,7 @@ * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> * - Added _PDC for platforms with Intel CPUs */ +#include <linux/export.h> #include <linux/dmi.h> #include <linux/slab.h> diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index a4e0f1ba6040..9d7bc9f6b6cc 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -426,7 +426,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, if (action == CPU_ONLINE && pr) { acpi_processor_ppc_has_changed(pr, 0); - acpi_processor_cst_has_changed(pr); + acpi_processor_hotplug(pr); acpi_processor_reevaluate_tstate(pr, action); acpi_processor_tstate_has_changed(pr); } @@ -503,8 +503,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) acpi_processor_get_throttling_info(pr); acpi_processor_get_limit_info(pr); - - if (cpuidle_get_driver() == &acpi_idle_driver) + if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) acpi_processor_power_init(pr, device); pr->cdev = thermal_cooling_device_register("Processor", device, @@ -800,17 +799,9 @@ static int __init acpi_processor_init(void) memset(&errata, 0, sizeof(errata)); - if (!cpuidle_register_driver(&acpi_idle_driver)) { - printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n", - acpi_idle_driver.name); - } else { - printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s\n", - cpuidle_get_driver()->name); - } - result = acpi_bus_register_driver(&acpi_processor_driver); if (result < 0) - goto out_cpuidle; + return result; acpi_processor_install_hotplug_notify(); @@ -821,11 +812,6 @@ static int __init acpi_processor_init(void) acpi_processor_throttling_init(); return 0; - -out_cpuidle: - cpuidle_unregister_driver(&acpi_idle_driver); - - return result; } static void __exit acpi_processor_exit(void) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 9b88f9828d8c..73b2909dddfe 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -741,22 +741,25 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) /** * acpi_idle_enter_c1 - enters an ACPI C1 state-type * @dev: the target CPU - * @state: the state data + * @drv: cpuidle driver containing cpuidle state info + * @index: index of target state * * This is equivalent to the HALT instruction. */ static int acpi_idle_enter_c1(struct cpuidle_device *dev, - struct cpuidle_state *state) + struct cpuidle_driver *drv, int index) { ktime_t kt1, kt2; s64 idle_time; struct acpi_processor *pr; - struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); pr = __this_cpu_read(processors); + dev->last_residency = 0; if (unlikely(!pr)) - return 0; + return -EINVAL; local_irq_disable(); @@ -764,7 +767,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, if (acpi_idle_suspend) { local_irq_enable(); cpu_relax(); - return 0; + return -EINVAL; } lapic_timer_state_broadcast(pr, cx, 1); @@ -773,37 +776,47 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, kt2 = ktime_get_real(); idle_time = ktime_to_us(ktime_sub(kt2, kt1)); + /* Update device last_residency*/ + dev->last_residency = (int)idle_time; + local_irq_enable(); cx->usage++; lapic_timer_state_broadcast(pr, cx, 0); - return idle_time; + return index; } /** * acpi_idle_enter_simple - enters an ACPI state without BM handling * @dev: the target CPU - * @state: the state data + * @drv: cpuidle driver with cpuidle state information + * @index: the index of suggested state */ static int acpi_idle_enter_simple(struct cpuidle_device *dev, - struct cpuidle_state *state) + struct cpuidle_driver *drv, int index) { struct acpi_processor *pr; - struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; pr = __this_cpu_read(processors); + dev->last_residency = 0; if (unlikely(!pr)) - return 0; - - if (acpi_idle_suspend) - return(acpi_idle_enter_c1(dev, state)); + return -EINVAL; local_irq_disable(); + if (acpi_idle_suspend) { + local_irq_enable(); + cpu_relax(); + return -EINVAL; + } + + if (cx->entry_method != ACPI_CSTATE_FFH) { current_thread_info()->status &= ~TS_POLLING; /* @@ -815,7 +828,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; local_irq_enable(); - return 0; + return -EINVAL; } } @@ -837,6 +850,9 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); + /* Update device last_residency*/ + dev->last_residency = (int)idle_time; + /* Tell the scheduler how much we idled: */ sched_clock_idle_wakeup_event(idle_time_ns); @@ -848,7 +864,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, lapic_timer_state_broadcast(pr, cx, 0); cx->time += idle_time; - return idle_time; + return index; } static int c3_cpu_count; @@ -857,37 +873,43 @@ static DEFINE_RAW_SPINLOCK(c3_lock); /** * acpi_idle_enter_bm - enters C3 with proper BM handling * @dev: the target CPU - * @state: the state data + * @drv: cpuidle driver containing state data + * @index: the index of suggested state * * If BM is detected, the deepest non-C3 idle state is entered instead. */ static int acpi_idle_enter_bm(struct cpuidle_device *dev, - struct cpuidle_state *state) + struct cpuidle_driver *drv, int index) { struct acpi_processor *pr; - struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; pr = __this_cpu_read(processors); + dev->last_residency = 0; if (unlikely(!pr)) - return 0; + return -EINVAL; + - if (acpi_idle_suspend) - return(acpi_idle_enter_c1(dev, state)); + if (acpi_idle_suspend) { + cpu_relax(); + return -EINVAL; + } if (!cx->bm_sts_skip && acpi_idle_bm_check()) { - if (dev->safe_state) { - dev->last_state = dev->safe_state; - return dev->safe_state->enter(dev, dev->safe_state); + if (drv->safe_state_index >= 0) { + return drv->states[drv->safe_state_index].enter(dev, + drv, drv->safe_state_index); } else { local_irq_disable(); acpi_safe_halt(); local_irq_enable(); - return 0; + return -EINVAL; } } @@ -904,7 +926,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; local_irq_enable(); - return 0; + return -EINVAL; } } @@ -954,6 +976,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); + /* Update device last_residency*/ + dev->last_residency = (int)idle_time; + /* Tell the scheduler how much we idled: */ sched_clock_idle_wakeup_event(idle_time_ns); @@ -965,7 +990,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, lapic_timer_state_broadcast(pr, cx, 0); cx->time += idle_time; - return idle_time; + return index; } struct cpuidle_driver acpi_idle_driver = { @@ -974,14 +999,16 @@ struct cpuidle_driver acpi_idle_driver = { }; /** - * acpi_processor_setup_cpuidle - prepares and configures CPUIDLE + * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE + * device i.e. per-cpu data + * * @pr: the ACPI processor */ -static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) +static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr) { int i, count = CPUIDLE_DRIVER_STATE_START; struct acpi_processor_cx *cx; - struct cpuidle_state *state; + struct cpuidle_state_usage *state_usage; struct cpuidle_device *dev = &pr->power.dev; if (!pr->flags.power_setup_done) @@ -992,9 +1019,62 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) } dev->cpu = pr->id; + + if (max_cstate == 0) + max_cstate = 1; + + for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { + cx = &pr->power.states[i]; + state_usage = &dev->states_usage[count]; + + if (!cx->valid) + continue; + +#ifdef CONFIG_HOTPLUG_CPU + if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && + !pr->flags.has_cst && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + continue; +#endif + + cpuidle_set_statedata(state_usage, cx); + + count++; + if (count == CPUIDLE_STATE_MAX) + break; + } + + dev->state_count = count; + + if (!count) + return -EINVAL; + + return 0; +} + +/** + * acpi_processor_setup_cpuidle states- prepares and configures cpuidle + * global state data i.e. idle routines + * + * @pr: the ACPI processor + */ +static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) +{ + int i, count = CPUIDLE_DRIVER_STATE_START; + struct acpi_processor_cx *cx; + struct cpuidle_state *state; + struct cpuidle_driver *drv = &acpi_idle_driver; + + if (!pr->flags.power_setup_done) + return -EINVAL; + + if (pr->flags.power == 0) + return -EINVAL; + + drv->safe_state_index = -1; for (i = 0; i < CPUIDLE_STATE_MAX; i++) { - dev->states[i].name[0] = '\0'; - dev->states[i].desc[0] = '\0'; + drv->states[i].name[0] = '\0'; + drv->states[i].desc[0] = '\0'; } if (max_cstate == 0) @@ -1002,7 +1082,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { cx = &pr->power.states[i]; - state = &dev->states[count]; if (!cx->valid) continue; @@ -1013,8 +1092,8 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) continue; #endif - cpuidle_set_statedata(state, cx); + state = &drv->states[count]; snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); state->exit_latency = cx->latency; @@ -1027,13 +1106,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_c1; - dev->safe_state = state; + drv->safe_state_index = count; break; case ACPI_STATE_C2: state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_simple; - dev->safe_state = state; + drv->safe_state_index = count; break; case ACPI_STATE_C3: @@ -1049,7 +1128,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) break; } - dev->state_count = count; + drv->state_count = count; if (!count) return -EINVAL; @@ -1057,7 +1136,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) return 0; } -int acpi_processor_cst_has_changed(struct acpi_processor *pr) +int acpi_processor_hotplug(struct acpi_processor *pr) { int ret = 0; @@ -1078,7 +1157,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) cpuidle_disable_device(&pr->power.dev); acpi_processor_get_power_info(pr); if (pr->flags.power) { - acpi_processor_setup_cpuidle(pr); + acpi_processor_setup_cpuidle_cx(pr); ret = cpuidle_enable_device(&pr->power.dev); } cpuidle_resume_and_unlock(); @@ -1086,10 +1165,72 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) return ret; } +int acpi_processor_cst_has_changed(struct acpi_processor *pr) +{ + int cpu; + struct acpi_processor *_pr; + + if (disabled_by_idle_boot_param()) + return 0; + + if (!pr) + return -EINVAL; + + if (nocst) + return -ENODEV; + + if (!pr->flags.power_setup_done) + return -ENODEV; + + /* + * FIXME: Design the ACPI notification to make it once per + * system instead of once per-cpu. This condition is a hack + * to make the code that updates C-States be called once. + */ + + if (smp_processor_id() == 0 && + cpuidle_get_driver() == &acpi_idle_driver) { + + cpuidle_pause_and_lock(); + /* Protect against cpu-hotplug */ + get_online_cpus(); + + /* Disable all cpuidle devices */ + for_each_online_cpu(cpu) { + _pr = per_cpu(processors, cpu); + if (!_pr || !_pr->flags.power_setup_done) + continue; + cpuidle_disable_device(&_pr->power.dev); + } + + /* Populate Updated C-state information */ + acpi_processor_setup_cpuidle_states(pr); + + /* Enable all cpuidle devices */ + for_each_online_cpu(cpu) { + _pr = per_cpu(processors, cpu); + if (!_pr || !_pr->flags.power_setup_done) + continue; + acpi_processor_get_power_info(_pr); + if (_pr->flags.power) { + acpi_processor_setup_cpuidle_cx(_pr); + cpuidle_enable_device(&_pr->power.dev); + } + } + put_online_cpus(); + cpuidle_resume_and_unlock(); + } + + return 0; +} + +static int acpi_processor_registered; + int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) { acpi_status status = 0; + int retval; static int first_run; if (disabled_by_idle_boot_param()) @@ -1126,9 +1267,26 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, * platforms that only support C1. */ if (pr->flags.power) { - acpi_processor_setup_cpuidle(pr); - if (cpuidle_register_device(&pr->power.dev)) - return -EIO; + /* Register acpi_idle_driver if not already registered */ + if (!acpi_processor_registered) { + acpi_processor_setup_cpuidle_states(pr); + retval = cpuidle_register_driver(&acpi_idle_driver); + if (retval) + return retval; + printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n", + acpi_idle_driver.name); + } + /* Register per-cpu cpuidle_device. Cpuidle driver + * must already be registered before registering device + */ + acpi_processor_setup_cpuidle_cx(pr); + retval = cpuidle_register_device(&pr->power.dev); + if (retval) { + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); + return retval; + } + acpi_processor_registered++; } return 0; } @@ -1139,8 +1297,13 @@ int acpi_processor_power_exit(struct acpi_processor *pr, if (disabled_by_idle_boot_param()) return 0; - cpuidle_unregister_device(&pr->power.dev); - pr->flags.power_setup_done = 0; + if (pr->flags.power) { + cpuidle_unregister_device(&pr->power.dev); + acpi_processor_registered--; + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); + } + pr->flags.power_setup_done = 0; return 0; } diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index f8be23b6c129..f8d2a472795c 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -13,6 +13,7 @@ #include <linux/wait.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/interrupt.h> #include "sbshc.h" diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 449c556274c0..8ab80bafe3f1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1062,13 +1062,12 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id) if (!id) return; - id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL); + id->id = kstrdup(dev_id, GFP_KERNEL); if (!id->id) { kfree(id); return; } - strcpy(id->id, dev_id); list_add_tail(&id->list, &device->pnp.ids); } diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 0e46faef1d30..6d9a3ab58db2 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -398,6 +398,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { }, { .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB17FX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"), + }, + }, + { + .callback = init_nvs_nosave, .ident = "Sony Vaio VGN-SR11M", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index c538d0ef10ff..9f66181c814e 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -706,11 +706,23 @@ static void __exit interrupt_stats_exit(void) return; } +static ssize_t +acpi_show_profile(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile); +} + +static const struct device_attribute pm_profile_attr = + __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); + int __init acpi_sysfs_init(void) { int result; result = acpi_tables_sysfs_init(); - + if (result) + return result; + result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); return result; } diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 5af3479714f6..f3f0fe7e255a 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -33,6 +33,7 @@ * */ +#include <linux/export.h> #include <linux/acpi.h> #include <linux/dmi.h> #include <linux/pci.h> diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index c021186736e9..f22957c2769a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -34,6 +34,7 @@ #include <linux/kernel.h> #include <linux/blkdev.h> +#include <linux/export.h> #include <linux/pci.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 3eb2b816eb2a..104462dbc524 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -8,6 +8,7 @@ */ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/libata.h> #include <linux/slab.h> #include "libata.h" diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 19ba77032ac2..72a9770ac42f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -37,6 +37,7 @@ #include <linux/kernel.h> #include <linux/blkdev.h> #include <linux/spinlock.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 239bfa67d032..63d53277d6a9 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -35,6 +35,7 @@ #include <linux/kernel.h> #include <linux/gfp.h> #include <linux/pci.h> +#include <linux/module.h> #include <linux/libata.h> #include <linux/highmem.h> diff --git a/drivers/base/base.h b/drivers/base/base.h index a34dca0ad041..21c1b96c34c6 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -1,3 +1,4 @@ +#include <linux/notifier.h> /** * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure. diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index f369e2795985..bb0025c510b3 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -4,6 +4,7 @@ */ #include <linux/slab.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/dma-mapping.h> struct dma_coherent_mem { diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index 763d59c1eb65..6f3676f1559f 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -8,6 +8,7 @@ */ #include <linux/dma-mapping.h> +#include <linux/export.h> #include <linux/gfp.h> /* diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c index 6428cba3aadd..4f8b741f4615 100644 --- a/drivers/base/hypervisor.c +++ b/drivers/base/hypervisor.c @@ -10,6 +10,7 @@ #include <linux/kobject.h> #include <linux/device.h> +#include <linux/export.h> #include "base.h" struct kobject *hypervisor_kobj; diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index 29820c396182..4af7c1cbf909 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -8,7 +8,7 @@ #include <linux/init.h> #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/pm_clock.h> diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 9508df71274b..265a0ee3b49e 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -8,6 +8,7 @@ #include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/export.h> #ifdef CONFIG_PM_RUNTIME /** diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 59f8ab235486..7fa098464dae 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -19,6 +19,7 @@ #include <linux/device.h> #include <linux/kallsyms.h> +#include <linux/export.h> #include <linux/mutex.h> #include <linux/pm.h> #include <linux/pm_runtime.h> diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 91e061417382..30a94eadc200 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -39,6 +39,7 @@ #include <linux/slab.h> #include <linux/device.h> #include <linux/mutex.h> +#include <linux/export.h> static DEFINE_MUTEX(dev_pm_qos_mtx); diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 6bb3aafa85ed..8c78443bca8f 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -8,6 +8,7 @@ */ #include <linux/sched.h> +#include <linux/export.h> #include <linux/pm_runtime.h> #include <trace/events/rpm.h> #include "power.h" @@ -29,13 +30,10 @@ static int rpm_suspend(struct device *dev, int rpmflags); void update_pm_runtime_accounting(struct device *dev) { unsigned long now = jiffies; - int delta; + unsigned long delta; delta = now - dev->power.accounting_timestamp; - if (delta < 0) - delta = 0; - dev->power.accounting_timestamp = now; if (dev->power.disable_depth > 0) @@ -296,6 +294,9 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) * the callback was running then carry it out, otherwise send an idle * notification for its parent (if the suspend succeeded and both * ignore_children of parent->power and irq_safe of dev->power are not set). + * If ->runtime_suspend failed with -EAGAIN or -EBUSY, and if the RPM_AUTO + * flag is set and the next autosuspend-delay expiration time is in the + * future, schedule another autosuspend attempt. * * This function must be called under dev->power.lock with interrupts disabled. */ @@ -416,10 +417,21 @@ static int rpm_suspend(struct device *dev, int rpmflags) if (retval) { __update_runtime_status(dev, RPM_ACTIVE); dev->power.deferred_resume = false; - if (retval == -EAGAIN || retval == -EBUSY) + if (retval == -EAGAIN || retval == -EBUSY) { dev->power.runtime_error = 0; - else + + /* + * If the callback routine failed an autosuspend, and + * if the last_busy time has been updated so that there + * is a new autosuspend expiration time, automatically + * reschedule another autosuspend. + */ + if ((rpmflags & RPM_AUTO) && + pm_runtime_autosuspend_expiration(dev) != 0) + goto repeat; + } else { pm_runtime_cancel_pending(dev); + } wake_up_all(&dev->power.wait_queue); goto out; } diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 17b7934f31cb..adf41be0ea66 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -4,6 +4,7 @@ #include <linux/device.h> #include <linux/string.h> +#include <linux/export.h> #include <linux/pm_runtime.h> #include <linux/atomic.h> #include <linux/jiffies.h> diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index af10abecb99b..d94a1f5121cf 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c @@ -8,6 +8,7 @@ */ #include <linux/resume-trace.h> +#include <linux/export.h> #include <linux/rtc.h> #include <asm/rtc.h> diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 14ee07e9cc43..caf995fb774b 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -10,6 +10,7 @@ #include <linux/slab.h> #include <linux/sched.h> #include <linux/capability.h> +#include <linux/export.h> #include <linux/suspend.h> #include <linux/seq_file.h> #include <linux/debugfs.h> diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index afcfef838263..666f6f5011dc 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -11,6 +11,7 @@ */ #include <linux/slab.h> +#include <linux/export.h> #include <trace/events/regmap.h> #include <linux/bsearch.h> #include <linux/sort.h> diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c index 84997efdb23d..f6c453c3816e 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c @@ -27,6 +27,7 @@ * transport class is framed entirely in terms of generic devices to * allow it to be used by any physical HBA in the system. */ +#include <linux/export.h> #include <linux/attribute_container.h> #include <linux/transport_class.h> diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c index 189a97b51be9..893f6e0c759f 100644 --- a/drivers/bcma/core.c +++ b/drivers/bcma/core.c @@ -6,6 +6,7 @@ */ #include "bcma_private.h" +#include <linux/export.h> #include <linux/bcma/bcma.h> bool bcma_core_is_enabled(struct bcma_device *core) diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index 47cce9d69630..e9f1b3fd252c 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -9,6 +9,7 @@ */ #include "bcma_private.h" +#include <linux/export.h> #include <linux/bcma/bcma.h> static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index 2968d809d49f..800163c8c2e7 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -9,6 +9,7 @@ */ #include "bcma_private.h" +#include <linux/export.h> #include <linux/bcma/bcma.h> static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset) diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 81f3d0a4b856..4fde6254f04e 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -9,6 +9,7 @@ */ #include "bcma_private.h" +#include <linux/export.h> #include <linux/bcma/bcma.h> /************************************************** diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index ac4bc626c149..1b51d8b7ac80 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -9,6 +9,7 @@ #include <linux/slab.h> #include <linux/bcma/bcma.h> #include <linux/pci.h> +#include <linux/module.h> static void bcma_host_pci_switch_core(struct bcma_device *core) { diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 8c09c3e547cd..70c84b951098 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -6,6 +6,7 @@ */ #include "bcma_private.h" +#include <linux/module.h> #include <linux/bcma/bcma.h> #include <linux/slab.h> diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 528f6318ded1..321de7b6c442 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -15,6 +15,7 @@ #include <linux/genhd.h> #include <linux/netdevice.h> #include <linux/mutex.h> +#include <linux/export.h> #include "aoe.h" static DEFINE_MUTEX(aoeblk_mutex); @@ -159,7 +160,7 @@ aoeblk_release(struct gendisk *disk, fmode_t mode) return 0; } -static int +static void aoeblk_make_request(struct request_queue *q, struct bio *bio) { struct sk_buff_head queue; @@ -172,25 +173,25 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) if (bio == NULL) { printk(KERN_ERR "aoe: bio is NULL\n"); BUG(); - return 0; + return; } d = bio->bi_bdev->bd_disk->private_data; if (d == NULL) { printk(KERN_ERR "aoe: bd_disk->private_data is NULL\n"); BUG(); bio_endio(bio, -ENXIO); - return 0; + return; } else if (bio->bi_io_vec == NULL) { printk(KERN_ERR "aoe: bi_io_vec is NULL\n"); BUG(); bio_endio(bio, -ENXIO); - return 0; + return; } buf = mempool_alloc(d->bufpool, GFP_NOIO); if (buf == NULL) { printk(KERN_INFO "aoe: buf allocation failure\n"); bio_endio(bio, -ENOMEM); - return 0; + return; } memset(buf, 0, sizeof(*buf)); INIT_LIST_HEAD(&buf->bufs); @@ -211,7 +212,7 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) spin_unlock_irqrestore(&d->lock, flags); mempool_free(buf, d->bufpool); bio_endio(bio, -ENXIO); - return 0; + return; } list_add_tail(&buf->bufs, &d->bufq); @@ -222,8 +223,6 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) spin_unlock_irqrestore(&d->lock, flags); aoenet_xmit(&queue); - - return 0; } static int diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 146296ca4965..5f8e39c43ae5 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/skbuff.h> +#include <linux/export.h> #include "aoe.h" enum { diff --git a/drivers/block/brd.c b/drivers/block/brd.c index dba1c32e1ddf..d22119d49e53 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -323,7 +323,7 @@ out: return err; } -static int brd_make_request(struct request_queue *q, struct bio *bio) +static void brd_make_request(struct request_queue *q, struct bio *bio) { struct block_device *bdev = bio->bi_bdev; struct brd_device *brd = bdev->bd_disk->private_data; @@ -359,8 +359,6 @@ static int brd_make_request(struct request_queue *q, struct bio *bio) out: bio_endio(bio, err); - - return 0; } #ifdef CONFIG_BLK_DEV_XIP diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 8f4ef656a1af..486f94ef24d4 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -68,6 +68,10 @@ static int cciss_tape_cmds = 6; module_param(cciss_tape_cmds, int, 0644); MODULE_PARM_DESC(cciss_tape_cmds, "number of commands to allocate for tape devices (default: 6)"); +static int cciss_simple_mode; +module_param(cciss_simple_mode, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(cciss_simple_mode, + "Use 'simple mode' rather than 'performant mode'"); static DEFINE_MUTEX(cciss_mutex); static struct proc_dir_entry *proc_cciss; @@ -176,6 +180,7 @@ static void cciss_geometry_inquiry(ctlr_info_t *h, int logvol, unsigned int block_size, InquiryData_struct *inq_buff, drive_info_struct *drv); static void __devinit cciss_interrupt_mode(ctlr_info_t *); +static int __devinit cciss_enter_simple_mode(struct ctlr_info *h); static void start_io(ctlr_info_t *h); static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size, __u8 page_code, unsigned char scsi3addr[], @@ -388,7 +393,7 @@ static void cciss_seq_show_header(struct seq_file *seq) h->product_name, (unsigned long)h->board_id, h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], - h->firm_ver[3], (unsigned int)h->intr[PERF_MODE_INT], + h->firm_ver[3], (unsigned int)h->intr[h->intr_mode], h->num_luns, h->Qdepth, h->commands_outstanding, h->maxQsinceinit, h->max_outstanding, h->maxSG); @@ -636,6 +641,18 @@ static ssize_t host_store_rescan(struct device *dev, } static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan); +static ssize_t host_show_transport_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ctlr_info *h = to_hba(dev); + + return snprintf(buf, 20, "%s\n", + h->transMethod & CFGTBL_Trans_Performant ? + "performant" : "simple"); +} +static DEVICE_ATTR(transport_mode, S_IRUGO, host_show_transport_mode, NULL); + static ssize_t dev_show_unique_id(struct device *dev, struct device_attribute *attr, char *buf) @@ -808,6 +825,7 @@ static DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL); static struct attribute *cciss_host_attrs[] = { &dev_attr_rescan.attr, &dev_attr_resettable.attr, + &dev_attr_transport_mode.attr, NULL }; @@ -3984,6 +4002,9 @@ static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h) { __u32 trans_support; + if (cciss_simple_mode) + return; + dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode\n"); /* Attempt to put controller into performant mode if supported */ /* Does board support performant mode? */ @@ -4081,7 +4102,7 @@ static void __devinit cciss_interrupt_mode(ctlr_info_t *h) default_int_mode: #endif /* CONFIG_PCI_MSI */ /* if we get here we're going to use the default interrupt mode */ - h->intr[PERF_MODE_INT] = h->pdev->irq; + h->intr[h->intr_mode] = h->pdev->irq; return; } @@ -4341,6 +4362,9 @@ static int __devinit cciss_pci_init(ctlr_info_t *h) } cciss_enable_scsi_prefetch(h); cciss_p600_dma_prefetch_quirk(h); + err = cciss_enter_simple_mode(h); + if (err) + goto err_out_free_res; cciss_put_controller_into_performant_mode(h); return 0; @@ -4533,6 +4557,13 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev, pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= PCI_D0; pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); + + /* + * The P600 requires a small delay when changing states. + * Otherwise we may think the board did not reset and we bail. + * This for kdump only and is particular to the P600. + */ + msleep(500); } return 0; } @@ -4843,20 +4874,20 @@ static int cciss_request_irq(ctlr_info_t *h, irqreturn_t (*intxhandler)(int, void *)) { if (h->msix_vector || h->msi_vector) { - if (!request_irq(h->intr[PERF_MODE_INT], msixhandler, + if (!request_irq(h->intr[h->intr_mode], msixhandler, IRQF_DISABLED, h->devname, h)) return 0; dev_err(&h->pdev->dev, "Unable to get msi irq %d" - " for %s\n", h->intr[PERF_MODE_INT], + " for %s\n", h->intr[h->intr_mode], h->devname); return -1; } - if (!request_irq(h->intr[PERF_MODE_INT], intxhandler, + if (!request_irq(h->intr[h->intr_mode], intxhandler, IRQF_DISABLED, h->devname, h)) return 0; dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n", - h->intr[PERF_MODE_INT], h->devname); + h->intr[h->intr_mode], h->devname); return -1; } @@ -4887,7 +4918,7 @@ static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h) { int ctlr = h->ctlr; - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); #ifdef CONFIG_PCI_MSI if (h->msix_vector) pci_disable_msix(h->pdev); @@ -4953,6 +4984,7 @@ reinit_after_soft_reset: h = hba[i]; h->pdev = pdev; h->busy_initializing = 1; + h->intr_mode = cciss_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; INIT_LIST_HEAD(&h->cmpQ); INIT_LIST_HEAD(&h->reqQ); mutex_init(&h->busy_shutting_down); @@ -5009,7 +5041,7 @@ reinit_after_soft_reset: dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n", h->devname, pdev->device, pci_name(pdev), - h->intr[PERF_MODE_INT], dac ? "" : " not"); + h->intr[h->intr_mode], dac ? "" : " not"); if (cciss_allocate_cmd_pool(h)) goto clean4; @@ -5056,7 +5088,7 @@ reinit_after_soft_reset: spin_lock_irqsave(&h->lock, flags); h->access.set_intr_mask(h, CCISS_INTR_OFF); spin_unlock_irqrestore(&h->lock, flags); - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); rc = cciss_request_irq(h, cciss_msix_discard_completions, cciss_intx_discard_completions); if (rc) { @@ -5133,7 +5165,7 @@ clean4: cciss_free_cmd_pool(h); cciss_free_scatterlists(h); cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds); - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); clean2: unregister_blkdev(h->major, h->devname); clean1: @@ -5172,9 +5204,31 @@ static void cciss_shutdown(struct pci_dev *pdev) if (return_code != IO_OK) dev_warn(&h->pdev->dev, "Error flushing cache\n"); h->access.set_intr_mask(h, CCISS_INTR_OFF); - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); +} + +static int __devinit cciss_enter_simple_mode(struct ctlr_info *h) +{ + u32 trans_support; + + trans_support = readl(&(h->cfgtable->TransportSupport)); + if (!(trans_support & SIMPLE_MODE)) + return -ENOTSUPP; + + h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); + writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + cciss_wait_for_mode_change_ack(h); + print_cfg_table(h); + if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { + dev_warn(&h->pdev->dev, "unable to get board into simple mode\n"); + return -ENODEV; + } + h->transMethod = CFGTBL_Trans_Simple; + return 0; } + static void __devexit cciss_remove_one(struct pci_dev *pdev) { ctlr_info_t *h; diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index c049548e68b7..7fda30e4a241 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -92,6 +92,7 @@ struct ctlr_info unsigned int intr[4]; unsigned int msix_vector; unsigned int msi_vector; + int intr_mode; int cciss_max_sectors; BYTE cciss_read; BYTE cciss_write; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index b2fceb53e809..9125bbeacd4d 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -620,6 +620,7 @@ static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev) } vendor_id = pdev->vendor; device_id = pdev->device; + revision = pdev->revision; irq = pdev->irq; for(i=0; i<6; i++) @@ -632,7 +633,6 @@ static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev) } pci_read_config_word(pdev, PCI_COMMAND, &command); - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size); pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer); diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 1706d60b8c99..9cf20355ceec 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1506,7 +1506,7 @@ extern void drbd_free_mdev(struct drbd_conf *mdev); extern int proc_details; /* drbd_req */ -extern int drbd_make_request(struct request_queue *q, struct bio *bio); +extern void drbd_make_request(struct request_queue *q, struct bio *bio); extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req); extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec); extern int is_valid_ar_handle(struct drbd_request *, sector_t); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 3424d675b769..4a0f314086e5 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1073,7 +1073,7 @@ static int drbd_fail_request_early(struct drbd_conf *mdev, int is_write) return 0; } -int drbd_make_request(struct request_queue *q, struct bio *bio) +void drbd_make_request(struct request_queue *q, struct bio *bio) { unsigned int s_enr, e_enr; struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata; @@ -1081,7 +1081,7 @@ int drbd_make_request(struct request_queue *q, struct bio *bio) if (drbd_fail_request_early(mdev, bio_data_dir(bio) & WRITE)) { bio_endio(bio, -EPERM); - return 0; + return; } start_time = jiffies; @@ -1100,7 +1100,8 @@ int drbd_make_request(struct request_queue *q, struct bio *bio) if (likely(s_enr == e_enr)) { inc_ap_bio(mdev, 1); - return drbd_make_request_common(mdev, bio, start_time); + drbd_make_request_common(mdev, bio, start_time); + return; } /* can this bio be split generically? @@ -1148,7 +1149,6 @@ int drbd_make_request(struct request_queue *q, struct bio *bio) bio_pair_release(bp); } - return 0; } /* This is called by bio_add_page(). With this function we reduce diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 4720c7ade0ae..3d806820280e 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -76,6 +76,8 @@ #include <linux/splice.h> #include <linux/sysfs.h> #include <linux/miscdevice.h> +#include <linux/falloc.h> + #include <asm/uaccess.h> static DEFINE_IDR(loop_index_idr); @@ -203,74 +205,6 @@ lo_do_transfer(struct loop_device *lo, int cmd, } /** - * do_lo_send_aops - helper for writing data to a loop device - * - * This is the fast version for backing filesystems which implement the address - * space operations write_begin and write_end. - */ -static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec, - loff_t pos, struct page *unused) -{ - struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */ - struct address_space *mapping = file->f_mapping; - pgoff_t index; - unsigned offset, bv_offs; - int len, ret; - - mutex_lock(&mapping->host->i_mutex); - index = pos >> PAGE_CACHE_SHIFT; - offset = pos & ((pgoff_t)PAGE_CACHE_SIZE - 1); - bv_offs = bvec->bv_offset; - len = bvec->bv_len; - while (len > 0) { - sector_t IV; - unsigned size, copied; - int transfer_result; - struct page *page; - void *fsdata; - - IV = ((sector_t)index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9); - size = PAGE_CACHE_SIZE - offset; - if (size > len) - size = len; - - ret = pagecache_write_begin(file, mapping, pos, size, 0, - &page, &fsdata); - if (ret) - goto fail; - - file_update_time(file); - - transfer_result = lo_do_transfer(lo, WRITE, page, offset, - bvec->bv_page, bv_offs, size, IV); - copied = size; - if (unlikely(transfer_result)) - copied = 0; - - ret = pagecache_write_end(file, mapping, pos, size, copied, - page, fsdata); - if (ret < 0 || ret != copied) - goto fail; - - if (unlikely(transfer_result)) - goto fail; - - bv_offs += copied; - len -= copied; - offset = 0; - index++; - pos += copied; - } - ret = 0; -out: - mutex_unlock(&mapping->host->i_mutex); - return ret; -fail: - ret = -1; - goto out; -} - -/** * __do_lo_send_write - helper for writing data to a loop device * * This helper just factors out common code between do_lo_send_direct_write() @@ -297,10 +231,8 @@ static int __do_lo_send_write(struct file *file, /** * do_lo_send_direct_write - helper for writing data to a loop device * - * This is the fast, non-transforming version for backing filesystems which do - * not implement the address space operations write_begin and write_end. - * It uses the write file operation which should be present on all writeable - * filesystems. + * This is the fast, non-transforming version that does not need double + * buffering. */ static int do_lo_send_direct_write(struct loop_device *lo, struct bio_vec *bvec, loff_t pos, struct page *page) @@ -316,15 +248,9 @@ static int do_lo_send_direct_write(struct loop_device *lo, /** * do_lo_send_write - helper for writing data to a loop device * - * This is the slow, transforming version for filesystems which do not - * implement the address space operations write_begin and write_end. It - * uses the write file operation which should be present on all writeable - * filesystems. - * - * Using fops->write is slower than using aops->{prepare,commit}_write in the - * transforming case because we need to double buffer the data as we cannot do - * the transformations in place as we do not have direct access to the - * destination pages of the backing file. + * This is the slow, transforming version that needs to double buffer the + * data as it cannot do the transformations in place without having direct + * access to the destination pages of the backing file. */ static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec, loff_t pos, struct page *page) @@ -350,17 +276,16 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos) struct page *page = NULL; int i, ret = 0; - do_lo_send = do_lo_send_aops; - if (!(lo->lo_flags & LO_FLAGS_USE_AOPS)) { + if (lo->transfer != transfer_none) { + page = alloc_page(GFP_NOIO | __GFP_HIGHMEM); + if (unlikely(!page)) + goto fail; + kmap(page); + do_lo_send = do_lo_send_write; + } else { do_lo_send = do_lo_send_direct_write; - if (lo->transfer != transfer_none) { - page = alloc_page(GFP_NOIO | __GFP_HIGHMEM); - if (unlikely(!page)) - goto fail; - kmap(page); - do_lo_send = do_lo_send_write; - } } + bio_for_each_segment(bvec, bio, i) { ret = do_lo_send(lo, bvec, pos, page); if (ret < 0) @@ -484,6 +409,29 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) } } + /* + * We use punch hole to reclaim the free space used by the + * image a.k.a. discard. However we do support discard if + * encryption is enabled, because it may give an attacker + * useful information. + */ + if (bio->bi_rw & REQ_DISCARD) { + struct file *file = lo->lo_backing_file; + int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; + + if ((!file->f_op->fallocate) || + lo->lo_encrypt_key_size) { + ret = -EOPNOTSUPP; + goto out; + } + ret = file->f_op->fallocate(file, mode, pos, + bio->bi_size); + if (unlikely(ret && ret != -EINVAL && + ret != -EOPNOTSUPP)) + ret = -EIO; + goto out; + } + ret = lo_send(lo, bio, pos); if ((bio->bi_rw & REQ_FUA) && !ret) { @@ -514,7 +462,7 @@ static struct bio *loop_get_bio(struct loop_device *lo) return bio_list_pop(&lo->lo_bio_list); } -static int loop_make_request(struct request_queue *q, struct bio *old_bio) +static void loop_make_request(struct request_queue *q, struct bio *old_bio) { struct loop_device *lo = q->queuedata; int rw = bio_rw(old_bio); @@ -532,12 +480,11 @@ static int loop_make_request(struct request_queue *q, struct bio *old_bio) loop_add_bio(lo, old_bio); wake_up(&lo->lo_event); spin_unlock_irq(&lo->lo_lock); - return 0; + return; out: spin_unlock_irq(&lo->lo_lock); bio_io_error(old_bio); - return 0; } struct switch_request { @@ -700,7 +647,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, goto out_putf; fput(old_file); - if (max_part > 0) + if (lo->lo_flags & LO_FLAGS_PARTSCAN) ioctl_by_bdev(bdev, BLKRRPART, 0); return 0; @@ -777,16 +724,25 @@ static ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf) return sprintf(buf, "%s\n", autoclear ? "1" : "0"); } +static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf) +{ + int partscan = (lo->lo_flags & LO_FLAGS_PARTSCAN); + + return sprintf(buf, "%s\n", partscan ? "1" : "0"); +} + LOOP_ATTR_RO(backing_file); LOOP_ATTR_RO(offset); LOOP_ATTR_RO(sizelimit); LOOP_ATTR_RO(autoclear); +LOOP_ATTR_RO(partscan); static struct attribute *loop_attrs[] = { &loop_attr_backing_file.attr, &loop_attr_offset.attr, &loop_attr_sizelimit.attr, &loop_attr_autoclear.attr, + &loop_attr_partscan.attr, NULL, }; @@ -807,6 +763,35 @@ static void loop_sysfs_exit(struct loop_device *lo) &loop_attribute_group); } +static void loop_config_discard(struct loop_device *lo) +{ + struct file *file = lo->lo_backing_file; + struct inode *inode = file->f_mapping->host; + struct request_queue *q = lo->lo_queue; + + /* + * We use punch hole to reclaim the free space used by the + * image a.k.a. discard. However we do support discard if + * encryption is enabled, because it may give an attacker + * useful information. + */ + if ((!file->f_op->fallocate) || + lo->lo_encrypt_key_size) { + q->limits.discard_granularity = 0; + q->limits.discard_alignment = 0; + q->limits.max_discard_sectors = 0; + q->limits.discard_zeroes_data = 0; + queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); + return; + } + + q->limits.discard_granularity = inode->i_sb->s_blocksize; + q->limits.discard_alignment = inode->i_sb->s_blocksize; + q->limits.max_discard_sectors = UINT_MAX >> 9; + q->limits.discard_zeroes_data = 1; + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); +} + static int loop_set_fd(struct loop_device *lo, fmode_t mode, struct block_device *bdev, unsigned int arg) { @@ -849,35 +834,23 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, mapping = file->f_mapping; inode = mapping->host; - if (!(file->f_mode & FMODE_WRITE)) - lo_flags |= LO_FLAGS_READ_ONLY; - error = -EINVAL; - if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) { - const struct address_space_operations *aops = mapping->a_ops; - - if (aops->write_begin) - lo_flags |= LO_FLAGS_USE_AOPS; - if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write) - lo_flags |= LO_FLAGS_READ_ONLY; + if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) + goto out_putf; - lo_blocksize = S_ISBLK(inode->i_mode) ? - inode->i_bdev->bd_block_size : PAGE_SIZE; + if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) || + !file->f_op->write) + lo_flags |= LO_FLAGS_READ_ONLY; - error = 0; - } else { - goto out_putf; - } + lo_blocksize = S_ISBLK(inode->i_mode) ? + inode->i_bdev->bd_block_size : PAGE_SIZE; + error = -EFBIG; size = get_loop_size(lo, file); - - if ((loff_t)(sector_t)size != size) { - error = -EFBIG; + if ((loff_t)(sector_t)size != size) goto out_putf; - } - if (!(mode & FMODE_WRITE)) - lo_flags |= LO_FLAGS_READ_ONLY; + error = 0; set_device_ro(bdev, (lo_flags & LO_FLAGS_READ_ONLY) != 0); @@ -919,7 +892,9 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, } lo->lo_state = Lo_bound; wake_up_process(lo->lo_thread); - if (max_part > 0) + if (part_shift) + lo->lo_flags |= LO_FLAGS_PARTSCAN; + if (lo->lo_flags & LO_FLAGS_PARTSCAN) ioctl_by_bdev(bdev, BLKRRPART, 0); return 0; @@ -980,10 +955,11 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, return err; } -static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) +static int loop_clr_fd(struct loop_device *lo) { struct file *filp = lo->lo_backing_file; gfp_t gfp = lo->old_gfp_mask; + struct block_device *bdev = lo->lo_device; if (lo->lo_state != Lo_bound) return -ENXIO; @@ -1012,7 +988,6 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) lo->lo_offset = 0; lo->lo_sizelimit = 0; lo->lo_encrypt_key_size = 0; - lo->lo_flags = 0; lo->lo_thread = NULL; memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); @@ -1030,8 +1005,11 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) lo->lo_state = Lo_unbound; /* This is safe: open() is still holding a reference. */ module_put(THIS_MODULE); - if (max_part > 0 && bdev) + if (lo->lo_flags & LO_FLAGS_PARTSCAN && bdev) ioctl_by_bdev(bdev, BLKRRPART, 0); + lo->lo_flags = 0; + if (!part_shift) + lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; mutex_unlock(&lo->lo_ctl_mutex); /* * Need not hold lo_ctl_mutex to fput backing file. @@ -1085,6 +1063,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if (figure_loop_size(lo)) return -EFBIG; } + loop_config_discard(lo); memcpy(lo->lo_file_name, info->lo_file_name, LO_NAME_SIZE); memcpy(lo->lo_crypt_name, info->lo_crypt_name, LO_NAME_SIZE); @@ -1100,6 +1079,13 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) (info->lo_flags & LO_FLAGS_AUTOCLEAR)) lo->lo_flags ^= LO_FLAGS_AUTOCLEAR; + if ((info->lo_flags & LO_FLAGS_PARTSCAN) && + !(lo->lo_flags & LO_FLAGS_PARTSCAN)) { + lo->lo_flags |= LO_FLAGS_PARTSCAN; + lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN; + ioctl_by_bdev(lo->lo_device, BLKRRPART, 0); + } + lo->lo_encrypt_key_size = info->lo_encrypt_key_size; lo->lo_init[0] = info->lo_init[0]; lo->lo_init[1] = info->lo_init[1]; @@ -1293,7 +1279,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, break; case LOOP_CLR_FD: /* loop_clr_fd would have unlocked lo_ctl_mutex on success */ - err = loop_clr_fd(lo, bdev); + err = loop_clr_fd(lo); if (!err) goto out_unlocked; break; @@ -1513,7 +1499,7 @@ static int lo_release(struct gendisk *disk, fmode_t mode) * In autoclear mode, stop the loop thread * and remove configuration after last close. */ - err = loop_clr_fd(lo, NULL); + err = loop_clr_fd(lo); if (!err) goto out_unlocked; } else { @@ -1635,6 +1621,27 @@ static int loop_add(struct loop_device **l, int i) if (!disk) goto out_free_queue; + /* + * Disable partition scanning by default. The in-kernel partition + * scanning can be requested individually per-device during its + * setup. Userspace can always add and remove partitions from all + * devices. The needed partition minors are allocated from the + * extended minor space, the main loop device numbers will continue + * to match the loop minors, regardless of the number of partitions + * used. + * + * If max_part is given, partition scanning is globally enabled for + * all loop devices. The minors for the main loop devices will be + * multiples of max_part. + * + * Note: Global-for-all-devices, set-only-at-init, read-only module + * parameteters like 'max_loop' and 'max_part' make things needlessly + * complicated, are too static, inflexible and may surprise + * userspace tools. Parameters like this in general should be avoided. + */ + if (!part_shift) + disk->flags |= GENHD_FL_NO_PART_SCAN; + disk->flags |= GENHD_FL_EXT_DEVT; mutex_init(&lo->lo_ctl_mutex); lo->lo_number = i; lo->lo_thread = NULL; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index f533f3375e24..c3f0ee16594d 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -127,8 +127,7 @@ static void sock_shutdown(struct nbd_device *lo, int lock) if (lock) mutex_lock(&lo->tx_lock); if (lo->sock) { - printk(KERN_WARNING "%s: shutting down socket\n", - lo->disk->disk_name); + dev_warn(disk_to_dev(lo->disk), "shutting down socket\n"); kernel_sock_shutdown(lo->sock, SHUT_RDWR); lo->sock = NULL; } @@ -158,8 +157,9 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size, sigset_t blocked, oldset; if (unlikely(!sock)) { - printk(KERN_ERR "%s: Attempted %s on closed socket in sock_xmit\n", - lo->disk->disk_name, (send ? "send" : "recv")); + dev_err(disk_to_dev(lo->disk), + "Attempted %s on closed socket in sock_xmit\n", + (send ? "send" : "recv")); return -EINVAL; } @@ -250,8 +250,8 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) result = sock_xmit(lo, 1, &request, sizeof(request), (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0); if (result <= 0) { - printk(KERN_ERR "%s: Send control failed (result %d)\n", - lo->disk->disk_name, result); + dev_err(disk_to_dev(lo->disk), + "Send control failed (result %d)\n", result); goto error_out; } @@ -270,8 +270,9 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) lo->disk->disk_name, req, bvec->bv_len); result = sock_send_bvec(lo, bvec, flags); if (result <= 0) { - printk(KERN_ERR "%s: Send data failed (result %d)\n", - lo->disk->disk_name, result); + dev_err(disk_to_dev(lo->disk), + "Send data failed (result %d)\n", + result); goto error_out; } } @@ -328,14 +329,13 @@ static struct request *nbd_read_stat(struct nbd_device *lo) reply.magic = 0; result = sock_xmit(lo, 0, &reply, sizeof(reply), MSG_WAITALL); if (result <= 0) { - printk(KERN_ERR "%s: Receive control failed (result %d)\n", - lo->disk->disk_name, result); + dev_err(disk_to_dev(lo->disk), + "Receive control failed (result %d)\n", result); goto harderror; } if (ntohl(reply.magic) != NBD_REPLY_MAGIC) { - printk(KERN_ERR "%s: Wrong magic (0x%lx)\n", - lo->disk->disk_name, + dev_err(disk_to_dev(lo->disk), "Wrong magic (0x%lx)\n", (unsigned long)ntohl(reply.magic)); result = -EPROTO; goto harderror; @@ -347,15 +347,15 @@ static struct request *nbd_read_stat(struct nbd_device *lo) if (result != -ENOENT) goto harderror; - printk(KERN_ERR "%s: Unexpected reply (%p)\n", - lo->disk->disk_name, reply.handle); + dev_err(disk_to_dev(lo->disk), "Unexpected reply (%p)\n", + reply.handle); result = -EBADR; goto harderror; } if (ntohl(reply.error)) { - printk(KERN_ERR "%s: Other side returned error (%d)\n", - lo->disk->disk_name, ntohl(reply.error)); + dev_err(disk_to_dev(lo->disk), "Other side returned error (%d)\n", + ntohl(reply.error)); req->errors++; return req; } @@ -369,8 +369,8 @@ static struct request *nbd_read_stat(struct nbd_device *lo) rq_for_each_segment(bvec, req, iter) { result = sock_recv_bvec(lo, bvec); if (result <= 0) { - printk(KERN_ERR "%s: Receive data failed (result %d)\n", - lo->disk->disk_name, result); + dev_err(disk_to_dev(lo->disk), "Receive data failed (result %d)\n", + result); req->errors++; return req; } @@ -405,10 +405,10 @@ static int nbd_do_it(struct nbd_device *lo) BUG_ON(lo->magic != LO_MAGIC); - lo->pid = current->pid; - ret = sysfs_create_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr); + lo->pid = task_pid_nr(current); + ret = device_create_file(disk_to_dev(lo->disk), &pid_attr); if (ret) { - printk(KERN_ERR "nbd: sysfs_create_file failed!"); + dev_err(disk_to_dev(lo->disk), "device_create_file failed!\n"); lo->pid = 0; return ret; } @@ -416,7 +416,7 @@ static int nbd_do_it(struct nbd_device *lo) while ((req = nbd_read_stat(lo)) != NULL) nbd_end_request(req); - sysfs_remove_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr); + device_remove_file(disk_to_dev(lo->disk), &pid_attr); lo->pid = 0; return 0; } @@ -457,8 +457,8 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req) if (rq_data_dir(req) == WRITE) { nbd_cmd(req) = NBD_CMD_WRITE; if (lo->flags & NBD_READ_ONLY) { - printk(KERN_ERR "%s: Write on read-only\n", - lo->disk->disk_name); + dev_err(disk_to_dev(lo->disk), + "Write on read-only\n"); goto error_out; } } @@ -468,16 +468,15 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req) mutex_lock(&lo->tx_lock); if (unlikely(!lo->sock)) { mutex_unlock(&lo->tx_lock); - printk(KERN_ERR "%s: Attempted send on closed socket\n", - lo->disk->disk_name); + dev_err(disk_to_dev(lo->disk), + "Attempted send on closed socket\n"); goto error_out; } lo->active_req = req; if (nbd_send_req(lo, req) != 0) { - printk(KERN_ERR "%s: Request send failed\n", - lo->disk->disk_name); + dev_err(disk_to_dev(lo->disk), "Request send failed\n"); req->errors++; nbd_end_request(req); } else { @@ -549,8 +548,8 @@ static void do_nbd_request(struct request_queue *q) BUG_ON(lo->magic != LO_MAGIC); if (unlikely(!lo->sock)) { - printk(KERN_ERR "%s: Attempted send on closed socket\n", - lo->disk->disk_name); + dev_err(disk_to_dev(lo->disk), + "Attempted send on closed socket\n"); req->errors++; nbd_end_request(req); spin_lock_irq(q->queue_lock); @@ -576,7 +575,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, case NBD_DISCONNECT: { struct request sreq; - printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); + dev_info(disk_to_dev(lo->disk), "NBD_DISCONNECT\n"); blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_SPECIAL; @@ -674,7 +673,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, file = lo->file; lo->file = NULL; nbd_clear_que(lo); - printk(KERN_WARNING "%s: queue cleared\n", lo->disk->disk_name); + dev_warn(disk_to_dev(lo->disk), "queue cleared\n"); if (file) fput(file); lo->bytesize = 0; @@ -694,8 +693,8 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, return 0; case NBD_PRINT_DEBUG: - printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n", - bdev->bd_disk->disk_name, + dev_info(disk_to_dev(lo->disk), + "next = %p, prev = %p, head = %p\n", lo->queue_head.next, lo->queue_head.prev, &lo->queue_head); return 0; @@ -745,7 +744,7 @@ static int __init nbd_init(void) BUILD_BUG_ON(sizeof(struct nbd_request) != 28); if (max_part < 0) { - printk(KERN_CRIT "nbd: max_part must be >= 0\n"); + printk(KERN_ERR "nbd: max_part must be >= 0\n"); return -EINVAL; } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index e133f094ab08..a63b0a2b7805 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2444,7 +2444,7 @@ static void pkt_end_io_read_cloned(struct bio *bio, int err) pkt_bio_finished(pd); } -static int pkt_make_request(struct request_queue *q, struct bio *bio) +static void pkt_make_request(struct request_queue *q, struct bio *bio) { struct pktcdvd_device *pd; char b[BDEVNAME_SIZE]; @@ -2473,7 +2473,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) cloned_bio->bi_end_io = pkt_end_io_read_cloned; pd->stats.secs_r += bio->bi_size >> 9; pkt_queue_bio(pd, cloned_bio); - return 0; + return; } if (!test_bit(PACKET_WRITABLE, &pd->flags)) { @@ -2509,7 +2509,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) pkt_make_request(q, &bp->bio1); pkt_make_request(q, &bp->bio2); bio_pair_release(bp); - return 0; + return; } } @@ -2533,7 +2533,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) } spin_unlock(&pkt->lock); spin_unlock(&pd->cdrw.active_list_lock); - return 0; + return; } else { blocked_bio = 1; } @@ -2584,10 +2584,9 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) */ wake_up(&pd->wqueue); } - return 0; + return; end_io: bio_io_error(bio); - return 0; } diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 8e1ce2e2916a..da0abc1838c1 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -21,6 +21,7 @@ #include <linux/ata.h> #include <linux/blkdev.h> #include <linux/slab.h> +#include <linux/module.h> #include <asm/lv1call.h> #include <asm/ps3stor.h> diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index b3bdb8af89cf..f58cdcfb305f 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -10,6 +10,7 @@ #include <linux/blkdev.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/slab.h> @@ -596,7 +597,7 @@ out: return next; } -static int ps3vram_make_request(struct request_queue *q, struct bio *bio) +static void ps3vram_make_request(struct request_queue *q, struct bio *bio) { struct ps3_system_bus_device *dev = q->queuedata; struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); @@ -610,13 +611,11 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio) spin_unlock_irq(&priv->lock); if (busy) - return 0; + return; do { bio = ps3vram_do_bio(dev, bio); } while (bio); - - return 0; } static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 031ca720d926..aa2712060bfb 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -513,7 +513,7 @@ static void process_page(unsigned long data) } } -static int mm_make_request(struct request_queue *q, struct bio *bio) +static void mm_make_request(struct request_queue *q, struct bio *bio) { struct cardinfo *card = q->queuedata; pr_debug("mm_make_request %llu %u\n", @@ -525,7 +525,7 @@ static int mm_make_request(struct request_queue *q, struct bio *bio) card->biotail = &bio->bi_next; spin_unlock_irq(&card->lock); - return 0; + return; } static irqreturn_t mm_interrupt(int irq, void *__card) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index e7a5750a93d9..4d0b70adf5f7 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -3,6 +3,7 @@ #include <linux/slab.h> #include <linux/blkdev.h> #include <linux/hdreg.h> +#include <linux/module.h> #include <linux/virtio.h> #include <linux/virtio_blk.h> #include <linux/scatterlist.h> diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 1540792b1e54..15ec4db194d1 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -39,6 +39,9 @@ #include <linux/list.h> #include <linux/delay.h> #include <linux/freezer.h> +#include <linux/loop.h> +#include <linux/falloc.h> +#include <linux/fs.h> #include <xen/events.h> #include <xen/page.h> @@ -258,13 +261,16 @@ irqreturn_t xen_blkif_be_int(int irq, void *dev_id) static void print_stats(struct xen_blkif *blkif) { - pr_info("xen-blkback (%s): oo %3d | rd %4d | wr %4d | f %4d\n", + pr_info("xen-blkback (%s): oo %3d | rd %4d | wr %4d | f %4d" + " | ds %4d\n", current->comm, blkif->st_oo_req, - blkif->st_rd_req, blkif->st_wr_req, blkif->st_f_req); + blkif->st_rd_req, blkif->st_wr_req, + blkif->st_f_req, blkif->st_ds_req); blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000); blkif->st_rd_req = 0; blkif->st_wr_req = 0; blkif->st_oo_req = 0; + blkif->st_ds_req = 0; } int xen_blkif_schedule(void *arg) @@ -410,6 +416,59 @@ static int xen_blkbk_map(struct blkif_request *req, return ret; } +static void xen_blk_discard(struct xen_blkif *blkif, struct blkif_request *req) +{ + int err = 0; + int status = BLKIF_RSP_OKAY; + struct block_device *bdev = blkif->vbd.bdev; + + if (blkif->blk_backend_type == BLKIF_BACKEND_PHY) + /* just forward the discard request */ + err = blkdev_issue_discard(bdev, + req->u.discard.sector_number, + req->u.discard.nr_sectors, + GFP_KERNEL, 0); + else if (blkif->blk_backend_type == BLKIF_BACKEND_FILE) { + /* punch a hole in the backing file */ + struct loop_device *lo = bdev->bd_disk->private_data; + struct file *file = lo->lo_backing_file; + + if (file->f_op->fallocate) + err = file->f_op->fallocate(file, + FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, + req->u.discard.sector_number << 9, + req->u.discard.nr_sectors << 9); + else + err = -EOPNOTSUPP; + } else + err = -EOPNOTSUPP; + + if (err == -EOPNOTSUPP) { + pr_debug(DRV_PFX "discard op failed, not supported\n"); + status = BLKIF_RSP_EOPNOTSUPP; + } else if (err) + status = BLKIF_RSP_ERROR; + + make_response(blkif, req->id, req->operation, status); +} + +static void xen_blk_drain_io(struct xen_blkif *blkif) +{ + atomic_set(&blkif->drain, 1); + do { + /* The initial value is one, and one refcnt taken at the + * start of the xen_blkif_schedule thread. */ + if (atomic_read(&blkif->refcnt) <= 2) + break; + wait_for_completion_interruptible_timeout( + &blkif->drain_complete, HZ); + + if (!atomic_read(&blkif->drain)) + break; + } while (!kthread_should_stop()); + atomic_set(&blkif->drain, 0); +} + /* * Completion callback on the bio's. Called as bh->b_end_io() */ @@ -422,6 +481,11 @@ static void __end_block_io_op(struct pending_req *pending_req, int error) pr_debug(DRV_PFX "flush diskcache op failed, not supported\n"); xen_blkbk_flush_diskcache(XBT_NIL, pending_req->blkif->be, 0); pending_req->status = BLKIF_RSP_EOPNOTSUPP; + } else if ((pending_req->operation == BLKIF_OP_WRITE_BARRIER) && + (error == -EOPNOTSUPP)) { + pr_debug(DRV_PFX "write barrier op failed, not supported\n"); + xen_blkbk_barrier(XBT_NIL, pending_req->blkif->be, 0); + pending_req->status = BLKIF_RSP_EOPNOTSUPP; } else if (error) { pr_debug(DRV_PFX "Buffer not up-to-date at end of operation," " error=%d\n", error); @@ -438,6 +502,10 @@ static void __end_block_io_op(struct pending_req *pending_req, int error) make_response(pending_req->blkif, pending_req->id, pending_req->operation, pending_req->status); xen_blkif_put(pending_req->blkif); + if (atomic_read(&pending_req->blkif->refcnt) <= 2) { + if (atomic_read(&pending_req->blkif->drain)) + complete(&pending_req->blkif->drain_complete); + } free_req(pending_req); } } @@ -532,7 +600,6 @@ do_block_io_op(struct xen_blkif *blkif) return more_to_do; } - /* * Transmutation of the 'struct blkif_request' to a proper 'struct bio' * and call the 'submit_bio' to pass it to the underlying storage. @@ -549,6 +616,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, int i, nbio = 0; int operation; struct blk_plug plug; + bool drain = false; switch (req->operation) { case BLKIF_OP_READ: @@ -559,11 +627,16 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, blkif->st_wr_req++; operation = WRITE_ODIRECT; break; + case BLKIF_OP_WRITE_BARRIER: + drain = true; case BLKIF_OP_FLUSH_DISKCACHE: blkif->st_f_req++; operation = WRITE_FLUSH; break; - case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_DISCARD: + blkif->st_ds_req++; + operation = REQ_DISCARD; + break; default: operation = 0; /* make gcc happy */ goto fail_response; @@ -572,7 +645,8 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, /* Check that the number of segments is sane. */ nseg = req->nr_segments; - if (unlikely(nseg == 0 && operation != WRITE_FLUSH) || + if (unlikely(nseg == 0 && operation != WRITE_FLUSH && + operation != REQ_DISCARD) || unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) { pr_debug(DRV_PFX "Bad number of segments in request (%d)\n", nseg); @@ -621,16 +695,25 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, } } + /* Wait on all outstanding I/O's and once that has been completed + * issue the WRITE_FLUSH. + */ + if (drain) + xen_blk_drain_io(pending_req->blkif); + /* * If we have failed at this point, we need to undo the M2P override, * set gnttab_set_unmap_op on all of the grant references and perform * the hypercall to unmap the grants - that is all done in * xen_blkbk_unmap. */ - if (xen_blkbk_map(req, pending_req, seg)) + if (operation != REQ_DISCARD && xen_blkbk_map(req, pending_req, seg)) goto fail_flush; - /* This corresponding xen_blkif_put is done in __end_block_io_op */ + /* + * This corresponding xen_blkif_put is done in __end_block_io_op, or + * below (in "!bio") if we are handling a BLKIF_OP_DISCARD. + */ xen_blkif_get(blkif); for (i = 0; i < nseg; i++) { @@ -654,18 +737,25 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, preq.sector_number += seg[i].nsec; } - /* This will be hit if the operation was a flush. */ + /* This will be hit if the operation was a flush or discard. */ if (!bio) { - BUG_ON(operation != WRITE_FLUSH); + BUG_ON(operation != WRITE_FLUSH && operation != REQ_DISCARD); - bio = bio_alloc(GFP_KERNEL, 0); - if (unlikely(bio == NULL)) - goto fail_put_bio; + if (operation == WRITE_FLUSH) { + bio = bio_alloc(GFP_KERNEL, 0); + if (unlikely(bio == NULL)) + goto fail_put_bio; - biolist[nbio++] = bio; - bio->bi_bdev = preq.bdev; - bio->bi_private = pending_req; - bio->bi_end_io = end_block_io_op; + biolist[nbio++] = bio; + bio->bi_bdev = preq.bdev; + bio->bi_private = pending_req; + bio->bi_end_io = end_block_io_op; + } else if (operation == REQ_DISCARD) { + xen_blk_discard(blkif, req); + xen_blkif_put(blkif); + free_req(pending_req); + return 0; + } } /* @@ -685,7 +775,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, if (operation == READ) blkif->st_rd_sect += preq.nr_sects; - else if (operation == WRITE || operation == WRITE_FLUSH) + else if (operation & WRITE) blkif->st_wr_sect += preq.nr_sects; return 0; @@ -765,9 +855,9 @@ static int __init xen_blkif_init(void) mmap_pages = xen_blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST; - blkbk->pending_reqs = kmalloc(sizeof(blkbk->pending_reqs[0]) * + blkbk->pending_reqs = kzalloc(sizeof(blkbk->pending_reqs[0]) * xen_blkif_reqs, GFP_KERNEL); - blkbk->pending_grant_handles = kzalloc(sizeof(blkbk->pending_grant_handles[0]) * + blkbk->pending_grant_handles = kmalloc(sizeof(blkbk->pending_grant_handles[0]) * mmap_pages, GFP_KERNEL); blkbk->pending_pages = kzalloc(sizeof(blkbk->pending_pages[0]) * mmap_pages, GFP_KERNEL); @@ -790,8 +880,6 @@ static int __init xen_blkif_init(void) if (rc) goto failed_init; - memset(blkbk->pending_reqs, 0, sizeof(blkbk->pending_reqs)); - INIT_LIST_HEAD(&blkbk->pending_free); spin_lock_init(&blkbk->pending_free_lock); init_waitqueue_head(&blkbk->pending_free_wq); diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index c4bd34063ecc..dfb1b3a43a5d 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -62,13 +62,26 @@ struct blkif_common_response { /* i386 protocol version */ #pragma pack(push, 4) + +struct blkif_x86_32_request_rw { + blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ + struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; +}; + +struct blkif_x86_32_request_discard { + blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ + uint64_t nr_sectors; +}; + struct blkif_x86_32_request { uint8_t operation; /* BLKIF_OP_??? */ uint8_t nr_segments; /* number of segments */ blkif_vdev_t handle; /* only for read/write requests */ uint64_t id; /* private guest value, echoed in resp */ - blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ - struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + union { + struct blkif_x86_32_request_rw rw; + struct blkif_x86_32_request_discard discard; + } u; }; struct blkif_x86_32_response { uint64_t id; /* copied from request */ @@ -78,13 +91,26 @@ struct blkif_x86_32_response { #pragma pack(pop) /* x86_64 protocol version */ + +struct blkif_x86_64_request_rw { + blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ + struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; +}; + +struct blkif_x86_64_request_discard { + blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ + uint64_t nr_sectors; +}; + struct blkif_x86_64_request { uint8_t operation; /* BLKIF_OP_??? */ uint8_t nr_segments; /* number of segments */ blkif_vdev_t handle; /* only for read/write requests */ uint64_t __attribute__((__aligned__(8))) id; - blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ - struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + union { + struct blkif_x86_64_request_rw rw; + struct blkif_x86_64_request_discard discard; + } u; }; struct blkif_x86_64_response { uint64_t __attribute__((__aligned__(8))) id; @@ -112,6 +138,11 @@ enum blkif_protocol { BLKIF_PROTOCOL_X86_64 = 3, }; +enum blkif_backend_type { + BLKIF_BACKEND_PHY = 1, + BLKIF_BACKEND_FILE = 2, +}; + struct xen_vbd { /* What the domain refers to this vbd as. */ blkif_vdev_t handle; @@ -137,8 +168,9 @@ struct xen_blkif { unsigned int irq; /* Comms information. */ enum blkif_protocol blk_protocol; + enum blkif_backend_type blk_backend_type; union blkif_back_rings blk_rings; - struct vm_struct *blk_ring_area; + void *blk_ring; /* The VBD attached to this interface. */ struct xen_vbd vbd; /* Back pointer to the backend_info. */ @@ -148,6 +180,9 @@ struct xen_blkif { atomic_t refcnt; wait_queue_head_t wq; + /* for barrier (drain) requests */ + struct completion drain_complete; + atomic_t drain; /* One thread per one blkif. */ struct task_struct *xenblkd; unsigned int waiting_reqs; @@ -158,13 +193,11 @@ struct xen_blkif { int st_wr_req; int st_oo_req; int st_f_req; + int st_ds_req; int st_rd_sect; int st_wr_sect; wait_queue_head_t waiting_to_free; - - grant_handle_t shmem_handle; - grant_ref_t shmem_ref; }; @@ -181,7 +214,7 @@ struct xen_blkif { struct phys_req { unsigned short dev; - unsigned short nr_sects; + blkif_sector_t nr_sects; struct block_device *bdev; blkif_sector_t sector_number; }; @@ -195,6 +228,8 @@ int xen_blkif_schedule(void *arg); int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, struct backend_info *be, int state); +int xen_blkbk_barrier(struct xenbus_transaction xbt, + struct backend_info *be, int state); struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be); static inline void blkif_get_x86_32_req(struct blkif_request *dst, @@ -205,12 +240,25 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst, dst->nr_segments = src->nr_segments; dst->handle = src->handle; dst->id = src->id; - dst->u.rw.sector_number = src->sector_number; - barrier(); - if (n > dst->nr_segments) - n = dst->nr_segments; - for (i = 0; i < n; i++) - dst->u.rw.seg[i] = src->seg[i]; + switch (src->operation) { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + dst->u.rw.sector_number = src->u.rw.sector_number; + barrier(); + if (n > dst->nr_segments) + n = dst->nr_segments; + for (i = 0; i < n; i++) + dst->u.rw.seg[i] = src->u.rw.seg[i]; + break; + case BLKIF_OP_DISCARD: + dst->u.discard.sector_number = src->u.discard.sector_number; + dst->u.discard.nr_sectors = src->u.discard.nr_sectors; + break; + default: + break; + } } static inline void blkif_get_x86_64_req(struct blkif_request *dst, @@ -221,12 +269,25 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst, dst->nr_segments = src->nr_segments; dst->handle = src->handle; dst->id = src->id; - dst->u.rw.sector_number = src->sector_number; - barrier(); - if (n > dst->nr_segments) - n = dst->nr_segments; - for (i = 0; i < n; i++) - dst->u.rw.seg[i] = src->seg[i]; + switch (src->operation) { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + dst->u.rw.sector_number = src->u.rw.sector_number; + barrier(); + if (n > dst->nr_segments) + n = dst->nr_segments; + for (i = 0; i < n; i++) + dst->u.rw.seg[i] = src->u.rw.seg[i]; + break; + case BLKIF_OP_DISCARD: + dst->u.discard.sector_number = src->u.discard.sector_number; + dst->u.discard.nr_sectors = src->u.discard.nr_sectors; + break; + default: + break; + } } #endif /* __XEN_BLKIF__BACKEND__COMMON_H__ */ diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 5fd2010f7d2b..f759ad4584c3 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -114,44 +114,14 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid) spin_lock_init(&blkif->blk_ring_lock); atomic_set(&blkif->refcnt, 1); init_waitqueue_head(&blkif->wq); + init_completion(&blkif->drain_complete); + atomic_set(&blkif->drain, 0); blkif->st_print = jiffies; init_waitqueue_head(&blkif->waiting_to_free); return blkif; } -static int map_frontend_page(struct xen_blkif *blkif, unsigned long shared_page) -{ - struct gnttab_map_grant_ref op; - - gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr, - GNTMAP_host_map, shared_page, blkif->domid); - - if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) - BUG(); - - if (op.status) { - DPRINTK("Grant table operation failure !\n"); - return op.status; - } - - blkif->shmem_ref = shared_page; - blkif->shmem_handle = op.handle; - - return 0; -} - -static void unmap_frontend_page(struct xen_blkif *blkif) -{ - struct gnttab_unmap_grant_ref op; - - gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr, - GNTMAP_host_map, blkif->shmem_handle); - - if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) - BUG(); -} - static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, unsigned int evtchn) { @@ -161,35 +131,29 @@ static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, if (blkif->irq) return 0; - blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE); - if (!blkif->blk_ring_area) - return -ENOMEM; - - err = map_frontend_page(blkif, shared_page); - if (err) { - free_vm_area(blkif->blk_ring_area); + err = xenbus_map_ring_valloc(blkif->be->dev, shared_page, &blkif->blk_ring); + if (err < 0) return err; - } switch (blkif->blk_protocol) { case BLKIF_PROTOCOL_NATIVE: { struct blkif_sring *sring; - sring = (struct blkif_sring *)blkif->blk_ring_area->addr; + sring = (struct blkif_sring *)blkif->blk_ring; BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE); break; } case BLKIF_PROTOCOL_X86_32: { struct blkif_x86_32_sring *sring_x86_32; - sring_x86_32 = (struct blkif_x86_32_sring *)blkif->blk_ring_area->addr; + sring_x86_32 = (struct blkif_x86_32_sring *)blkif->blk_ring; BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE); break; } case BLKIF_PROTOCOL_X86_64: { struct blkif_x86_64_sring *sring_x86_64; - sring_x86_64 = (struct blkif_x86_64_sring *)blkif->blk_ring_area->addr; + sring_x86_64 = (struct blkif_x86_64_sring *)blkif->blk_ring; BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE); break; } @@ -201,8 +165,7 @@ static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, xen_blkif_be_int, 0, "blkif-backend", blkif); if (err < 0) { - unmap_frontend_page(blkif); - free_vm_area(blkif->blk_ring_area); + xenbus_unmap_ring_vfree(blkif->be->dev, blkif->blk_ring); blkif->blk_rings.common.sring = NULL; return err; } @@ -228,8 +191,7 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif) } if (blkif->blk_rings.common.sring) { - unmap_frontend_page(blkif); - free_vm_area(blkif->blk_ring_area); + xenbus_unmap_ring_vfree(blkif->be->dev, blkif->blk_ring); blkif->blk_rings.common.sring = NULL; } } @@ -272,6 +234,7 @@ VBD_SHOW(oo_req, "%d\n", be->blkif->st_oo_req); VBD_SHOW(rd_req, "%d\n", be->blkif->st_rd_req); VBD_SHOW(wr_req, "%d\n", be->blkif->st_wr_req); VBD_SHOW(f_req, "%d\n", be->blkif->st_f_req); +VBD_SHOW(ds_req, "%d\n", be->blkif->st_ds_req); VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect); VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect); @@ -280,6 +243,7 @@ static struct attribute *xen_vbdstat_attrs[] = { &dev_attr_rd_req.attr, &dev_attr_wr_req.attr, &dev_attr_f_req.attr, + &dev_attr_ds_req.attr, &dev_attr_rd_sect.attr, &dev_attr_wr_sect.attr, NULL @@ -419,6 +383,73 @@ int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, return err; } +int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) +{ + struct xenbus_device *dev = be->dev; + struct xen_blkif *blkif = be->blkif; + char *type; + int err; + int state = 0; + + type = xenbus_read(XBT_NIL, dev->nodename, "type", NULL); + if (!IS_ERR(type)) { + if (strncmp(type, "file", 4) == 0) { + state = 1; + blkif->blk_backend_type = BLKIF_BACKEND_FILE; + } + if (strncmp(type, "phy", 3) == 0) { + struct block_device *bdev = be->blkif->vbd.bdev; + struct request_queue *q = bdev_get_queue(bdev); + if (blk_queue_discard(q)) { + err = xenbus_printf(xbt, dev->nodename, + "discard-granularity", "%u", + q->limits.discard_granularity); + if (err) { + xenbus_dev_fatal(dev, err, + "writing discard-granularity"); + goto kfree; + } + err = xenbus_printf(xbt, dev->nodename, + "discard-alignment", "%u", + q->limits.discard_alignment); + if (err) { + xenbus_dev_fatal(dev, err, + "writing discard-alignment"); + goto kfree; + } + state = 1; + blkif->blk_backend_type = BLKIF_BACKEND_PHY; + } + } + } else { + err = PTR_ERR(type); + xenbus_dev_fatal(dev, err, "reading type"); + goto out; + } + + err = xenbus_printf(xbt, dev->nodename, "feature-discard", + "%d", state); + if (err) + xenbus_dev_fatal(dev, err, "writing feature-discard"); +kfree: + kfree(type); +out: + return err; +} +int xen_blkbk_barrier(struct xenbus_transaction xbt, + struct backend_info *be, int state) +{ + struct xenbus_device *dev = be->dev; + int err; + + err = xenbus_printf(xbt, dev->nodename, "feature-barrier", + "%d", state); + if (err) + xenbus_dev_fatal(dev, err, "writing feature-barrier"); + + return err; +} + /* * Entry point to this code when a new device is created. Allocate the basic * structures, and watch the store waiting for the hotplug scripts to tell us @@ -650,6 +681,11 @@ again: if (err) goto abort; + err = xen_blkbk_discard(xbt, be); + + /* If we can't advertise it is OK. */ + err = xen_blkbk_barrier(xbt, be, be->blkif->vbd.flush_support); + err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu", (unsigned long long)vbd_sz(&be->blkif->vbd)); if (err) { diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 9ea8c2576c70..7b2ec5908413 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -98,6 +98,9 @@ struct blkfront_info unsigned long shadow_free; unsigned int feature_flush; unsigned int flush_op; + unsigned int feature_discard; + unsigned int discard_granularity; + unsigned int discard_alignment; int is_ready; }; @@ -302,29 +305,36 @@ static int blkif_queue_request(struct request *req) ring_req->operation = info->flush_op; } - ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg); - BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST); + if (unlikely(req->cmd_flags & REQ_DISCARD)) { + /* id, sector_number and handle are set above. */ + ring_req->operation = BLKIF_OP_DISCARD; + ring_req->nr_segments = 0; + ring_req->u.discard.nr_sectors = blk_rq_sectors(req); + } else { + ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg); + BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST); - for_each_sg(info->sg, sg, ring_req->nr_segments, i) { - buffer_mfn = pfn_to_mfn(page_to_pfn(sg_page(sg))); - fsect = sg->offset >> 9; - lsect = fsect + (sg->length >> 9) - 1; - /* install a grant reference. */ - ref = gnttab_claim_grant_reference(&gref_head); - BUG_ON(ref == -ENOSPC); + for_each_sg(info->sg, sg, ring_req->nr_segments, i) { + buffer_mfn = pfn_to_mfn(page_to_pfn(sg_page(sg))); + fsect = sg->offset >> 9; + lsect = fsect + (sg->length >> 9) - 1; + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&gref_head); + BUG_ON(ref == -ENOSPC); - gnttab_grant_foreign_access_ref( - ref, - info->xbdev->otherend_id, - buffer_mfn, - rq_data_dir(req) ); - - info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn); - ring_req->u.rw.seg[i] = - (struct blkif_request_segment) { - .gref = ref, - .first_sect = fsect, - .last_sect = lsect }; + gnttab_grant_foreign_access_ref( + ref, + info->xbdev->otherend_id, + buffer_mfn, + rq_data_dir(req)); + + info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn); + ring_req->u.rw.seg[i] = + (struct blkif_request_segment) { + .gref = ref, + .first_sect = fsect, + .last_sect = lsect }; + } } info->ring.req_prod_pvt++; @@ -370,7 +380,9 @@ static void do_blkif_request(struct request_queue *rq) blk_start_request(req); - if (req->cmd_type != REQ_TYPE_FS) { + if ((req->cmd_type != REQ_TYPE_FS) || + ((req->cmd_flags & (REQ_FLUSH | REQ_FUA)) && + !info->flush_op)) { __blk_end_request_all(req, -EIO); continue; } @@ -399,6 +411,7 @@ wait: static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) { struct request_queue *rq; + struct blkfront_info *info = gd->private_data; rq = blk_init_queue(do_blkif_request, &blkif_io_lock); if (rq == NULL) @@ -406,6 +419,13 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) queue_flag_set_unlocked(QUEUE_FLAG_VIRT, rq); + if (info->feature_discard) { + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, rq); + blk_queue_max_discard_sectors(rq, get_capacity(gd)); + rq->limits.discard_granularity = info->discard_granularity; + rq->limits.discard_alignment = info->discard_alignment; + } + /* Hard sector size and max sectors impersonate the equiv. hardware. */ blk_queue_logical_block_size(rq, sector_size); blk_queue_max_hw_sectors(rq, 512); @@ -722,6 +742,17 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO; switch (bret->operation) { + case BLKIF_OP_DISCARD: + if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { + struct request_queue *rq = info->rq; + printk(KERN_WARNING "blkfront: %s: discard op failed\n", + info->gd->disk_name); + error = -EOPNOTSUPP; + info->feature_discard = 0; + queue_flag_clear(QUEUE_FLAG_DISCARD, rq); + } + __blk_end_request_all(req, error); + break; case BLKIF_OP_FLUSH_DISKCACHE: case BLKIF_OP_WRITE_BARRIER: if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { @@ -1098,6 +1129,33 @@ blkfront_closing(struct blkfront_info *info) bdput(bdev); } +static void blkfront_setup_discard(struct blkfront_info *info) +{ + int err; + char *type; + unsigned int discard_granularity; + unsigned int discard_alignment; + + type = xenbus_read(XBT_NIL, info->xbdev->otherend, "type", NULL); + if (IS_ERR(type)) + return; + + if (strncmp(type, "phy", 3) == 0) { + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "discard-granularity", "%u", &discard_granularity, + "discard-alignment", "%u", &discard_alignment, + NULL); + if (!err) { + info->feature_discard = 1; + info->discard_granularity = discard_granularity; + info->discard_alignment = discard_alignment; + } + } else if (strncmp(type, "file", 4) == 0) + info->feature_discard = 1; + + kfree(type); +} + /* * Invoked when the backend is finally 'ready' (and has told produced * the details about the physical device - #sectors, size, etc). @@ -1108,7 +1166,7 @@ static void blkfront_connect(struct blkfront_info *info) unsigned long sector_size; unsigned int binfo; int err; - int barrier, flush; + int barrier, flush, discard; switch (info->connected) { case BLKIF_STATE_CONNECTED: @@ -1178,7 +1236,14 @@ static void blkfront_connect(struct blkfront_info *info) info->feature_flush = REQ_FLUSH; info->flush_op = BLKIF_OP_FLUSH_DISKCACHE; } - + + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "feature-discard", "%d", &discard, + NULL); + + if (!err && discard) + blkfront_setup_discard(info); + err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size); if (err) { xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s", @@ -1385,6 +1450,8 @@ static struct xenbus_driver blkfront = { static int __init xlblk_init(void) { + int ret; + if (!xen_domain()) return -ENODEV; @@ -1394,7 +1461,13 @@ static int __init xlblk_init(void) return -ENODEV; } - return xenbus_register_frontend(&blkfront); + ret = xenbus_register_frontend(&blkfront); + if (ret) { + unregister_blkdev(XENVBD_MAJOR, DEV_NAME); + return ret; + } + + return 0; } module_init(xlblk_init); diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 548d1d9e4dda..a88a78c86162 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -18,6 +18,8 @@ * this warranty disclaimer. **/ +#include <linux/module.h> + #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index c827d737ccee..9ef48167e2cf 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -23,6 +23,7 @@ #include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio_func.h> +#include <linux/module.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index 04d353f58d71..b5f83b44a0cd 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -29,6 +29,7 @@ #include <net/bluetooth/hci.h> #include <linux/ti_wilink_st.h> +#include <linux/module.h> /* Bluetooth Driver Version */ #define VERSION "1.0" diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 75f1cbd61c17..fd699ccecf5b 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -23,6 +23,7 @@ #include <linux/spinlock.h> #include <linux/virtio.h> #include <linux/virtio_rng.h> +#include <linux/module.h> static struct virtqueue *vq; static unsigned int data_avail; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 8fc04b4f311f..145179033716 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -26,6 +26,7 @@ #include <linux/bootmem.h> #include <linux/splice.h> #include <linux/pfn.h> +#include <linux/export.h> #include <asm/uaccess.h> #include <asm/io.h> diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index d0c57c2e2909..6abdde4da2b7 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -22,6 +22,7 @@ #include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/uaccess.h> +#include <linux/module.h> #include <asm/lv1call.h> #include <asm/ps3stor.h> diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c index 810aff9e750f..7c7f42a1f880 100644 --- a/drivers/char/ramoops.c +++ b/drivers/char/ramoops.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/kmsg_dump.h> #include <linux/time.h> +#include <linux/err.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/platform_device.h> diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index f22861511909..eedd5474850c 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -17,6 +17,7 @@ #include <linux/device.h> #include <linux/serial.h> #include <linux/tty.h> +#include <linux/export.h> struct ttyprintk_port { struct tty_port port; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 4ca181f1378b..8e3c46d67cb3 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -34,6 +34,7 @@ #include <linux/virtio_console.h> #include <linux/wait.h> #include <linux/workqueue.h> +#include <linux/module.h> #include "../tty/hvc/hvc_console.h" /* diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 32a77becc098..ca09bc421ddb 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -31,6 +31,7 @@ #include <linux/clockchips.h> #include <linux/sh_timer.h> #include <linux/slab.h> +#include <linux/module.h> struct sh_cmt_priv { void __iomem *mapbase; diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 40630cb98237..db8d5955bad4 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -30,6 +30,7 @@ #include <linux/clockchips.h> #include <linux/sh_timer.h> #include <linux/slab.h> +#include <linux/module.h> struct sh_mtu2_priv { void __iomem *mapbase; diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 808135768617..079e96ad44e8 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -31,6 +31,7 @@ #include <linux/clockchips.h> #include <linux/sh_timer.h> #include <linux/slab.h> +#include <linux/module.h> struct sh_tmu_priv { void __iomem *mapbase; diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index faf7c5217848..c5072a91e848 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -15,6 +15,7 @@ #include <linux/cpu.h> #include <linux/sysfs.h> #include <linux/cpufreq.h> +#include <linux/module.h> #include <linux/jiffies.h> #include <linux/percpu.h> #include <linux/kobject.h> diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index b8d1d205e1ef..3475f65aeec6 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -15,6 +15,7 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/regulator/consumer.h> +#include <linux/module.h> static struct clk *armclk; static struct regulator *vddarm; diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 0df014110097..06ce2680d00d 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -17,6 +17,7 @@ #include <linux/cpuidle.h> #include <linux/ktime.h> #include <linux/hrtimer.h> +#include <linux/module.h> #include <trace/events/power.h> #include "cpuidle.h" @@ -61,8 +62,9 @@ static int __cpuidle_register_device(struct cpuidle_device *dev); int cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); + struct cpuidle_driver *drv = cpuidle_get_driver(); struct cpuidle_state *target_state; - int next_state; + int next_state, entered_state; if (off) return -ENODEV; @@ -83,45 +85,36 @@ int cpuidle_idle_call(void) hrtimer_peek_ahead_timers(); #endif - /* - * Call the device's prepare function before calling the - * governor's select function. ->prepare gives the device's - * cpuidle driver a chance to update any dynamic information - * of its cpuidle states for the current idle period, e.g. - * state availability, latencies, residencies, etc. - */ - if (dev->prepare) - dev->prepare(dev); - /* ask the governor for the next state */ - next_state = cpuidle_curr_governor->select(dev); + next_state = cpuidle_curr_governor->select(drv, dev); if (need_resched()) { local_irq_enable(); return 0; } - target_state = &dev->states[next_state]; - - /* enter the state and update stats */ - dev->last_state = target_state; + target_state = &drv->states[next_state]; trace_power_start(POWER_CSTATE, next_state, dev->cpu); trace_cpu_idle(next_state, dev->cpu); - dev->last_residency = target_state->enter(dev, target_state); + entered_state = target_state->enter(dev, drv, next_state); trace_power_end(dev->cpu); trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); - if (dev->last_state) - target_state = dev->last_state; - - target_state->time += (unsigned long long)dev->last_residency; - target_state->usage++; + if (entered_state >= 0) { + /* Update cpuidle counters */ + /* This can be moved to within driver enter routine + * but that results in multiple copies of same code. + */ + dev->states_usage[entered_state].time += + (unsigned long long)dev->last_residency; + dev->states_usage[entered_state].usage++; + } /* give the governor an opportunity to reflect on the outcome */ if (cpuidle_curr_governor->reflect) - cpuidle_curr_governor->reflect(dev); + cpuidle_curr_governor->reflect(dev, entered_state); return 0; } @@ -172,11 +165,11 @@ void cpuidle_resume_and_unlock(void) EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); #ifdef CONFIG_ARCH_HAS_CPU_RELAX -static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) +static int poll_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { ktime_t t1, t2; s64 diff; - int ret; t1 = ktime_get(); local_irq_enable(); @@ -188,15 +181,14 @@ static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) if (diff > INT_MAX) diff = INT_MAX; - ret = (int) diff; - return ret; + dev->last_residency = (int) diff; + + return index; } -static void poll_idle_init(struct cpuidle_device *dev) +static void poll_idle_init(struct cpuidle_driver *drv) { - struct cpuidle_state *state = &dev->states[0]; - - cpuidle_set_statedata(state, NULL); + struct cpuidle_state *state = &drv->states[0]; snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); @@ -207,7 +199,7 @@ static void poll_idle_init(struct cpuidle_device *dev) state->enter = poll_idle; } #else -static void poll_idle_init(struct cpuidle_device *dev) {} +static void poll_idle_init(struct cpuidle_driver *drv) {} #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ /** @@ -234,21 +226,20 @@ int cpuidle_enable_device(struct cpuidle_device *dev) return ret; } - poll_idle_init(dev); + poll_idle_init(cpuidle_get_driver()); if ((ret = cpuidle_add_state_sysfs(dev))) return ret; if (cpuidle_curr_governor->enable && - (ret = cpuidle_curr_governor->enable(dev))) + (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) goto fail_sysfs; for (i = 0; i < dev->state_count; i++) { - dev->states[i].usage = 0; - dev->states[i].time = 0; + dev->states_usage[i].usage = 0; + dev->states_usage[i].time = 0; } dev->last_residency = 0; - dev->last_state = NULL; smp_wmb(); @@ -282,7 +273,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev) dev->enabled = 0; if (cpuidle_curr_governor->disable) - cpuidle_curr_governor->disable(dev); + cpuidle_curr_governor->disable(cpuidle_get_driver(), dev); cpuidle_remove_state_sysfs(dev); enabled_devices--; @@ -310,26 +301,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) init_completion(&dev->kobj_unregister); - /* - * cpuidle driver should set the dev->power_specified bit - * before registering the device if the driver provides - * power_usage numbers. - * - * For those devices whose ->power_specified is not set, - * we fill in power_usage with decreasing values as the - * cpuidle code has an implicit assumption that state Cn - * uses less power than C(n-1). - * - * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned - * an power value of -1. So we use -2, -3, etc, for other - * c-states. - */ - if (!dev->power_specified) { - int i; - for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) - dev->states[i].power_usage = -1 - i; - } - per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); if ((ret = cpuidle_add_sysfs(sys_dev))) { diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 3f7e3cedd133..284d7af5a9c8 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -17,6 +17,30 @@ static struct cpuidle_driver *cpuidle_curr_driver; DEFINE_SPINLOCK(cpuidle_driver_lock); +static void __cpuidle_register_driver(struct cpuidle_driver *drv) +{ + int i; + /* + * cpuidle driver should set the drv->power_specified bit + * before registering if the driver provides + * power_usage numbers. + * + * If power_specified is not set, + * we fill in power_usage with decreasing values as the + * cpuidle code has an implicit assumption that state Cn + * uses less power than C(n-1). + * + * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned + * an power value of -1. So we use -2, -3, etc, for other + * c-states. + */ + if (!drv->power_specified) { + for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) + drv->states[i].power_usage = -1 - i; + } +} + + /** * cpuidle_register_driver - registers a driver * @drv: the driver @@ -34,6 +58,7 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) spin_unlock(&cpuidle_driver_lock); return -EBUSY; } + __cpuidle_register_driver(drv); cpuidle_curr_driver = drv; spin_unlock(&cpuidle_driver_lock); diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index f62fde21e962..b6a09ea859b1 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -15,7 +15,7 @@ #include <linux/kernel.h> #include <linux/cpuidle.h> #include <linux/pm_qos.h> -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/jiffies.h> #include <asm/io.h> @@ -60,9 +60,11 @@ static inline void ladder_do_selection(struct ladder_device *ldev, /** * ladder_select_state - selects the next state to enter + * @drv: cpuidle driver * @dev: the CPU */ -static int ladder_select_state(struct cpuidle_device *dev) +static int ladder_select_state(struct cpuidle_driver *drv, + struct cpuidle_device *dev) { struct ladder_device *ldev = &__get_cpu_var(ladder_devices); struct ladder_device_state *last_state; @@ -77,15 +79,17 @@ static int ladder_select_state(struct cpuidle_device *dev) last_state = &ldev->states[last_idx]; - if (dev->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) - last_residency = cpuidle_get_last_residency(dev) - dev->states[last_idx].exit_latency; + if (drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) { + last_residency = cpuidle_get_last_residency(dev) - \ + drv->states[last_idx].exit_latency; + } else last_residency = last_state->threshold.promotion_time + 1; /* consider promotion */ - if (last_idx < dev->state_count - 1 && + if (last_idx < drv->state_count - 1 && last_residency > last_state->threshold.promotion_time && - dev->states[last_idx + 1].exit_latency <= latency_req) { + drv->states[last_idx + 1].exit_latency <= latency_req) { last_state->stats.promotion_count++; last_state->stats.demotion_count = 0; if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) { @@ -96,11 +100,11 @@ static int ladder_select_state(struct cpuidle_device *dev) /* consider demotion */ if (last_idx > CPUIDLE_DRIVER_STATE_START && - dev->states[last_idx].exit_latency > latency_req) { + drv->states[last_idx].exit_latency > latency_req) { int i; for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) { - if (dev->states[i].exit_latency <= latency_req) + if (drv->states[i].exit_latency <= latency_req) break; } ladder_do_selection(ldev, last_idx, i); @@ -123,9 +127,11 @@ static int ladder_select_state(struct cpuidle_device *dev) /** * ladder_enable_device - setup for the governor + * @drv: cpuidle driver * @dev: the CPU */ -static int ladder_enable_device(struct cpuidle_device *dev) +static int ladder_enable_device(struct cpuidle_driver *drv, + struct cpuidle_device *dev) { int i; struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu); @@ -134,8 +140,8 @@ static int ladder_enable_device(struct cpuidle_device *dev) ldev->last_state_idx = CPUIDLE_DRIVER_STATE_START; - for (i = 0; i < dev->state_count; i++) { - state = &dev->states[i]; + for (i = 0; i < drv->state_count; i++) { + state = &drv->states[i]; lstate = &ldev->states[i]; lstate->stats.promotion_count = 0; @@ -144,7 +150,7 @@ static int ladder_enable_device(struct cpuidle_device *dev) lstate->threshold.promotion_count = PROMOTION_COUNT; lstate->threshold.demotion_count = DEMOTION_COUNT; - if (i < dev->state_count - 1) + if (i < drv->state_count - 1) lstate->threshold.promotion_time = state->exit_latency; if (i > 0) lstate->threshold.demotion_time = state->exit_latency; @@ -153,11 +159,24 @@ static int ladder_enable_device(struct cpuidle_device *dev) return 0; } +/** + * ladder_reflect - update the correct last_state_idx + * @dev: the CPU + * @index: the index of actual state entered + */ +static void ladder_reflect(struct cpuidle_device *dev, int index) +{ + struct ladder_device *ldev = &__get_cpu_var(ladder_devices); + if (index > 0) + ldev->last_state_idx = index; +} + static struct cpuidle_governor ladder_governor = { .name = "ladder", .rating = 10, .enable = ladder_enable_device, .select = ladder_select_state, + .reflect = ladder_reflect, .owner = THIS_MODULE, }; diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 3600f1955e48..ad0952601ae2 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -19,6 +19,7 @@ #include <linux/tick.h> #include <linux/sched.h> #include <linux/math64.h> +#include <linux/module.h> #define BUCKETS 12 #define INTERVALS 8 @@ -182,7 +183,7 @@ static inline int performance_multiplier(void) static DEFINE_PER_CPU(struct menu_device, menu_devices); -static void menu_update(struct cpuidle_device *dev); +static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev); /* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */ static u64 div_round64(u64 dividend, u32 divisor) @@ -228,9 +229,10 @@ static void detect_repeating_patterns(struct menu_device *data) /** * menu_select - selects the next idle state to enter + * @drv: cpuidle driver containing state data * @dev: the CPU */ -static int menu_select(struct cpuidle_device *dev) +static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); @@ -240,7 +242,7 @@ static int menu_select(struct cpuidle_device *dev) struct timespec t; if (data->needs_update) { - menu_update(dev); + menu_update(drv, dev); data->needs_update = 0; } @@ -285,11 +287,9 @@ static int menu_select(struct cpuidle_device *dev) * Find the idle state with the lowest power while satisfying * our constraints. */ - for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { - struct cpuidle_state *s = &dev->states[i]; + for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { + struct cpuidle_state *s = &drv->states[i]; - if (s->flags & CPUIDLE_FLAG_IGNORE) - continue; if (s->target_residency > data->predicted_us) continue; if (s->exit_latency > latency_req) @@ -310,26 +310,30 @@ static int menu_select(struct cpuidle_device *dev) /** * menu_reflect - records that data structures need update * @dev: the CPU + * @index: the index of actual entered state * * NOTE: it's important to be fast here because this operation will add to * the overall exit latency. */ -static void menu_reflect(struct cpuidle_device *dev) +static void menu_reflect(struct cpuidle_device *dev, int index) { struct menu_device *data = &__get_cpu_var(menu_devices); - data->needs_update = 1; + data->last_state_idx = index; + if (index >= 0) + data->needs_update = 1; } /** * menu_update - attempts to guess what happened after entry + * @drv: cpuidle driver containing state data * @dev: the CPU */ -static void menu_update(struct cpuidle_device *dev) +static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int last_idx = data->last_state_idx; unsigned int last_idle_us = cpuidle_get_last_residency(dev); - struct cpuidle_state *target = &dev->states[last_idx]; + struct cpuidle_state *target = &drv->states[last_idx]; unsigned int measured_us; u64 new_factor; @@ -383,9 +387,11 @@ static void menu_update(struct cpuidle_device *dev) /** * menu_enable_device - scans a CPU's states and does setup + * @drv: cpuidle driver * @dev: the CPU */ -static int menu_enable_device(struct cpuidle_device *dev) +static int menu_enable_device(struct cpuidle_driver *drv, + struct cpuidle_device *dev) { struct menu_device *data = &per_cpu(menu_devices, dev->cpu); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index be7917ec40c9..1e756e160dca 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -216,7 +216,8 @@ static struct kobj_type ktype_cpuidle = { struct cpuidle_state_attr { struct attribute attr; - ssize_t (*show)(struct cpuidle_state *, char *); + ssize_t (*show)(struct cpuidle_state *, \ + struct cpuidle_state_usage *, char *); ssize_t (*store)(struct cpuidle_state *, const char *, size_t); }; @@ -224,19 +225,22 @@ struct cpuidle_state_attr { static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL) #define define_show_state_function(_name) \ -static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, \ + struct cpuidle_state_usage *state_usage, char *buf) \ { \ return sprintf(buf, "%u\n", state->_name);\ } #define define_show_state_ull_function(_name) \ -static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, \ + struct cpuidle_state_usage *state_usage, char *buf) \ { \ - return sprintf(buf, "%llu\n", state->_name);\ + return sprintf(buf, "%llu\n", state_usage->_name);\ } #define define_show_state_str_function(_name) \ -static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, \ + struct cpuidle_state_usage *state_usage, char *buf) \ { \ if (state->_name[0] == '\0')\ return sprintf(buf, "<null>\n");\ @@ -269,16 +273,18 @@ static struct attribute *cpuidle_state_default_attrs[] = { #define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj) #define kobj_to_state(k) (kobj_to_state_obj(k)->state) +#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr) static ssize_t cpuidle_state_show(struct kobject * kobj, struct attribute * attr ,char * buf) { int ret = -EIO; struct cpuidle_state *state = kobj_to_state(kobj); + struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj); struct cpuidle_state_attr * cattr = attr_to_stateattr(attr); if (cattr->show) - ret = cattr->show(state, buf); + ret = cattr->show(state, state_usage, buf); return ret; } @@ -316,13 +322,15 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) { int i, ret = -ENOMEM; struct cpuidle_state_kobj *kobj; + struct cpuidle_driver *drv = cpuidle_get_driver(); /* state statistics */ for (i = 0; i < device->state_count; i++) { kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); if (!kobj) goto error_state; - kobj->state = &device->states[i]; + kobj->state = &drv->states[i]; + kobj->state_usage = &device->states_usage[i]; init_completion(&kobj->kobj_unregister); ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj, diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 3cf303ee3fe3..5c6f56f21443 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/scatterlist.h> #include <linux/slab.h> +#include <linux/module.h> #include <crypto/internal/hash.h> #include <crypto/sha.h> diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index 25ec0bb05198..bc6f5faa1e9e 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c @@ -28,6 +28,7 @@ #include <linux/device.h> #include <linux/dca.h> #include <linux/slab.h> +#include <linux/module.h> #define DCA_VERSION "1.12.1" diff --git a/drivers/dca/dca-sysfs.c b/drivers/dca/dca-sysfs.c index 5e8f335e6f6e..591b6597c00a 100644 --- a/drivers/dca/dca-sysfs.c +++ b/drivers/dca/dca-sysfs.c @@ -27,6 +27,7 @@ #include <linux/err.h> #include <linux/dca.h> #include <linux/gfp.h> +#include <linux/export.h> static struct class *dca_class; static struct idr dca_idr; diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 2e3b3d38c465..ab8f469f5cf8 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -193,7 +193,8 @@ config ARCH_HAS_ASYNC_TX_FIND_CHANNEL config PL330_DMA tristate "DMA API Driver for PL330" select DMA_ENGINE - depends on PL330 + depends on ARM_AMBA + select PL330 help Select if your platform has one or more PL330 DMACs. You need to provide platform specific settings via diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index be21e3f138a8..b7cbd1ab1db1 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -66,32 +66,29 @@ * after the final transfer signalled by LBREQ or LSREQ. The DMAC * will then move to the next LLI entry. * - * Only the former works sanely with scatter lists, so we only implement - * the DMAC flow control method. However, peripherals which use the LBREQ - * and LSREQ signals (eg, MMCI) are unable to use this mode, which through - * these hardware restrictions prevents them from using scatter DMA. - * * Global TODO: * - Break out common code from arch/arm/mach-s3c64xx and share */ -#include <linux/device.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/dmapool.h> -#include <linux/dmaengine.h> #include <linux/amba/bus.h> #include <linux/amba/pl08x.h> #include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dmaengine.h> +#include <linux/dmapool.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> #include <linux/seq_file.h> - +#include <linux/slab.h> #include <asm/hardware/pl080.h> #define DRIVER_NAME "pl08xdmac" +static struct amba_driver pl08x_amba_driver; + /** * struct vendor_data - vendor-specific config parameters for PL08x derivatives * @channels: the number of channels available in this variant @@ -126,7 +123,8 @@ struct pl08x_lli { * @phy_chans: array of data for the physical channels * @pool: a pool for the LLI descriptors * @pool_ctr: counter of LLIs in the pool - * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI fetches + * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI + * fetches * @mem_buses: set to indicate memory transfers on AHB2. * @lock: a spinlock for this struct */ @@ -149,14 +147,6 @@ struct pl08x_driver_data { * PL08X specific defines */ -/* - * Memory boundaries: the manual for PL08x says that the controller - * cannot read past a 1KiB boundary, so these defines are used to - * create transfer LLIs that do not cross such boundaries. - */ -#define PL08X_BOUNDARY_SHIFT (10) /* 1KB 0x400 */ -#define PL08X_BOUNDARY_SIZE (1 << PL08X_BOUNDARY_SHIFT) - /* Size (bytes) of each LLI buffer allocated for one transfer */ # define PL08X_LLI_TSFR_SIZE 0x2000 @@ -272,7 +262,6 @@ static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch) writel(val, ch->base + PL080_CH_CONFIG); } - /* * pl08x_terminate_phy_chan() stops the channel, clears the FIFO and * clears any pending interrupt status. This should not be used for @@ -363,7 +352,9 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) if (!list_empty(&plchan->pend_list)) { struct pl08x_txd *txdi; list_for_each_entry(txdi, &plchan->pend_list, node) { - bytes += txdi->len; + struct pl08x_sg *dsg; + list_for_each_entry(dsg, &txd->dsg_list, node) + bytes += dsg->len; } } @@ -407,6 +398,7 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, return NULL; } + pm_runtime_get_sync(&pl08x->adev->dev); return ch; } @@ -420,6 +412,8 @@ static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x, /* Stop the channel and clear its interrupts */ pl08x_terminate_phy_chan(pl08x, ch); + pm_runtime_put(&pl08x->adev->dev); + /* Mark it as free */ ch->serving = NULL; spin_unlock_irqrestore(&ch->lock, flags); @@ -499,36 +493,30 @@ struct pl08x_lli_build_data { }; /* - * Autoselect a master bus to use for the transfer this prefers the - * destination bus if both available if fixed address on one bus the - * other will be chosen + * Autoselect a master bus to use for the transfer. Slave will be the chosen as + * victim in case src & dest are not similarly aligned. i.e. If after aligning + * masters address with width requirements of transfer (by sending few byte by + * byte data), slave is still not aligned, then its width will be reduced to + * BYTE. + * - prefers the destination bus if both available + * - prefers bus with fixed address (i.e. peripheral) */ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd, struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl) { if (!(cctl & PL080_CONTROL_DST_INCR)) { - *mbus = &bd->srcbus; - *sbus = &bd->dstbus; - } else if (!(cctl & PL080_CONTROL_SRC_INCR)) { *mbus = &bd->dstbus; *sbus = &bd->srcbus; + } else if (!(cctl & PL080_CONTROL_SRC_INCR)) { + *mbus = &bd->srcbus; + *sbus = &bd->dstbus; } else { - if (bd->dstbus.buswidth == 4) { + if (bd->dstbus.buswidth >= bd->srcbus.buswidth) { *mbus = &bd->dstbus; *sbus = &bd->srcbus; - } else if (bd->srcbus.buswidth == 4) { - *mbus = &bd->srcbus; - *sbus = &bd->dstbus; - } else if (bd->dstbus.buswidth == 2) { - *mbus = &bd->dstbus; - *sbus = &bd->srcbus; - } else if (bd->srcbus.buswidth == 2) { + } else { *mbus = &bd->srcbus; *sbus = &bd->dstbus; - } else { - /* bd->srcbus.buswidth == 1 */ - *mbus = &bd->dstbus; - *sbus = &bd->srcbus; } } } @@ -547,7 +535,8 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, llis_va[num_llis].cctl = cctl; llis_va[num_llis].src = bd->srcbus.addr; llis_va[num_llis].dst = bd->dstbus.addr; - llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); + llis_va[num_llis].lli = llis_bus + (num_llis + 1) * + sizeof(struct pl08x_lli); llis_va[num_llis].lli |= bd->lli_bus; if (cctl & PL080_CONTROL_SRC_INCR) @@ -560,16 +549,12 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, bd->remainder -= len; } -/* - * Return number of bytes to fill to boundary, or len. - * This calculation works for any value of addr. - */ -static inline size_t pl08x_pre_boundary(u32 addr, size_t len) +static inline void prep_byte_width_lli(struct pl08x_lli_build_data *bd, + u32 *cctl, u32 len, int num_llis, size_t *total_bytes) { - size_t boundary_len = PL08X_BOUNDARY_SIZE - - (addr & (PL08X_BOUNDARY_SIZE - 1)); - - return min(boundary_len, len); + *cctl = pl08x_cctl_bits(*cctl, 1, 1, len); + pl08x_fill_lli_for_desc(bd, num_llis, len, *cctl); + (*total_bytes) += len; } /* @@ -583,13 +568,12 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_bus_data *mbus, *sbus; struct pl08x_lli_build_data bd; int num_llis = 0; - u32 cctl; - size_t max_bytes_per_lli; - size_t total_bytes = 0; + u32 cctl, early_bytes = 0; + size_t max_bytes_per_lli, total_bytes; struct pl08x_lli *llis_va; + struct pl08x_sg *dsg; - txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, - &txd->llis_bus); + txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus); if (!txd->llis_va) { dev_err(&pl08x->adev->dev, "%s no memory for llis\n", __func__); return 0; @@ -597,13 +581,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, pl08x->pool_ctr++; - /* Get the default CCTL */ - cctl = txd->cctl; - bd.txd = txd; - bd.srcbus.addr = txd->src_addr; - bd.dstbus.addr = txd->dst_addr; bd.lli_bus = (pl08x->lli_buses & PL08X_AHB2) ? PL080_LLI_LM_AHB2 : 0; + cctl = txd->cctl; /* Find maximum width of the source bus */ bd.srcbus.maxwidth = @@ -615,215 +595,179 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >> PL080_CONTROL_DWIDTH_SHIFT); - /* Set up the bus widths to the maximum */ - bd.srcbus.buswidth = bd.srcbus.maxwidth; - bd.dstbus.buswidth = bd.dstbus.maxwidth; + list_for_each_entry(dsg, &txd->dsg_list, node) { + total_bytes = 0; + cctl = txd->cctl; - /* - * Bytes transferred == tsize * MIN(buswidths), not max(buswidths) - */ - max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) * - PL080_CONTROL_TRANSFER_SIZE_MASK; + bd.srcbus.addr = dsg->src_addr; + bd.dstbus.addr = dsg->dst_addr; + bd.remainder = dsg->len; + bd.srcbus.buswidth = bd.srcbus.maxwidth; + bd.dstbus.buswidth = bd.dstbus.maxwidth; - /* We need to count this down to zero */ - bd.remainder = txd->len; + pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); - /* - * Choose bus to align to - * - prefers destination bus if both available - * - if fixed address on one bus chooses other - */ - pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); - - dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu llimax=%zu\n", - bd.srcbus.addr, cctl & PL080_CONTROL_SRC_INCR ? "+" : "", - bd.srcbus.buswidth, - bd.dstbus.addr, cctl & PL080_CONTROL_DST_INCR ? "+" : "", - bd.dstbus.buswidth, - bd.remainder, max_bytes_per_lli); - dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n", - mbus == &bd.srcbus ? "src" : "dst", - sbus == &bd.srcbus ? "src" : "dst"); - - if (txd->len < mbus->buswidth) { - /* Less than a bus width available - send as single bytes */ - while (bd.remainder) { - dev_vdbg(&pl08x->adev->dev, - "%s single byte LLIs for a transfer of " - "less than a bus width (remain 0x%08x)\n", - __func__, bd.remainder); - cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); - total_bytes++; - } - } else { - /* Make one byte LLIs until master bus is aligned */ - while ((mbus->addr) % (mbus->buswidth)) { - dev_vdbg(&pl08x->adev->dev, - "%s adjustment lli for less than bus width " - "(remain 0x%08x)\n", - __func__, bd.remainder); - cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); - total_bytes++; - } + dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu\n", + bd.srcbus.addr, cctl & PL080_CONTROL_SRC_INCR ? "+" : "", + bd.srcbus.buswidth, + bd.dstbus.addr, cctl & PL080_CONTROL_DST_INCR ? "+" : "", + bd.dstbus.buswidth, + bd.remainder); + dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n", + mbus == &bd.srcbus ? "src" : "dst", + sbus == &bd.srcbus ? "src" : "dst"); /* - * Master now aligned - * - if slave is not then we must set its width down + * Zero length is only allowed if all these requirements are + * met: + * - flow controller is peripheral. + * - src.addr is aligned to src.width + * - dst.addr is aligned to dst.width + * + * sg_len == 1 should be true, as there can be two cases here: + * + * - Memory addresses are contiguous and are not scattered. + * Here, Only one sg will be passed by user driver, with + * memory address and zero length. We pass this to controller + * and after the transfer it will receive the last burst + * request from peripheral and so transfer finishes. + * + * - Memory addresses are scattered and are not contiguous. + * Here, Obviously as DMA controller doesn't know when a lli's + * transfer gets over, it can't load next lli. So in this + * case, there has to be an assumption that only one lli is + * supported. Thus, we can't have scattered addresses. */ - if (sbus->addr % sbus->buswidth) { - dev_dbg(&pl08x->adev->dev, - "%s set down bus width to one byte\n", - __func__); + if (!bd.remainder) { + u32 fc = (txd->ccfg & PL080_CONFIG_FLOW_CONTROL_MASK) >> + PL080_CONFIG_FLOW_CONTROL_SHIFT; + if (!((fc >= PL080_FLOW_SRC2DST_DST) && + (fc <= PL080_FLOW_SRC2DST_SRC))) { + dev_err(&pl08x->adev->dev, "%s sg len can't be zero", + __func__); + return 0; + } + + if ((bd.srcbus.addr % bd.srcbus.buswidth) || + (bd.srcbus.addr % bd.srcbus.buswidth)) { + dev_err(&pl08x->adev->dev, + "%s src & dst address must be aligned to src" + " & dst width if peripheral is flow controller", + __func__); + return 0; + } - sbus->buswidth = 1; + cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth, + bd.dstbus.buswidth, 0); + pl08x_fill_lli_for_desc(&bd, num_llis++, 0, cctl); + break; } /* - * Make largest possible LLIs until less than one bus - * width left + * Send byte by byte for following cases + * - Less than a bus width available + * - until master bus is aligned */ - while (bd.remainder > (mbus->buswidth - 1)) { - size_t lli_len, target_len, tsize, odd_bytes; + if (bd.remainder < mbus->buswidth) + early_bytes = bd.remainder; + else if ((mbus->addr) % (mbus->buswidth)) { + early_bytes = mbus->buswidth - (mbus->addr) % + (mbus->buswidth); + if ((bd.remainder - early_bytes) < mbus->buswidth) + early_bytes = bd.remainder; + } + if (early_bytes) { + dev_vdbg(&pl08x->adev->dev, + "%s byte width LLIs (remain 0x%08x)\n", + __func__, bd.remainder); + prep_byte_width_lli(&bd, &cctl, early_bytes, num_llis++, + &total_bytes); + } + + if (bd.remainder) { /* - * If enough left try to send max possible, - * otherwise try to send the remainder + * Master now aligned + * - if slave is not then we must set its width down */ - target_len = min(bd.remainder, max_bytes_per_lli); + if (sbus->addr % sbus->buswidth) { + dev_dbg(&pl08x->adev->dev, + "%s set down bus width to one byte\n", + __func__); + + sbus->buswidth = 1; + } /* - * Set bus lengths for incrementing buses to the - * number of bytes which fill to next memory boundary, - * limiting on the target length calculated above. + * Bytes transferred = tsize * src width, not + * MIN(buswidths) */ - if (cctl & PL080_CONTROL_SRC_INCR) - bd.srcbus.fill_bytes = - pl08x_pre_boundary(bd.srcbus.addr, - target_len); - else - bd.srcbus.fill_bytes = target_len; - - if (cctl & PL080_CONTROL_DST_INCR) - bd.dstbus.fill_bytes = - pl08x_pre_boundary(bd.dstbus.addr, - target_len); - else - bd.dstbus.fill_bytes = target_len; - - /* Find the nearest */ - lli_len = min(bd.srcbus.fill_bytes, - bd.dstbus.fill_bytes); - - BUG_ON(lli_len > bd.remainder); - - if (lli_len <= 0) { - dev_err(&pl08x->adev->dev, - "%s lli_len is %zu, <= 0\n", - __func__, lli_len); - return 0; - } + max_bytes_per_lli = bd.srcbus.buswidth * + PL080_CONTROL_TRANSFER_SIZE_MASK; + dev_vdbg(&pl08x->adev->dev, + "%s max bytes per lli = %zu\n", + __func__, max_bytes_per_lli); + + /* + * Make largest possible LLIs until less than one bus + * width left + */ + while (bd.remainder > (mbus->buswidth - 1)) { + size_t lli_len, tsize, width; - if (lli_len == target_len) { - /* - * Can send what we wanted. - * Maintain alignment - */ - lli_len = (lli_len/mbus->buswidth) * - mbus->buswidth; - odd_bytes = 0; - } else { /* - * So now we know how many bytes to transfer - * to get to the nearest boundary. The next - * LLI will past the boundary. However, we - * may be working to a boundary on the slave - * bus. We need to ensure the master stays - * aligned, and that we are working in - * multiples of the bus widths. + * If enough left try to send max possible, + * otherwise try to send the remainder */ - odd_bytes = lli_len % mbus->buswidth; - lli_len -= odd_bytes; - - } + lli_len = min(bd.remainder, max_bytes_per_lli); - if (lli_len) { /* - * Check against minimum bus alignment: - * Calculate actual transfer size in relation - * to bus width an get a maximum remainder of - * the smallest bus width - 1 + * Check against maximum bus alignment: + * Calculate actual transfer size in relation to + * bus width an get a maximum remainder of the + * highest bus width - 1 */ - /* FIXME: use round_down()? */ - tsize = lli_len / min(mbus->buswidth, - sbus->buswidth); - lli_len = tsize * min(mbus->buswidth, - sbus->buswidth); - - if (target_len != lli_len) { - dev_vdbg(&pl08x->adev->dev, - "%s can't send what we want. Desired 0x%08zx, lli of 0x%08zx bytes in txd of 0x%08zx\n", - __func__, target_len, lli_len, txd->len); - } - - cctl = pl08x_cctl_bits(cctl, - bd.srcbus.buswidth, - bd.dstbus.buswidth, - tsize); + width = max(mbus->buswidth, sbus->buswidth); + lli_len = (lli_len / width) * width; + tsize = lli_len / bd.srcbus.buswidth; dev_vdbg(&pl08x->adev->dev, - "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n", + "%s fill lli with single lli chunk of " + "size 0x%08zx (remainder 0x%08zx)\n", __func__, lli_len, bd.remainder); + + cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth, + bd.dstbus.buswidth, tsize); pl08x_fill_lli_for_desc(&bd, num_llis++, - lli_len, cctl); + lli_len, cctl); total_bytes += lli_len; } - - if (odd_bytes) { - /* - * Creep past the boundary, maintaining - * master alignment - */ - int j; - for (j = 0; (j < mbus->buswidth) - && (bd.remainder); j++) { - cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single byte (remain 0x%08zx)\n", - __func__, bd.remainder); - pl08x_fill_lli_for_desc(&bd, - num_llis++, 1, cctl); - total_bytes++; - } + /* + * Send any odd bytes + */ + if (bd.remainder) { + dev_vdbg(&pl08x->adev->dev, + "%s align with boundary, send odd bytes (remain %zu)\n", + __func__, bd.remainder); + prep_byte_width_lli(&bd, &cctl, bd.remainder, + num_llis++, &total_bytes); } } - /* - * Send any odd bytes - */ - while (bd.remainder) { - cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single odd byte (remain %zu)\n", - __func__, bd.remainder); - pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); - total_bytes++; + if (total_bytes != dsg->len) { + dev_err(&pl08x->adev->dev, + "%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n", + __func__, total_bytes, dsg->len); + return 0; } - } - if (total_bytes != txd->len) { - dev_err(&pl08x->adev->dev, - "%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n", - __func__, total_bytes, txd->len); - return 0; - } - if (num_llis >= MAX_NUM_TSFR_LLIS) { - dev_err(&pl08x->adev->dev, - "%s need to increase MAX_NUM_TSFR_LLIS from 0x%08x\n", - __func__, (u32) MAX_NUM_TSFR_LLIS); - return 0; + if (num_llis >= MAX_NUM_TSFR_LLIS) { + dev_err(&pl08x->adev->dev, + "%s need to increase MAX_NUM_TSFR_LLIS from 0x%08x\n", + __func__, (u32) MAX_NUM_TSFR_LLIS); + return 0; + } } llis_va = txd->llis_va; @@ -856,11 +800,19 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, static void pl08x_free_txd(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd) { + struct pl08x_sg *dsg, *_dsg; + /* Free the LLI */ - dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus); + if (txd->llis_va) + dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus); pl08x->pool_ctr--; + list_for_each_entry_safe(dsg, _dsg, &txd->dsg_list, node) { + list_del(&dsg->node); + kfree(dsg); + } + kfree(txd); } @@ -917,9 +869,7 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, * need, but for slaves the physical signals may be muxed! * Can the platform allow us to use this channel? */ - if (plchan->slave && - ch->signal < 0 && - pl08x->pd->get_signal) { + if (plchan->slave && pl08x->pd->get_signal) { ret = pl08x->pd->get_signal(plchan); if (ret < 0) { dev_dbg(&pl08x->adev->dev, @@ -1008,10 +958,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt( * If slaves are relying on interrupts to signal completion this function * must not be called with interrupts disabled. */ -static enum dma_status -pl08x_dma_tx_status(struct dma_chan *chan, - dma_cookie_t cookie, - struct dma_tx_state *txstate) +static enum dma_status pl08x_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *txstate) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); dma_cookie_t last_used; @@ -1253,7 +1201,9 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, num_llis = pl08x_fill_llis_for_desc(pl08x, txd); if (!num_llis) { - kfree(txd); + spin_lock_irqsave(&plchan->lock, flags); + pl08x_free_txd(pl08x, txd); + spin_unlock_irqrestore(&plchan->lock, flags); return -EINVAL; } @@ -1301,13 +1251,14 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, unsigned long flags) { - struct pl08x_txd *txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); + struct pl08x_txd *txd = kzalloc(sizeof(*txd), GFP_NOWAIT); if (txd) { dma_async_tx_descriptor_init(&txd->tx, &plchan->chan); txd->tx.flags = flags; txd->tx.tx_submit = pl08x_tx_submit; INIT_LIST_HEAD(&txd->node); + INIT_LIST_HEAD(&txd->dsg_list); /* Always enable error and terminal interrupts */ txd->ccfg = PL080_CONFIG_ERR_IRQ_MASK | @@ -1326,6 +1277,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; + struct pl08x_sg *dsg; int ret; txd = pl08x_get_txd(plchan, flags); @@ -1335,10 +1287,19 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( return NULL; } + dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT); + if (!dsg) { + pl08x_free_txd(pl08x, txd); + dev_err(&pl08x->adev->dev, "%s no memory for pl080 sg\n", + __func__); + return NULL; + } + list_add_tail(&dsg->node, &txd->dsg_list); + txd->direction = DMA_NONE; - txd->src_addr = src; - txd->dst_addr = dest; - txd->len = len; + dsg->src_addr = src; + dsg->dst_addr = dest; + dsg->len = len; /* Set platform data for m2m */ txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; @@ -1367,19 +1328,13 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; - int ret; - - /* - * Current implementation ASSUMES only one sg - */ - if (sg_len != 1) { - dev_err(&pl08x->adev->dev, "%s prepared too long sglist\n", - __func__); - BUG(); - } + struct pl08x_sg *dsg; + struct scatterlist *sg; + dma_addr_t slave_addr; + int ret, tmp; dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n", - __func__, sgl->length, plchan->name); + __func__, sgl->length, plchan->name); txd = pl08x_get_txd(plchan, flags); if (!txd) { @@ -1398,24 +1353,49 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( * channel target address dynamically at runtime. */ txd->direction = direction; - txd->len = sgl->length; if (direction == DMA_TO_DEVICE) { - txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl = plchan->dst_cctl; - txd->src_addr = sgl->dma_address; - txd->dst_addr = plchan->dst_addr; + slave_addr = plchan->dst_addr; } else if (direction == DMA_FROM_DEVICE) { - txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl = plchan->src_cctl; - txd->src_addr = plchan->src_addr; - txd->dst_addr = sgl->dma_address; + slave_addr = plchan->src_addr; } else { + pl08x_free_txd(pl08x, txd); dev_err(&pl08x->adev->dev, "%s direction unsupported\n", __func__); return NULL; } + if (plchan->cd->device_fc) + tmp = (direction == DMA_TO_DEVICE) ? PL080_FLOW_MEM2PER_PER : + PL080_FLOW_PER2MEM_PER; + else + tmp = (direction == DMA_TO_DEVICE) ? PL080_FLOW_MEM2PER : + PL080_FLOW_PER2MEM; + + txd->ccfg |= tmp << PL080_CONFIG_FLOW_CONTROL_SHIFT; + + for_each_sg(sgl, sg, sg_len, tmp) { + dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT); + if (!dsg) { + pl08x_free_txd(pl08x, txd); + dev_err(&pl08x->adev->dev, "%s no mem for pl080 sg\n", + __func__); + return NULL; + } + list_add_tail(&dsg->node, &txd->dsg_list); + + dsg->len = sg_dma_len(sg); + if (direction == DMA_TO_DEVICE) { + dsg->src_addr = sg_phys(sg); + dsg->dst_addr = slave_addr; + } else { + dsg->src_addr = slave_addr; + dsg->dst_addr = sg_phys(sg); + } + } + ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; @@ -1489,9 +1469,15 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) { - struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); + struct pl08x_dma_chan *plchan; char *name = chan_id; + /* Reject channels for devices not bound to this driver */ + if (chan->device->dev->driver != &pl08x_amba_driver.drv) + return false; + + plchan = to_pl08x_chan(chan); + /* Check that the channel is not taken! */ if (!strcmp(plchan->name, name)) return true; @@ -1507,34 +1493,34 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) */ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) { - u32 val; - - val = readl(pl08x->base + PL080_CONFIG); - val &= ~(PL080_CONFIG_M2_BE | PL080_CONFIG_M1_BE | PL080_CONFIG_ENABLE); - /* We implicitly clear bit 1 and that means little-endian mode */ - val |= PL080_CONFIG_ENABLE; - writel(val, pl08x->base + PL080_CONFIG); + writel(PL080_CONFIG_ENABLE, pl08x->base + PL080_CONFIG); } static void pl08x_unmap_buffers(struct pl08x_txd *txd) { struct device *dev = txd->tx.chan->device->dev; + struct pl08x_sg *dsg; if (!(txd->tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) { if (txd->tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE) - dma_unmap_single(dev, txd->src_addr, txd->len, - DMA_TO_DEVICE); - else - dma_unmap_page(dev, txd->src_addr, txd->len, - DMA_TO_DEVICE); + list_for_each_entry(dsg, &txd->dsg_list, node) + dma_unmap_single(dev, dsg->src_addr, dsg->len, + DMA_TO_DEVICE); + else { + list_for_each_entry(dsg, &txd->dsg_list, node) + dma_unmap_page(dev, dsg->src_addr, dsg->len, + DMA_TO_DEVICE); + } } if (!(txd->tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) { if (txd->tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE) - dma_unmap_single(dev, txd->dst_addr, txd->len, - DMA_FROM_DEVICE); + list_for_each_entry(dsg, &txd->dsg_list, node) + dma_unmap_single(dev, dsg->dst_addr, dsg->len, + DMA_FROM_DEVICE); else - dma_unmap_page(dev, txd->dst_addr, txd->len, - DMA_FROM_DEVICE); + list_for_each_entry(dsg, &txd->dsg_list, node) + dma_unmap_page(dev, dsg->dst_addr, dsg->len, + DMA_FROM_DEVICE); } } @@ -1589,8 +1575,8 @@ static void pl08x_tasklet(unsigned long data) */ list_for_each_entry(waiting, &pl08x->memcpy.channels, chan.device_node) { - if (waiting->state == PL08X_CHAN_WAITING && - waiting->waiting != NULL) { + if (waiting->state == PL08X_CHAN_WAITING && + waiting->waiting != NULL) { int ret; /* This should REALLY not fail now */ @@ -1630,38 +1616,40 @@ static void pl08x_tasklet(unsigned long data) static irqreturn_t pl08x_irq(int irq, void *dev) { struct pl08x_driver_data *pl08x = dev; - u32 mask = 0; - u32 val; - int i; - - val = readl(pl08x->base + PL080_ERR_STATUS); - if (val) { - /* An error interrupt (on one or more channels) */ - dev_err(&pl08x->adev->dev, - "%s error interrupt, register value 0x%08x\n", - __func__, val); - /* - * Simply clear ALL PL08X error interrupts, - * regardless of channel and cause - * FIXME: should be 0x00000003 on PL081 really. - */ - writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR); + u32 mask = 0, err, tc, i; + + /* check & clear - ERR & TC interrupts */ + err = readl(pl08x->base + PL080_ERR_STATUS); + if (err) { + dev_err(&pl08x->adev->dev, "%s error interrupt, register value 0x%08x\n", + __func__, err); + writel(err, pl08x->base + PL080_ERR_CLEAR); } - val = readl(pl08x->base + PL080_INT_STATUS); + tc = readl(pl08x->base + PL080_INT_STATUS); + if (tc) + writel(tc, pl08x->base + PL080_TC_CLEAR); + + if (!err && !tc) + return IRQ_NONE; + for (i = 0; i < pl08x->vd->channels; i++) { - if ((1 << i) & val) { + if (((1 << i) & err) || ((1 << i) & tc)) { /* Locate physical channel */ struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i]; struct pl08x_dma_chan *plchan = phychan->serving; + if (!plchan) { + dev_err(&pl08x->adev->dev, + "%s Error TC interrupt on unused channel: 0x%08x\n", + __func__, i); + continue; + } + /* Schedule tasklet on this channel */ tasklet_schedule(&plchan->tasklet); - mask |= (1 << i); } } - /* Clear only the terminal interrupts on channels we processed */ - writel(mask, pl08x->base + PL080_TC_CLEAR); return mask ? IRQ_HANDLED : IRQ_NONE; } @@ -1685,9 +1673,7 @@ static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan) * Make a local wrapper to hold required data */ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, - struct dma_device *dmadev, - unsigned int channels, - bool slave) + struct dma_device *dmadev, unsigned int channels, bool slave) { struct pl08x_dma_chan *chan; int i; @@ -1700,7 +1686,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, * to cope with that situation. */ for (i = 0; i < channels; i++) { - chan = kzalloc(sizeof(struct pl08x_dma_chan), GFP_KERNEL); + chan = kzalloc(sizeof(*chan), GFP_KERNEL); if (!chan) { dev_err(&pl08x->adev->dev, "%s no memory for channel\n", __func__); @@ -1728,7 +1714,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, kfree(chan); continue; } - dev_info(&pl08x->adev->dev, + dev_dbg(&pl08x->adev->dev, "initialize virtual channel \"%s\"\n", chan->name); @@ -1837,9 +1823,9 @@ static const struct file_operations pl08x_debugfs_operations = { static void init_pl08x_debugfs(struct pl08x_driver_data *pl08x) { /* Expose a simple debugfs interface to view all clocks */ - (void) debugfs_create_file(dev_name(&pl08x->adev->dev), S_IFREG | S_IRUGO, - NULL, pl08x, - &pl08x_debugfs_operations); + (void) debugfs_create_file(dev_name(&pl08x->adev->dev), + S_IFREG | S_IRUGO, NULL, pl08x, + &pl08x_debugfs_operations); } #else @@ -1860,12 +1846,15 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) return ret; /* Create the driver state holder */ - pl08x = kzalloc(sizeof(struct pl08x_driver_data), GFP_KERNEL); + pl08x = kzalloc(sizeof(*pl08x), GFP_KERNEL); if (!pl08x) { ret = -ENOMEM; goto out_no_pl08x; } + pm_runtime_set_active(&adev->dev); + pm_runtime_enable(&adev->dev); + /* Initialize memcpy engine */ dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask); pl08x->memcpy.dev = &adev->dev; @@ -1939,7 +1928,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) } /* Initialize physical channels */ - pl08x->phy_chans = kmalloc((vd->channels * sizeof(struct pl08x_phy_chan)), + pl08x->phy_chans = kmalloc((vd->channels * sizeof(*pl08x->phy_chans)), GFP_KERNEL); if (!pl08x->phy_chans) { dev_err(&adev->dev, "%s failed to allocate " @@ -1956,9 +1945,8 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&ch->lock); ch->serving = NULL; ch->signal = -1; - dev_info(&adev->dev, - "physical channel %d is %s\n", i, - pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE"); + dev_dbg(&adev->dev, "physical channel %d is %s\n", + i, pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE"); } /* Register as many memcpy channels as there are physical channels */ @@ -1974,8 +1962,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) /* Register slave channels */ ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->slave, - pl08x->pd->num_slave_channels, - true); + pl08x->pd->num_slave_channels, true); if (ret <= 0) { dev_warn(&pl08x->adev->dev, "%s failed to enumerate slave channels - %d\n", @@ -2005,6 +1992,8 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) dev_info(&pl08x->adev->dev, "DMA: PL%03x rev%u at 0x%08llx irq %d\n", amba_part(adev), amba_rev(adev), (unsigned long long)adev->res.start, adev->irq[0]); + + pm_runtime_put(&adev->dev); return 0; out_no_slave_reg: @@ -2023,6 +2012,9 @@ out_no_ioremap: dma_pool_destroy(pl08x->pool); out_no_lli_pool: out_no_platdata: + pm_runtime_put(&adev->dev); + pm_runtime_disable(&adev->dev); + kfree(pl08x); out_no_pl08x: amba_release_regions(adev); diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 6a483eac7b3f..fcfa0a8b5c59 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -107,10 +107,11 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) { struct at_desc *desc, *_desc; struct at_desc *ret = NULL; + unsigned long flags; unsigned int i = 0; LIST_HEAD(tmp_list); - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) { i++; if (async_tx_test_ack(&desc->txd)) { @@ -121,7 +122,7 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) dev_dbg(chan2dev(&atchan->chan_common), "desc %p not ACKed\n", desc); } - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); dev_vdbg(chan2dev(&atchan->chan_common), "scanned %u descriptors on freelist\n", i); @@ -129,9 +130,9 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) if (!ret) { ret = atc_alloc_descriptor(&atchan->chan_common, GFP_ATOMIC); if (ret) { - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); atchan->descs_allocated++; - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } else { dev_err(chan2dev(&atchan->chan_common), "not enough descriptors available\n"); @@ -150,8 +151,9 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc) { if (desc) { struct at_desc *child; + unsigned long flags; - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); list_for_each_entry(child, &desc->tx_list, desc_node) dev_vdbg(chan2dev(&atchan->chan_common), "moving child desc %p to freelist\n", @@ -160,7 +162,7 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc) dev_vdbg(chan2dev(&atchan->chan_common), "moving desc %p to freelist\n", desc); list_add(&desc->desc_node, &atchan->free_list); - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } } @@ -299,7 +301,7 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) /* for cyclic transfers, * no need to replay callback function while stopping */ - if (!test_bit(ATC_IS_CYCLIC, &atchan->status)) { + if (!atc_chan_is_cyclic(atchan)) { dma_async_tx_callback callback = txd->callback; void *param = txd->callback_param; @@ -471,16 +473,17 @@ static void atc_handle_cyclic(struct at_dma_chan *atchan) static void atc_tasklet(unsigned long data) { struct at_dma_chan *atchan = (struct at_dma_chan *)data; + unsigned long flags; - spin_lock(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status)) atc_handle_error(atchan); - else if (test_bit(ATC_IS_CYCLIC, &atchan->status)) + else if (atc_chan_is_cyclic(atchan)) atc_handle_cyclic(atchan); else atc_advance_work(atchan); - spin_unlock(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } static irqreturn_t at_dma_interrupt(int irq, void *dev_id) @@ -539,8 +542,9 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx) struct at_desc *desc = txd_to_at_desc(tx); struct at_dma_chan *atchan = to_at_dma_chan(tx->chan); dma_cookie_t cookie; + unsigned long flags; - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); cookie = atc_assign_cookie(atchan, desc); if (list_empty(&atchan->active_list)) { @@ -554,7 +558,7 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx) list_add_tail(&desc->desc_node, &atchan->queue); } - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); return cookie; } @@ -927,28 +931,29 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma *atdma = to_at_dma(chan->device); int chan_id = atchan->chan_common.chan_id; + unsigned long flags; LIST_HEAD(list); dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd); if (cmd == DMA_PAUSE) { - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id)); set_bit(ATC_IS_PAUSED, &atchan->status); - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_RESUME) { - if (!test_bit(ATC_IS_PAUSED, &atchan->status)) + if (!atc_chan_is_paused(atchan)) return 0; - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); dma_writel(atdma, CHDR, AT_DMA_RES(chan_id)); clear_bit(ATC_IS_PAUSED, &atchan->status); - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_TERMINATE_ALL) { struct at_desc *desc, *_desc; /* @@ -957,7 +962,7 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, * channel. We still have to poll the channel enable bit due * to AHB/HSB limitations. */ - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); /* disabling channel: must also remove suspend state */ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask); @@ -978,7 +983,7 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, /* if channel dedicated to cyclic operations, free it */ clear_bit(ATC_IS_CYCLIC, &atchan->status); - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } else { return -ENXIO; } @@ -1004,9 +1009,10 @@ atc_tx_status(struct dma_chan *chan, struct at_dma_chan *atchan = to_at_dma_chan(chan); dma_cookie_t last_used; dma_cookie_t last_complete; + unsigned long flags; enum dma_status ret; - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); last_complete = atchan->completed_cookie; last_used = chan->cookie; @@ -1021,7 +1027,7 @@ atc_tx_status(struct dma_chan *chan, ret = dma_async_is_complete(cookie, last_complete, last_used); } - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); if (ret != DMA_SUCCESS) dma_set_tx_state(txstate, last_complete, last_used, @@ -1029,7 +1035,7 @@ atc_tx_status(struct dma_chan *chan, else dma_set_tx_state(txstate, last_complete, last_used, 0); - if (test_bit(ATC_IS_PAUSED, &atchan->status)) + if (atc_chan_is_paused(atchan)) ret = DMA_PAUSED; dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d (d%d, u%d)\n", @@ -1046,18 +1052,19 @@ atc_tx_status(struct dma_chan *chan, static void atc_issue_pending(struct dma_chan *chan) { struct at_dma_chan *atchan = to_at_dma_chan(chan); + unsigned long flags; dev_vdbg(chan2dev(chan), "issue_pending\n"); /* Not needed for cyclic transfers */ - if (test_bit(ATC_IS_CYCLIC, &atchan->status)) + if (atc_chan_is_cyclic(atchan)) return; - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); if (!atc_chan_is_enabled(atchan)) { atc_advance_work(atchan); } - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } /** @@ -1073,6 +1080,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) struct at_dma *atdma = to_at_dma(chan->device); struct at_desc *desc; struct at_dma_slave *atslave; + unsigned long flags; int i; u32 cfg; LIST_HEAD(tmp_list); @@ -1116,11 +1124,11 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) list_add_tail(&desc->desc_node, &tmp_list); } - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); atchan->descs_allocated = i; list_splice(&tmp_list, &atchan->free_list); atchan->completed_cookie = chan->cookie = 1; - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); /* channel parameters */ channel_writel(atchan, CFG, cfg); @@ -1260,12 +1268,11 @@ static int __init at_dma_probe(struct platform_device *pdev) /* initialize channels related values */ INIT_LIST_HEAD(&atdma->dma_common.channels); - for (i = 0; i < pdata->nr_channels; i++, atdma->dma_common.chancnt++) { + for (i = 0; i < pdata->nr_channels; i++) { struct at_dma_chan *atchan = &atdma->chan[i]; atchan->chan_common.device = &atdma->dma_common; atchan->chan_common.cookie = atchan->completed_cookie = 1; - atchan->chan_common.chan_id = i; list_add_tail(&atchan->chan_common.device_node, &atdma->dma_common.channels); @@ -1293,22 +1300,20 @@ static int __init at_dma_probe(struct platform_device *pdev) if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask)) atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy; - if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) + if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) { atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg; - - if (dma_has_cap(DMA_CYCLIC, atdma->dma_common.cap_mask)) + /* controller can do slave DMA: can trigger cyclic transfers */ + dma_cap_set(DMA_CYCLIC, atdma->dma_common.cap_mask); atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic; - - if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) || - dma_has_cap(DMA_CYCLIC, atdma->dma_common.cap_mask)) atdma->dma_common.device_control = atc_control; + } dma_writel(atdma, EN, AT_DMA_ENABLE); dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s), %d channels\n", dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask) ? "cpy " : "", dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) ? "slave " : "", - atdma->dma_common.chancnt); + pdata->nr_channels); dma_async_device_register(&atdma->dma_common); @@ -1377,27 +1382,112 @@ static void at_dma_shutdown(struct platform_device *pdev) clk_disable(atdma->clk); } +static int at_dma_prepare(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct at_dma *atdma = platform_get_drvdata(pdev); + struct dma_chan *chan, *_chan; + + list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, + device_node) { + struct at_dma_chan *atchan = to_at_dma_chan(chan); + /* wait for transaction completion (except in cyclic case) */ + if (atc_chan_is_enabled(atchan) && !atc_chan_is_cyclic(atchan)) + return -EAGAIN; + } + return 0; +} + +static void atc_suspend_cyclic(struct at_dma_chan *atchan) +{ + struct dma_chan *chan = &atchan->chan_common; + + /* Channel should be paused by user + * do it anyway even if it is not done already */ + if (!atc_chan_is_paused(atchan)) { + dev_warn(chan2dev(chan), + "cyclic channel not paused, should be done by channel user\n"); + atc_control(chan, DMA_PAUSE, 0); + } + + /* now preserve additional data for cyclic operations */ + /* next descriptor address in the cyclic list */ + atchan->save_dscr = channel_readl(atchan, DSCR); + + vdbg_dump_regs(atchan); +} + static int at_dma_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct at_dma *atdma = platform_get_drvdata(pdev); + struct dma_chan *chan, *_chan; - at_dma_off(platform_get_drvdata(pdev)); + /* preserve data */ + list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, + device_node) { + struct at_dma_chan *atchan = to_at_dma_chan(chan); + + if (atc_chan_is_cyclic(atchan)) + atc_suspend_cyclic(atchan); + atchan->save_cfg = channel_readl(atchan, CFG); + } + atdma->save_imr = dma_readl(atdma, EBCIMR); + + /* disable DMA controller */ + at_dma_off(atdma); clk_disable(atdma->clk); return 0; } +static void atc_resume_cyclic(struct at_dma_chan *atchan) +{ + struct at_dma *atdma = to_at_dma(atchan->chan_common.device); + + /* restore channel status for cyclic descriptors list: + * next descriptor in the cyclic list at the time of suspend */ + channel_writel(atchan, SADDR, 0); + channel_writel(atchan, DADDR, 0); + channel_writel(atchan, CTRLA, 0); + channel_writel(atchan, CTRLB, 0); + channel_writel(atchan, DSCR, atchan->save_dscr); + dma_writel(atdma, CHER, atchan->mask); + + /* channel pause status should be removed by channel user + * We cannot take the initiative to do it here */ + + vdbg_dump_regs(atchan); +} + static int at_dma_resume_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct at_dma *atdma = platform_get_drvdata(pdev); + struct dma_chan *chan, *_chan; + /* bring back DMA controller */ clk_enable(atdma->clk); dma_writel(atdma, EN, AT_DMA_ENABLE); + + /* clear any pending interrupt */ + while (dma_readl(atdma, EBCISR)) + cpu_relax(); + + /* restore saved data */ + dma_writel(atdma, EBCIER, atdma->save_imr); + list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, + device_node) { + struct at_dma_chan *atchan = to_at_dma_chan(chan); + + channel_writel(atchan, CFG, atchan->save_cfg); + if (atc_chan_is_cyclic(atchan)) + atc_resume_cyclic(atchan); + } return 0; } static const struct dev_pm_ops at_dma_dev_pm_ops = { + .prepare = at_dma_prepare, .suspend_noirq = at_dma_suspend_noirq, .resume_noirq = at_dma_resume_noirq, }; diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index 087dbf1dd39c..aa4c9aebab7c 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -204,6 +204,9 @@ enum atc_status { * @status: transmit status information from irq/prep* functions * to tasklet (use atomic operations) * @tasklet: bottom half to finish transaction work + * @save_cfg: configuration register that is saved on suspend/resume cycle + * @save_dscr: for cyclic operations, preserve next descriptor address in + * the cyclic list on suspend/resume cycle * @lock: serializes enqueue/dequeue operations to descriptors lists * @completed_cookie: identifier for the most recently completed operation * @active_list: list of descriptors dmaengine is being running on @@ -218,6 +221,8 @@ struct at_dma_chan { u8 mask; unsigned long status; struct tasklet_struct tasklet; + u32 save_cfg; + u32 save_dscr; spinlock_t lock; @@ -248,6 +253,7 @@ static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan) * @chan_common: common dmaengine dma_device object members * @ch_regs: memory mapped register base * @clk: dma controller clock + * @save_imr: interrupt mask register that is saved on suspend/resume cycle * @all_chan_mask: all channels availlable in a mask * @dma_desc_pool: base of DMA descriptor region (DMA address) * @chan: channels table to store at_dma_chan structures @@ -256,6 +262,7 @@ struct at_dma { struct dma_device dma_common; void __iomem *regs; struct clk *clk; + u32 save_imr; u8 all_chan_mask; @@ -355,6 +362,23 @@ static inline int atc_chan_is_enabled(struct at_dma_chan *atchan) return !!(dma_readl(atdma, CHSR) & atchan->mask); } +/** + * atc_chan_is_paused - test channel pause/resume status + * @atchan: channel we want to test status + */ +static inline int atc_chan_is_paused(struct at_dma_chan *atchan) +{ + return test_bit(ATC_IS_PAUSED, &atchan->status); +} + +/** + * atc_chan_is_cyclic - test if given channel has cyclic property set + * @atchan: channel we want to test status + */ +static inline int atc_chan_is_cyclic(struct at_dma_chan *atchan) +{ + return test_bit(ATC_IS_CYCLIC, &atchan->status); +} /** * set_desc_eol - set end-of-link to descriptor so it will end transfer diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 765f5ff22304..eb1d8641cf5c 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> +#include <linux/freezer.h> #include <linux/init.h> #include <linux/kthread.h> #include <linux/module.h> @@ -251,6 +252,7 @@ static int dmatest_func(void *data) int i; thread_name = current->comm; + set_freezable_with_signal(); ret = -ENOMEM; @@ -305,7 +307,8 @@ static int dmatest_func(void *data) dma_addr_t dma_srcs[src_cnt]; dma_addr_t dma_dsts[dst_cnt]; struct completion cmp; - unsigned long tmo = msecs_to_jiffies(timeout); + unsigned long start, tmo, end = 0 /* compiler... */; + bool reload = true; u8 align = 0; total_tests++; @@ -404,7 +407,17 @@ static int dmatest_func(void *data) } dma_async_issue_pending(chan); - tmo = wait_for_completion_timeout(&cmp, tmo); + do { + start = jiffies; + if (reload) + end = start + msecs_to_jiffies(timeout); + else if (end <= start) + end = start + 1; + tmo = wait_for_completion_interruptible_timeout(&cmp, + end - start); + reload = try_to_freeze(); + } while (tmo == -ERESTARTSYS); + status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); if (tmo == 0) { @@ -477,6 +490,8 @@ err_srcs: pr_notice("%s: terminating after %u tests, %u failures (status %d)\n", thread_name, total_tests, failed_tests, ret); + /* terminate all transfers on specified channels */ + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); if (iterations > 0) while (!kthread_should_stop()) { DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit); @@ -499,6 +514,10 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc) list_del(&thread->node); kfree(thread); } + + /* terminate all transfers on specified channels */ + dtc->chan->device->device_control(dtc->chan, DMA_TERMINATE_ALL, 0); + kfree(dtc); } diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 4d180ca9a1d8..9bfd6d360718 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1407,12 +1407,11 @@ static int __init dw_probe(struct platform_device *pdev) dw->all_chan_mask = (1 << pdata->nr_channels) - 1; INIT_LIST_HEAD(&dw->dma.channels); - for (i = 0; i < pdata->nr_channels; i++, dw->dma.chancnt++) { + for (i = 0; i < pdata->nr_channels; i++) { struct dw_dma_chan *dwc = &dw->chan[i]; dwc->chan.device = &dw->dma; dwc->chan.cookie = dwc->completed = 1; - dwc->chan.chan_id = i; if (pdata->chan_allocation_order == CHAN_ALLOCATION_ASCENDING) list_add_tail(&dwc->chan.device_node, &dw->dma.channels); @@ -1468,7 +1467,7 @@ static int __init dw_probe(struct platform_device *pdev) dma_writel(dw, CFG, DW_CFG_DMA_EN); printk(KERN_INFO "%s: DesignWare DMA Controller, %d channels\n", - dev_name(&pdev->dev), dw->dma.chancnt); + dev_name(&pdev->dev), pdata->nr_channels); dma_async_device_register(&dw->dma); diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index 5d7a49bd7c26..b47e2b803faf 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -22,6 +22,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/dmaengine.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index d99f71c356b5..4be55f9bb6c1 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -14,6 +14,7 @@ * http://www.gnu.org/copyleft/gpl.html */ #include <linux/init.h> +#include <linux/module.h> #include <linux/types.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -23,6 +24,7 @@ #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/dmaengine.h> +#include <linux/module.h> #include <asm/irq.h> #include <mach/dma-v1.h> diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 7bd7e98548cd..f993955a640c 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -18,6 +18,7 @@ */ #include <linux/init.h> +#include <linux/module.h> #include <linux/types.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -34,6 +35,7 @@ #include <linux/dmaengine.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/module.h> #include <asm/irq.h> #include <mach/sdma.h> @@ -318,6 +320,7 @@ struct sdma_engine { dma_addr_t context_phys; struct dma_device dma_device; struct clk *clk; + struct mutex channel_0_lock; struct sdma_script_start_addrs *script_addrs; }; @@ -415,11 +418,15 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, dma_addr_t buf_phys; int ret; + mutex_lock(&sdma->channel_0_lock); + buf_virt = dma_alloc_coherent(NULL, size, &buf_phys, GFP_KERNEL); - if (!buf_virt) - return -ENOMEM; + if (!buf_virt) { + ret = -ENOMEM; + goto err_out; + } bd0->mode.command = C0_SETPM; bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; @@ -433,6 +440,9 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, dma_free_coherent(NULL, size, buf_virt, buf_phys); +err_out: + mutex_unlock(&sdma->channel_0_lock); + return ret; } @@ -656,6 +666,8 @@ static int sdma_load_context(struct sdma_channel *sdmac) dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0); dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1); + mutex_lock(&sdma->channel_0_lock); + memset(context, 0, sizeof(*context)); context->channel_state.pc = load_address; @@ -676,6 +688,8 @@ static int sdma_load_context(struct sdma_channel *sdmac) ret = sdma_run_channel(&sdma->channel[0]); + mutex_unlock(&sdma->channel_0_lock); + return ret; } @@ -1131,18 +1145,17 @@ static void sdma_add_scripts(struct sdma_engine *sdma, saddr_arr[i] = addr_arr[i]; } -static int __init sdma_get_firmware(struct sdma_engine *sdma, - const char *fw_name) +static void sdma_load_firmware(const struct firmware *fw, void *context) { - const struct firmware *fw; + struct sdma_engine *sdma = context; const struct sdma_firmware_header *header; - int ret; const struct sdma_script_start_addrs *addr; unsigned short *ram_code; - ret = request_firmware(&fw, fw_name, sdma->dev); - if (ret) - return ret; + if (!fw) { + dev_err(sdma->dev, "firmware not found\n"); + return; + } if (fw->size < sizeof(*header)) goto err_firmware; @@ -1172,6 +1185,16 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma, err_firmware: release_firmware(fw); +} + +static int __init sdma_get_firmware(struct sdma_engine *sdma, + const char *fw_name) +{ + int ret; + + ret = request_firmware_nowait(THIS_MODULE, + FW_ACTION_HOTPLUG, fw_name, sdma->dev, + GFP_KERNEL, sdma, sdma_load_firmware); return ret; } @@ -1269,11 +1292,14 @@ static int __init sdma_probe(struct platform_device *pdev) struct sdma_platform_data *pdata = pdev->dev.platform_data; int i; struct sdma_engine *sdma; + s32 *saddr_arr; sdma = kzalloc(sizeof(*sdma), GFP_KERNEL); if (!sdma) return -ENOMEM; + mutex_init(&sdma->channel_0_lock); + sdma->dev = &pdev->dev; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1310,6 +1336,11 @@ static int __init sdma_probe(struct platform_device *pdev) goto err_alloc; } + /* initially no scripts available */ + saddr_arr = (s32 *)sdma->script_addrs; + for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++) + saddr_arr[i] = -EINVAL; + if (of_id) pdev->id_entry = of_id->data; sdma->devtype = pdev->id_entry->driver_data; diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 8a3fdd87db97..19a0c64d45d3 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -27,6 +27,7 @@ #include <linux/interrupt.h> #include <linux/pm_runtime.h> #include <linux/intel_mid_dma.h> +#include <linux/module.h> #define MAX_CHAN 4 /*max ch across controllers*/ #include "intel_mid_dma_regs.h" @@ -115,16 +116,15 @@ DMAC1 interrupt Functions*/ /** * dmac1_mask_periphral_intr - mask the periphral interrupt - * @midc: dma channel for which masking is required + * @mid: dma device for which masking is required * * Masks the DMA periphral interrupt * this is valid for DMAC1 family controllers only * This controller should have periphral mask registers already mapped */ -static void dmac1_mask_periphral_intr(struct intel_mid_dma_chan *midc) +static void dmac1_mask_periphral_intr(struct middma_device *mid) { u32 pimr; - struct middma_device *mid = to_middma_device(midc->chan.device); if (mid->pimr_mask) { pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK); @@ -184,7 +184,6 @@ static void enable_dma_interrupt(struct intel_mid_dma_chan *midc) static void disable_dma_interrupt(struct intel_mid_dma_chan *midc) { /*Check LPE PISR, make sure fwd is disabled*/ - dmac1_mask_periphral_intr(midc); iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_BLOCK); iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR); iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR); @@ -1114,7 +1113,6 @@ static int mid_setup_dma(struct pci_dev *pdev) midch->chan.device = &dma->common; midch->chan.cookie = 1; - midch->chan.chan_id = i; midch->ch_id = dma->chan_base + i; pr_debug("MDMA:Init CH %d, ID %d\n", i, midch->ch_id); @@ -1150,7 +1148,6 @@ static int mid_setup_dma(struct pci_dev *pdev) dma_cap_set(DMA_SLAVE, dma->common.cap_mask); dma_cap_set(DMA_PRIVATE, dma->common.cap_mask); dma->common.dev = &pdev->dev; - dma->common.chancnt = dma->max_chan; dma->common.device_alloc_chan_resources = intel_mid_dma_alloc_chan_resources; @@ -1350,6 +1347,7 @@ int dma_suspend(struct pci_dev *pci, pm_message_t state) if (device->ch[i].in_use) return -EAGAIN; } + dmac1_mask_periphral_intr(device); device->state = SUSPENDED; pci_save_state(pci); pci_disable_device(pci); diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index ddc2a1331822..0e5ef33f90a1 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -21,6 +21,7 @@ #include <linux/string.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/module.h> #include <mach/ipu.h> diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index b9bae94f2015..8ba4edc6185e 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -741,7 +741,6 @@ static int __devinit mpc_dma_probe(struct platform_device *op) mchan = &mdma->channels[i]; mchan->chan.device = dma; - mchan->chan.chan_id = i; mchan->chan.cookie = 1; mchan->completed_cookie = mchan->chan.cookie; diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index be641cbd36fc..b4588bdd98bb 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -130,6 +130,23 @@ struct mxs_dma_engine { struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS]; }; +static inline void mxs_dma_clkgate(struct mxs_dma_chan *mxs_chan, int enable) +{ + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + int chan_id = mxs_chan->chan.chan_id; + int set_clr = enable ? MXS_CLR_ADDR : MXS_SET_ADDR; + + /* enable apbh channel clock */ + if (dma_is_apbh()) { + if (apbh_is_old()) + writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), + mxs_dma->base + HW_APBHX_CTRL0 + set_clr); + else + writel(1 << chan_id, + mxs_dma->base + HW_APBHX_CTRL0 + set_clr); + } +} + static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan) { struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; @@ -148,38 +165,21 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan) struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; int chan_id = mxs_chan->chan.chan_id; + /* clkgate needs to be enabled before writing other registers */ + mxs_dma_clkgate(mxs_chan, 1); + /* set cmd_addr up */ writel(mxs_chan->ccw_phys, mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id)); - /* enable apbh channel clock */ - if (dma_is_apbh()) { - if (apbh_is_old()) - writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), - mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR); - else - writel(1 << chan_id, - mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR); - } - /* write 1 to SEMA to kick off the channel */ writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(chan_id)); } static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan) { - struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; - int chan_id = mxs_chan->chan.chan_id; - /* disable apbh channel clock */ - if (dma_is_apbh()) { - if (apbh_is_old()) - writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), - mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); - else - writel(1 << chan_id, - mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); - } + mxs_dma_clkgate(mxs_chan, 0); mxs_chan->status = DMA_SUCCESS; } @@ -338,7 +338,10 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan) if (ret) goto err_clk; + /* clkgate needs to be enabled for reset to finish */ + mxs_dma_clkgate(mxs_chan, 1); mxs_dma_reset_chan(mxs_chan); + mxs_dma_clkgate(mxs_chan, 0); dma_async_tx_descriptor_init(&mxs_chan->desc, chan); mxs_chan->desc.tx_submit = mxs_dma_tx_submit; diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index 1ac8d4b580b7..a6d0e3dbed07 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -60,7 +60,7 @@ #define DMA_DESC_FOLLOW_WITHOUT_IRQ 0x2 #define DMA_DESC_FOLLOW_WITH_IRQ 0x3 -#define MAX_CHAN_NR 8 +#define MAX_CHAN_NR 12 #define DMA_MASK_CTL0_MODE 0x33333333 #define DMA_MASK_CTL2_MODE 0x00003333 @@ -872,8 +872,7 @@ static int __devinit pch_dma_probe(struct pci_dev *pdev, int i; nr_channels = id->driver_data; - pd = kzalloc(sizeof(struct pch_dma)+ - sizeof(struct pch_dma_chan) * nr_channels, GFP_KERNEL); + pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) return -ENOMEM; @@ -926,7 +925,6 @@ static int __devinit pch_dma_probe(struct pci_dev *pdev, } pd->dma.dev = &pdev->dev; - pd->dma.chancnt = nr_channels; INIT_LIST_HEAD(&pd->dma.channels); @@ -935,7 +933,6 @@ static int __devinit pch_dma_probe(struct pci_dev *pdev, pd_chan->chan.device = &pd->dma; pd_chan->chan.cookie = 1; - pd_chan->chan.chan_id = i; pd_chan->membase = ®s->desc[i]; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 00eee59e8b33..571041477ab2 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -17,6 +17,8 @@ #include <linux/interrupt.h> #include <linux/amba/bus.h> #include <linux/amba/pl330.h> +#include <linux/pm_runtime.h> +#include <linux/scatterlist.h> #define NR_DEFAULT_DESC 16 @@ -68,6 +70,14 @@ struct dma_pl330_chan { * NULL if the channel is available to be acquired. */ void *pl330_chid; + + /* For D-to-M and M-to-D channels */ + int burst_sz; /* the peripheral fifo width */ + int burst_len; /* the number of burst */ + dma_addr_t fifo_addr; + + /* for cyclic capability */ + bool cyclic; }; struct dma_pl330_dmac { @@ -83,6 +93,8 @@ struct dma_pl330_dmac { /* Peripheral channels connected to this DMAC */ struct dma_pl330_chan *peripherals; /* keep at end */ + + struct clk *clk; }; struct dma_pl330_desc { @@ -152,6 +164,31 @@ static inline void free_desc_list(struct list_head *list) spin_unlock_irqrestore(&pdmac->pool_lock, flags); } +static inline void handle_cyclic_desc_list(struct list_head *list) +{ + struct dma_pl330_desc *desc; + struct dma_pl330_chan *pch; + unsigned long flags; + + if (list_empty(list)) + return; + + list_for_each_entry(desc, list, node) { + dma_async_tx_callback callback; + + /* Change status to reload it */ + desc->status = PREP; + pch = desc->pchan; + callback = desc->txd.callback; + if (callback) + callback(desc->txd.callback_param); + } + + spin_lock_irqsave(&pch->lock, flags); + list_splice_tail_init(list, &pch->work_list); + spin_unlock_irqrestore(&pch->lock, flags); +} + static inline void fill_queue(struct dma_pl330_chan *pch) { struct dma_pl330_desc *desc; @@ -205,7 +242,10 @@ static void pl330_tasklet(unsigned long data) spin_unlock_irqrestore(&pch->lock, flags); - free_desc_list(&list); + if (pch->cyclic) + handle_cyclic_desc_list(&list); + else + free_desc_list(&list); } static void dma_pl330_rqcb(void *token, enum pl330_op_err err) @@ -236,6 +276,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) spin_lock_irqsave(&pch->lock, flags); pch->completed = chan->cookie = 1; + pch->cyclic = false; pch->pl330_chid = pl330_request_channel(&pdmac->pif); if (!pch->pl330_chid) { @@ -253,25 +294,52 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) { struct dma_pl330_chan *pch = to_pchan(chan); - struct dma_pl330_desc *desc; + struct dma_pl330_desc *desc, *_dt; unsigned long flags; + struct dma_pl330_dmac *pdmac = pch->dmac; + struct dma_slave_config *slave_config; + LIST_HEAD(list); - /* Only supports DMA_TERMINATE_ALL */ - if (cmd != DMA_TERMINATE_ALL) - return -ENXIO; - - spin_lock_irqsave(&pch->lock, flags); - - /* FLUSH the PL330 Channel thread */ - pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH); + switch (cmd) { + case DMA_TERMINATE_ALL: + spin_lock_irqsave(&pch->lock, flags); - /* Mark all desc done */ - list_for_each_entry(desc, &pch->work_list, node) - desc->status = DONE; + /* FLUSH the PL330 Channel thread */ + pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH); - spin_unlock_irqrestore(&pch->lock, flags); + /* Mark all desc done */ + list_for_each_entry_safe(desc, _dt, &pch->work_list , node) { + desc->status = DONE; + pch->completed = desc->txd.cookie; + list_move_tail(&desc->node, &list); + } - pl330_tasklet((unsigned long) pch); + list_splice_tail_init(&list, &pdmac->desc_pool); + spin_unlock_irqrestore(&pch->lock, flags); + break; + case DMA_SLAVE_CONFIG: + slave_config = (struct dma_slave_config *)arg; + + if (slave_config->direction == DMA_TO_DEVICE) { + if (slave_config->dst_addr) + pch->fifo_addr = slave_config->dst_addr; + if (slave_config->dst_addr_width) + pch->burst_sz = __ffs(slave_config->dst_addr_width); + if (slave_config->dst_maxburst) + pch->burst_len = slave_config->dst_maxburst; + } else if (slave_config->direction == DMA_FROM_DEVICE) { + if (slave_config->src_addr) + pch->fifo_addr = slave_config->src_addr; + if (slave_config->src_addr_width) + pch->burst_sz = __ffs(slave_config->src_addr_width); + if (slave_config->src_maxburst) + pch->burst_len = slave_config->src_maxburst; + } + break; + default: + dev_err(pch->dmac->pif.dev, "Not supported command.\n"); + return -ENXIO; + } return 0; } @@ -288,6 +356,9 @@ static void pl330_free_chan_resources(struct dma_chan *chan) pl330_release_channel(pch->pl330_chid); pch->pl330_chid = NULL; + if (pch->cyclic) + list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); + spin_unlock_irqrestore(&pch->lock, flags); } @@ -453,7 +524,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) if (peri) { desc->req.rqtype = peri->rqtype; - desc->req.peri = peri->peri_id; + desc->req.peri = pch->chan.chan_id; } else { desc->req.rqtype = MEMTOMEM; desc->req.peri = 0; @@ -524,6 +595,51 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) return burst_len; } +static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t dma_addr, size_t len, + size_t period_len, enum dma_data_direction direction) +{ + struct dma_pl330_desc *desc; + struct dma_pl330_chan *pch = to_pchan(chan); + dma_addr_t dst; + dma_addr_t src; + + desc = pl330_get_desc(pch); + if (!desc) { + dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n", + __func__, __LINE__); + return NULL; + } + + switch (direction) { + case DMA_TO_DEVICE: + desc->rqcfg.src_inc = 1; + desc->rqcfg.dst_inc = 0; + src = dma_addr; + dst = pch->fifo_addr; + break; + case DMA_FROM_DEVICE: + desc->rqcfg.src_inc = 0; + desc->rqcfg.dst_inc = 1; + src = pch->fifo_addr; + dst = dma_addr; + break; + default: + dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n", + __func__, __LINE__); + return NULL; + } + + desc->rqcfg.brst_size = pch->burst_sz; + desc->rqcfg.brst_len = 1; + + pch->cyclic = true; + + fill_px(&desc->px, dst, src, period_len); + + return &desc->txd; +} + static struct dma_async_tx_descriptor * pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, size_t len, unsigned long flags) @@ -579,7 +695,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, struct dma_pl330_peri *peri = chan->private; struct scatterlist *sg; unsigned long flags; - int i, burst_size; + int i; dma_addr_t addr; if (unlikely(!pch || !sgl || !sg_len || !peri)) @@ -595,8 +711,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, return NULL; } - addr = peri->fifo_addr; - burst_size = peri->burst_sz; + addr = pch->fifo_addr; first = NULL; @@ -644,7 +759,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, sg_dma_address(sg), addr, sg_dma_len(sg)); } - desc->rqcfg.brst_size = burst_size; + desc->rqcfg.brst_size = pch->burst_sz; desc->rqcfg.brst_len = 1; } @@ -696,6 +811,30 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) goto probe_err1; } + pdmac->clk = clk_get(&adev->dev, "dma"); + if (IS_ERR(pdmac->clk)) { + dev_err(&adev->dev, "Cannot get operation clock.\n"); + ret = -EINVAL; + goto probe_err1; + } + + amba_set_drvdata(adev, pdmac); + +#ifdef CONFIG_PM_RUNTIME + /* to use the runtime PM helper functions */ + pm_runtime_enable(&adev->dev); + + /* enable the power domain */ + if (pm_runtime_get_sync(&adev->dev)) { + dev_err(&adev->dev, "failed to get runtime pm\n"); + ret = -ENODEV; + goto probe_err1; + } +#else + /* enable dma clk */ + clk_enable(pdmac->clk); +#endif + irq = adev->irq[0]; ret = request_irq(irq, pl330_irq_handler, 0, dev_name(&adev->dev), pi); @@ -732,6 +871,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) case MEMTODEV: case DEVTOMEM: dma_cap_set(DMA_SLAVE, pd->cap_mask); + dma_cap_set(DMA_CYCLIC, pd->cap_mask); break; default: dev_err(&adev->dev, "DEVTODEV Not Supported\n"); @@ -747,11 +887,9 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&pch->lock); pch->pl330_chid = NULL; pch->chan.device = pd; - pch->chan.chan_id = i; pch->dmac = pdmac; /* Add the channel to the DMAC list */ - pd->chancnt++; list_add_tail(&pch->chan.device_node, &pd->channels); } @@ -760,6 +898,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pd->device_alloc_chan_resources = pl330_alloc_chan_resources; pd->device_free_chan_resources = pl330_free_chan_resources; pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy; + pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic; pd->device_tx_status = pl330_tx_status; pd->device_prep_slave_sg = pl330_prep_slave_sg; pd->device_control = pl330_control; @@ -771,8 +910,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) goto probe_err4; } - amba_set_drvdata(adev, pdmac); - dev_info(&adev->dev, "Loaded driver for PL330 DMAC-%d\n", adev->periphid); dev_info(&adev->dev, @@ -833,6 +970,13 @@ static int __devexit pl330_remove(struct amba_device *adev) res = &adev->res; release_mem_region(res->start, resource_size(res)); +#ifdef CONFIG_PM_RUNTIME + pm_runtime_put(&adev->dev); + pm_runtime_disable(&adev->dev); +#else + clk_disable(pdmac->clk); +#endif + kfree(pdmac); return 0; @@ -846,10 +990,49 @@ static struct amba_id pl330_ids[] = { { 0, 0 }, }; +#ifdef CONFIG_PM_RUNTIME +static int pl330_runtime_suspend(struct device *dev) +{ + struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev); + + if (!pdmac) { + dev_err(dev, "failed to get dmac\n"); + return -ENODEV; + } + + clk_disable(pdmac->clk); + + return 0; +} + +static int pl330_runtime_resume(struct device *dev) +{ + struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev); + + if (!pdmac) { + dev_err(dev, "failed to get dmac\n"); + return -ENODEV; + } + + clk_enable(pdmac->clk); + + return 0; +} +#else +#define pl330_runtime_suspend NULL +#define pl330_runtime_resume NULL +#endif /* CONFIG_PM_RUNTIME */ + +static const struct dev_pm_ops pl330_pm_ops = { + .runtime_suspend = pl330_runtime_suspend, + .runtime_resume = pl330_runtime_resume, +}; + static struct amba_driver pl330_driver = { .drv = { .owner = THIS_MODULE, .name = "dma-pl330", + .pm = &pl330_pm_ops, }, .id_table = pl330_ids, .probe = pl330_probe, diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 7f49235d14b9..81809c2b46ab 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -259,14 +259,23 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) return 0; } +static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan); + static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx) { struct sh_desc *desc = tx_to_sh_desc(tx), *chunk, *last = desc, *c; struct sh_dmae_chan *sh_chan = to_sh_chan(tx->chan); + struct sh_dmae_slave *param = tx->chan->private; dma_async_tx_callback callback = tx->callback; dma_cookie_t cookie; + bool power_up; + + spin_lock_irq(&sh_chan->desc_lock); - spin_lock_bh(&sh_chan->desc_lock); + if (list_empty(&sh_chan->ld_queue)) + power_up = true; + else + power_up = false; cookie = sh_chan->common.cookie; cookie++; @@ -302,7 +311,38 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx) tx->cookie, &last->async_tx, sh_chan->id, desc->hw.sar, desc->hw.tcr, desc->hw.dar); - spin_unlock_bh(&sh_chan->desc_lock); + if (power_up) { + sh_chan->pm_state = DMAE_PM_BUSY; + + pm_runtime_get(sh_chan->dev); + + spin_unlock_irq(&sh_chan->desc_lock); + + pm_runtime_barrier(sh_chan->dev); + + spin_lock_irq(&sh_chan->desc_lock); + + /* Have we been reset, while waiting? */ + if (sh_chan->pm_state != DMAE_PM_ESTABLISHED) { + dev_dbg(sh_chan->dev, "Bring up channel %d\n", + sh_chan->id); + if (param) { + const struct sh_dmae_slave_config *cfg = + param->config; + + dmae_set_dmars(sh_chan, cfg->mid_rid); + dmae_set_chcr(sh_chan, cfg->chcr); + } else { + dmae_init(sh_chan); + } + + if (sh_chan->pm_state == DMAE_PM_PENDING) + sh_chan_xfer_ld_queue(sh_chan); + sh_chan->pm_state = DMAE_PM_ESTABLISHED; + } + } + + spin_unlock_irq(&sh_chan->desc_lock); return cookie; } @@ -346,8 +386,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) struct sh_dmae_slave *param = chan->private; int ret; - pm_runtime_get_sync(sh_chan->dev); - /* * This relies on the guarantee from dmaengine that alloc_chan_resources * never runs concurrently with itself or free_chan_resources. @@ -367,31 +405,20 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) } param->config = cfg; - - dmae_set_dmars(sh_chan, cfg->mid_rid); - dmae_set_chcr(sh_chan, cfg->chcr); - } else { - dmae_init(sh_chan); } - spin_lock_bh(&sh_chan->desc_lock); while (sh_chan->descs_allocated < NR_DESCS_PER_CHANNEL) { - spin_unlock_bh(&sh_chan->desc_lock); desc = kzalloc(sizeof(struct sh_desc), GFP_KERNEL); - if (!desc) { - spin_lock_bh(&sh_chan->desc_lock); + if (!desc) break; - } dma_async_tx_descriptor_init(&desc->async_tx, &sh_chan->common); desc->async_tx.tx_submit = sh_dmae_tx_submit; desc->mark = DESC_IDLE; - spin_lock_bh(&sh_chan->desc_lock); list_add(&desc->node, &sh_chan->ld_free); sh_chan->descs_allocated++; } - spin_unlock_bh(&sh_chan->desc_lock); if (!sh_chan->descs_allocated) { ret = -ENOMEM; @@ -405,7 +432,7 @@ edescalloc: clear_bit(param->slave_id, sh_dmae_slave_used); etestused: efindslave: - pm_runtime_put(sh_chan->dev); + chan->private = NULL; return ret; } @@ -417,7 +444,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) struct sh_dmae_chan *sh_chan = to_sh_chan(chan); struct sh_desc *desc, *_desc; LIST_HEAD(list); - int descs = sh_chan->descs_allocated; /* Protect against ISR */ spin_lock_irq(&sh_chan->desc_lock); @@ -437,15 +463,12 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) chan->private = NULL; } - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irq(&sh_chan->desc_lock); list_splice_init(&sh_chan->ld_free, &list); sh_chan->descs_allocated = 0; - spin_unlock_bh(&sh_chan->desc_lock); - - if (descs > 0) - pm_runtime_put(sh_chan->dev); + spin_unlock_irq(&sh_chan->desc_lock); list_for_each_entry_safe(desc, _desc, &list, node) kfree(desc); @@ -534,6 +557,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c struct sh_desc *first = NULL, *new = NULL /* compiler... */; LIST_HEAD(tx_list); int chunks = 0; + unsigned long irq_flags; int i; if (!sg_len) @@ -544,7 +568,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c (SH_DMA_TCR_MAX + 1); /* Have to lock the whole loop to protect against concurrent release */ - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, irq_flags); /* * Chaining: @@ -590,7 +614,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c /* Put them back on the free list, so, they don't get lost */ list_splice_tail(&tx_list, &sh_chan->ld_free); - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, irq_flags); return &first->async_tx; @@ -599,7 +623,7 @@ err_get_desc: new->mark = DESC_IDLE; list_splice(&tx_list, &sh_chan->ld_free); - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, irq_flags); return NULL; } @@ -661,6 +685,7 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) { struct sh_dmae_chan *sh_chan = to_sh_chan(chan); + unsigned long flags; /* Only supports DMA_TERMINATE_ALL */ if (cmd != DMA_TERMINATE_ALL) @@ -669,7 +694,7 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, if (!chan) return -EINVAL; - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); dmae_halt(sh_chan); if (!list_empty(&sh_chan->ld_queue)) { @@ -678,9 +703,8 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, struct sh_desc, node); desc->partial = (desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) << sh_chan->xmit_shift; - } - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); sh_dmae_chan_ld_cleanup(sh_chan, true); @@ -695,8 +719,9 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all dma_cookie_t cookie = 0; dma_async_tx_callback callback = NULL; void *param = NULL; + unsigned long flags; - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); list_for_each_entry_safe(desc, _desc, &sh_chan->ld_queue, node) { struct dma_async_tx_descriptor *tx = &desc->async_tx; @@ -762,7 +787,13 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all async_tx_test_ack(&desc->async_tx)) || all) { /* Remove from ld_queue list */ desc->mark = DESC_IDLE; + list_move(&desc->node, &sh_chan->ld_free); + + if (list_empty(&sh_chan->ld_queue)) { + dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id); + pm_runtime_put(sh_chan->dev); + } } } @@ -773,7 +804,7 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all */ sh_chan->completed_cookie = sh_chan->common.cookie; - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); if (callback) callback(param); @@ -792,14 +823,14 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all) ; } +/* Called under spin_lock_irq(&sh_chan->desc_lock) */ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) { struct sh_desc *desc; - spin_lock_bh(&sh_chan->desc_lock); /* DMA work check */ if (dmae_is_busy(sh_chan)) - goto sh_chan_xfer_ld_queue_end; + return; /* Find the first not transferred descriptor */ list_for_each_entry(desc, &sh_chan->ld_queue, node) @@ -812,15 +843,18 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) dmae_start(sh_chan); break; } - -sh_chan_xfer_ld_queue_end: - spin_unlock_bh(&sh_chan->desc_lock); } static void sh_dmae_memcpy_issue_pending(struct dma_chan *chan) { struct sh_dmae_chan *sh_chan = to_sh_chan(chan); - sh_chan_xfer_ld_queue(sh_chan); + + spin_lock_irq(&sh_chan->desc_lock); + if (sh_chan->pm_state == DMAE_PM_ESTABLISHED) + sh_chan_xfer_ld_queue(sh_chan); + else + sh_chan->pm_state = DMAE_PM_PENDING; + spin_unlock_irq(&sh_chan->desc_lock); } static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, @@ -831,6 +865,7 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, dma_cookie_t last_used; dma_cookie_t last_complete; enum dma_status status; + unsigned long flags; sh_dmae_chan_ld_cleanup(sh_chan, false); @@ -841,7 +876,7 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, BUG_ON(last_complete < 0); dma_set_tx_state(txstate, last_complete, last_used, 0); - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); status = dma_async_is_complete(cookie, last_complete, last_used); @@ -859,7 +894,7 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, } } - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); return status; } @@ -912,6 +947,12 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev) list_splice_init(&sh_chan->ld_queue, &dl); + if (!list_empty(&dl)) { + dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id); + pm_runtime_put(sh_chan->dev); + } + sh_chan->pm_state = DMAE_PM_ESTABLISHED; + spin_unlock(&sh_chan->desc_lock); /* Complete all */ @@ -952,7 +993,7 @@ static void dmae_do_tasklet(unsigned long data) u32 sar_buf = sh_dmae_readl(sh_chan, SAR); u32 dar_buf = sh_dmae_readl(sh_chan, DAR); - spin_lock(&sh_chan->desc_lock); + spin_lock_irq(&sh_chan->desc_lock); list_for_each_entry(desc, &sh_chan->ld_queue, node) { if (desc->mark == DESC_SUBMITTED && ((desc->direction == DMA_FROM_DEVICE && @@ -965,10 +1006,10 @@ static void dmae_do_tasklet(unsigned long data) break; } } - spin_unlock(&sh_chan->desc_lock); - /* Next desc */ sh_chan_xfer_ld_queue(sh_chan); + spin_unlock_irq(&sh_chan->desc_lock); + sh_dmae_chan_ld_cleanup(sh_chan, false); } @@ -1036,7 +1077,9 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, return -ENOMEM; } - /* copy struct dma_device */ + new_sh_chan->pm_state = DMAE_PM_ESTABLISHED; + + /* reference struct dma_device */ new_sh_chan->common.device = &shdev->common; new_sh_chan->dev = shdev->common.dev; diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h index dc56576f9fdb..2b55a276dc5b 100644 --- a/drivers/dma/shdma.h +++ b/drivers/dma/shdma.h @@ -23,6 +23,12 @@ struct device; +enum dmae_pm_state { + DMAE_PM_ESTABLISHED, + DMAE_PM_BUSY, + DMAE_PM_PENDING, +}; + struct sh_dmae_chan { dma_cookie_t completed_cookie; /* The maximum cookie completed */ spinlock_t desc_lock; /* Descriptor operation lock */ @@ -38,6 +44,7 @@ struct sh_dmae_chan { u32 __iomem *base; char dev_id[16]; /* unique name per DMAC of channel */ int pm_error; + enum dmae_pm_state pm_state; }; struct sh_dmae_device { diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 467e4dcb20a0..13259cad0ceb 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -9,6 +9,7 @@ #include <linux/dma-mapping.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/export.h> #include <linux/dmaengine.h> #include <linux/platform_device.h> #include <linux/clk.h> diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index f69f90a61873..a4a398f2ef61 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -753,7 +753,7 @@ static int __devinit td_probe(struct platform_device *pdev) INIT_LIST_HEAD(&td->dma.channels); - for (i = 0; i < pdata->nr_channels; i++, td->dma.chancnt++) { + for (i = 0; i < pdata->nr_channels; i++) { struct timb_dma_chan *td_chan = &td->channels[i]; struct timb_dma_platform_data_channel *pchan = pdata->channels + i; @@ -762,12 +762,11 @@ static int __devinit td_probe(struct platform_device *pdev) if ((i % 2) == pchan->rx) { dev_err(&pdev->dev, "Wrong channel configuration\n"); err = -EINVAL; - goto err_tasklet_kill; + goto err_free_irq; } td_chan->chan.device = &td->dma; td_chan->chan.cookie = 1; - td_chan->chan.chan_id = i; spin_lock_init(&td_chan->lock); INIT_LIST_HEAD(&td_chan->active_list); INIT_LIST_HEAD(&td_chan->queue); diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c index a687a0d16962..a774c0ddaf5b 100644 --- a/drivers/edac/cpc925_edac.c +++ b/drivers/edac/cpc925_edac.c @@ -90,6 +90,7 @@ enum apimask_bits { ECC_MASK_ENABLE = (APIMASK_ECC_UE_H | APIMASK_ECC_CE_H | APIMASK_ECC_UE_L | APIMASK_ECC_CE_L), }; +#define APIMASK_ADI(n) CPC925_BIT(((n)+1)) /************************************************************ * Processor Interface Exception Register (APIEXCP) @@ -581,16 +582,73 @@ static void cpc925_mc_check(struct mem_ctl_info *mci) } /******************** CPU err device********************************/ +static u32 cpc925_cpu_mask_disabled(void) +{ + struct device_node *cpus; + struct device_node *cpunode = NULL; + static u32 mask = 0; + + /* use cached value if available */ + if (mask != 0) + return mask; + + mask = APIMASK_ADI0 | APIMASK_ADI1; + + cpus = of_find_node_by_path("/cpus"); + if (cpus == NULL) { + cpc925_printk(KERN_DEBUG, "No /cpus node !\n"); + return 0; + } + + while ((cpunode = of_get_next_child(cpus, cpunode)) != NULL) { + const u32 *reg = of_get_property(cpunode, "reg", NULL); + + if (strcmp(cpunode->type, "cpu")) { + cpc925_printk(KERN_ERR, "Not a cpu node in /cpus: %s\n", cpunode->name); + continue; + } + + if (reg == NULL || *reg > 2) { + cpc925_printk(KERN_ERR, "Bad reg value at %s\n", cpunode->full_name); + continue; + } + + mask &= ~APIMASK_ADI(*reg); + } + + if (mask != (APIMASK_ADI0 | APIMASK_ADI1)) { + /* We assume that each CPU sits on it's own PI and that + * for present CPUs the reg property equals to the PI + * interface id */ + cpc925_printk(KERN_WARNING, + "Assuming PI id is equal to CPU MPIC id!\n"); + } + + of_node_put(cpunode); + of_node_put(cpus); + + return mask; +} + /* Enable CPU Errors detection */ static void cpc925_cpu_init(struct cpc925_dev_info *dev_info) { u32 apimask; + u32 cpumask; apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET); - if ((apimask & CPU_MASK_ENABLE) == 0) { - apimask |= CPU_MASK_ENABLE; - __raw_writel(apimask, dev_info->vbase + REG_APIMASK_OFFSET); + + cpumask = cpc925_cpu_mask_disabled(); + if (apimask & cpumask) { + cpc925_printk(KERN_WARNING, "CPU(s) not present, " + "but enabled in APIMASK, disabling\n"); + apimask &= ~cpumask; } + + if ((apimask & CPU_MASK_ENABLE) == 0) + apimask |= CPU_MASK_ENABLE; + + __raw_writel(apimask, dev_info->vbase + REG_APIMASK_OFFSET); } /* Disable CPU Errors detection */ @@ -622,6 +680,9 @@ static void cpc925_cpu_check(struct edac_device_ctl_info *edac_dev) if ((apiexcp & CPU_EXCP_DETECTED) == 0) return; + if ((apiexcp & ~cpc925_cpu_mask_disabled()) == 0) + return; + apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET); cpc925_printk(KERN_INFO, "Processor Interface Fault\n" "Processor Interface register dump:\n"); diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c index a4987e03f59e..73c3e26a0bce 100644 --- a/drivers/edac/mce_amd_inj.c +++ b/drivers/edac/mce_amd_inj.c @@ -13,6 +13,7 @@ #include <linux/kobject.h> #include <linux/sysdev.h> #include <linux/edac.h> +#include <linux/module.h> #include <asm/mce.h> #include "mce_amd.h" diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 0de7d8770891..38400963e245 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -205,7 +205,7 @@ static struct platform_driver ppc4xx_edac_driver = { .remove = ppc4xx_edac_remove, .driver = { .owner = THIS_MODULE, - .name = PPC4XX_EDAC_MODULE_NAME + .name = PPC4XX_EDAC_MODULE_NAME, .of_match_table = ppc4xx_edac_match, }, }; diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 57c3973093ad..0f90e0071875 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <asm/byteorder.h> diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index f1b7f659d3c9..e22957665808 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -151,7 +151,8 @@ edd_show_host_bus(struct edd_device *edev, char *buf) p += scnprintf(p, left, "\tbase_address: %x\n", info->params.interface_path.isa.base_address); } else if (!strncmp(info->params.host_bus_type, "PCIX", 4) || - !strncmp(info->params.host_bus_type, "PCI", 3)) { + !strncmp(info->params.host_bus_type, "PCI", 3) || + !strncmp(info->params.host_bus_type, "XPRS", 4)) { p += scnprintf(p, left, "\t%02x:%02x.%d channel: %u\n", info->params.interface_path.pci.bus, @@ -159,7 +160,6 @@ edd_show_host_bus(struct edd_device *edev, char *buf) info->params.interface_path.pci.function, info->params.interface_path.pci.channel); } else if (!strncmp(info->params.host_bus_type, "IBND", 4) || - !strncmp(info->params.host_bus_type, "XPRS", 4) || !strncmp(info->params.host_bus_type, "HTPT", 4)) { p += scnprintf(p, left, "\tTBD: %llx\n", @@ -668,7 +668,7 @@ edd_get_pci_dev(struct edd_device *edev) { struct edd_info *info = edd_dev_get_info(edev); - if (edd_dev_is_type(edev, "PCI")) { + if (edd_dev_is_type(edev, "PCI") || edd_dev_is_type(edev, "XPRS")) { return pci_get_bus_and_slot(info->params.interface_path.pci.bus, PCI_DEVFN(info->params.interface_path.pci.slot, info->params.interface_path.pci. diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index aa83de9db1b9..c4e7c59d1c63 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -27,6 +27,7 @@ #include <linux/kdebug.h> #include <linux/reboot.h> #include <linux/efi.h> +#include <linux/module.h> #define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */ /* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */ diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8b3c745b1b05..8482a23887dc 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -95,14 +95,18 @@ config GPIO_EP93XX depends on ARCH_EP93XX select GPIO_GENERIC -config GPIO_EXYNOS4 - def_bool y - depends on CPU_EXYNOS4210 - config GPIO_MPC5200 def_bool y depends on PPC_MPC52xx +config GPIO_MPC8XXX + bool "MPC512x/MPC8xxx GPIO support" + depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \ + FSL_SOC_BOOKE || PPC_86xx + help + Say Y here if you're going to use hardware that connects to the + MPC512x/831x/834x/837x/8572/8610 GPIOs. + config GPIO_MSM_V1 tristate "Qualcomm MSM GPIO v1" depends on GPIOLIB && ARCH_MSM @@ -131,18 +135,6 @@ config GPIO_MXS select GPIO_GENERIC select GENERIC_IRQ_CHIP -config GPIO_PLAT_SAMSUNG - def_bool y - depends on SAMSUNG_GPIOLIB_4BIT - -config GPIO_S5PC100 - def_bool y - depends on CPU_S5PC100 - -config GPIO_S5PV210 - def_bool y - depends on CPU_S5PV210 - config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 19c5d27b6d2e..dbcb0bcfd8da 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o -obj-$(CONFIG_GPIO_EXYNOS4) += gpio-exynos4.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_MACH_KS8695) += gpio-ks8695.o @@ -30,6 +29,7 @@ obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o +obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o @@ -42,10 +42,7 @@ obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_PLAT_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o - -obj-$(CONFIG_GPIO_PLAT_SAMSUNG) += gpio-plat-samsung.o -obj-$(CONFIG_GPIO_S5PC100) += gpio-s5pc100.o -obj-$(CONFIG_GPIO_S5PV210) += gpio-s5pv210.o +obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index ff525c0958dd..a31ad6f5d910 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -15,6 +15,7 @@ #include <linux/spi/74x164.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/module.h> struct gen_74x164_chip { struct spi_device *spi; diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 7aafbb437339..1c0fc3756cb1 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -15,6 +15,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/init.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/io.h> #include <linux/gpio.h> diff --git a/drivers/gpio/gpio-exynos4.c b/drivers/gpio/gpio-exynos4.c deleted file mode 100644 index d24b337cf1ac..000000000000 --- a/drivers/gpio/gpio-exynos4.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * EXYNOS4 - GPIOlib support - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/kernel.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/gpio.h> - -#include <mach/map.h> - -#include <plat/gpio-core.h> -#include <plat/gpio-cfg.h> -#include <plat/gpio-cfg-helpers.h> - -int s3c_gpio_setpull_exynos4(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull) -{ - if (pull == S3C_GPIO_PULL_UP) - pull = 3; - - return s3c_gpio_setpull_updown(chip, off, pull); -} - -s3c_gpio_pull_t s3c_gpio_getpull_exynos4(struct s3c_gpio_chip *chip, - unsigned int off) -{ - s3c_gpio_pull_t pull; - - pull = s3c_gpio_getpull_updown(chip, off); - if (pull == 3) - pull = S3C_GPIO_PULL_UP; - - return pull; -} - -static struct s3c_gpio_cfg gpio_cfg = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_exynos4, - .get_pull = s3c_gpio_getpull_exynos4, -}; - -static struct s3c_gpio_cfg gpio_cfg_noint = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_exynos4, - .get_pull = s3c_gpio_getpull_exynos4, -}; - -/* - * Following are the gpio banks in v310. - * - * The 'config' member when left to NULL, is initialized to the default - * structure gpio_cfg in the init function below. - * - * The 'base' member is also initialized in the init function below. - * Note: The initialization of 'base' member of s3c_gpio_chip structure - * uses the above macro and depends on the banks being listed in order here. - */ -static struct s3c_gpio_chip exynos4_gpio_part1_4bit[] = { - { - .chip = { - .base = EXYNOS4_GPA0(0), - .ngpio = EXYNOS4_GPIO_A0_NR, - .label = "GPA0", - }, - }, { - .chip = { - .base = EXYNOS4_GPA1(0), - .ngpio = EXYNOS4_GPIO_A1_NR, - .label = "GPA1", - }, - }, { - .chip = { - .base = EXYNOS4_GPB(0), - .ngpio = EXYNOS4_GPIO_B_NR, - .label = "GPB", - }, - }, { - .chip = { - .base = EXYNOS4_GPC0(0), - .ngpio = EXYNOS4_GPIO_C0_NR, - .label = "GPC0", - }, - }, { - .chip = { - .base = EXYNOS4_GPC1(0), - .ngpio = EXYNOS4_GPIO_C1_NR, - .label = "GPC1", - }, - }, { - .chip = { - .base = EXYNOS4_GPD0(0), - .ngpio = EXYNOS4_GPIO_D0_NR, - .label = "GPD0", - }, - }, { - .chip = { - .base = EXYNOS4_GPD1(0), - .ngpio = EXYNOS4_GPIO_D1_NR, - .label = "GPD1", - }, - }, { - .chip = { - .base = EXYNOS4_GPE0(0), - .ngpio = EXYNOS4_GPIO_E0_NR, - .label = "GPE0", - }, - }, { - .chip = { - .base = EXYNOS4_GPE1(0), - .ngpio = EXYNOS4_GPIO_E1_NR, - .label = "GPE1", - }, - }, { - .chip = { - .base = EXYNOS4_GPE2(0), - .ngpio = EXYNOS4_GPIO_E2_NR, - .label = "GPE2", - }, - }, { - .chip = { - .base = EXYNOS4_GPE3(0), - .ngpio = EXYNOS4_GPIO_E3_NR, - .label = "GPE3", - }, - }, { - .chip = { - .base = EXYNOS4_GPE4(0), - .ngpio = EXYNOS4_GPIO_E4_NR, - .label = "GPE4", - }, - }, { - .chip = { - .base = EXYNOS4_GPF0(0), - .ngpio = EXYNOS4_GPIO_F0_NR, - .label = "GPF0", - }, - }, { - .chip = { - .base = EXYNOS4_GPF1(0), - .ngpio = EXYNOS4_GPIO_F1_NR, - .label = "GPF1", - }, - }, { - .chip = { - .base = EXYNOS4_GPF2(0), - .ngpio = EXYNOS4_GPIO_F2_NR, - .label = "GPF2", - }, - }, { - .chip = { - .base = EXYNOS4_GPF3(0), - .ngpio = EXYNOS4_GPIO_F3_NR, - .label = "GPF3", - }, - }, -}; - -static struct s3c_gpio_chip exynos4_gpio_part2_4bit[] = { - { - .chip = { - .base = EXYNOS4_GPJ0(0), - .ngpio = EXYNOS4_GPIO_J0_NR, - .label = "GPJ0", - }, - }, { - .chip = { - .base = EXYNOS4_GPJ1(0), - .ngpio = EXYNOS4_GPIO_J1_NR, - .label = "GPJ1", - }, - }, { - .chip = { - .base = EXYNOS4_GPK0(0), - .ngpio = EXYNOS4_GPIO_K0_NR, - .label = "GPK0", - }, - }, { - .chip = { - .base = EXYNOS4_GPK1(0), - .ngpio = EXYNOS4_GPIO_K1_NR, - .label = "GPK1", - }, - }, { - .chip = { - .base = EXYNOS4_GPK2(0), - .ngpio = EXYNOS4_GPIO_K2_NR, - .label = "GPK2", - }, - }, { - .chip = { - .base = EXYNOS4_GPK3(0), - .ngpio = EXYNOS4_GPIO_K3_NR, - .label = "GPK3", - }, - }, { - .chip = { - .base = EXYNOS4_GPL0(0), - .ngpio = EXYNOS4_GPIO_L0_NR, - .label = "GPL0", - }, - }, { - .chip = { - .base = EXYNOS4_GPL1(0), - .ngpio = EXYNOS4_GPIO_L1_NR, - .label = "GPL1", - }, - }, { - .chip = { - .base = EXYNOS4_GPL2(0), - .ngpio = EXYNOS4_GPIO_L2_NR, - .label = "GPL2", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY0(0), - .ngpio = EXYNOS4_GPIO_Y0_NR, - .label = "GPY0", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY1(0), - .ngpio = EXYNOS4_GPIO_Y1_NR, - .label = "GPY1", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY2(0), - .ngpio = EXYNOS4_GPIO_Y2_NR, - .label = "GPY2", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY3(0), - .ngpio = EXYNOS4_GPIO_Y3_NR, - .label = "GPY3", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY4(0), - .ngpio = EXYNOS4_GPIO_Y4_NR, - .label = "GPY4", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY5(0), - .ngpio = EXYNOS4_GPIO_Y5_NR, - .label = "GPY5", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY6(0), - .ngpio = EXYNOS4_GPIO_Y6_NR, - .label = "GPY6", - }, - }, { - .base = (S5P_VA_GPIO2 + 0xC00), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(0), - .chip = { - .base = EXYNOS4_GPX0(0), - .ngpio = EXYNOS4_GPIO_X0_NR, - .label = "GPX0", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO2 + 0xC20), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(8), - .chip = { - .base = EXYNOS4_GPX1(0), - .ngpio = EXYNOS4_GPIO_X1_NR, - .label = "GPX1", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO2 + 0xC40), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(16), - .chip = { - .base = EXYNOS4_GPX2(0), - .ngpio = EXYNOS4_GPIO_X2_NR, - .label = "GPX2", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO2 + 0xC60), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(24), - .chip = { - .base = EXYNOS4_GPX3(0), - .ngpio = EXYNOS4_GPIO_X3_NR, - .label = "GPX3", - .to_irq = samsung_gpiolib_to_irq, - }, - }, -}; - -static struct s3c_gpio_chip exynos4_gpio_part3_4bit[] = { - { - .chip = { - .base = EXYNOS4_GPZ(0), - .ngpio = EXYNOS4_GPIO_Z_NR, - .label = "GPZ", - }, - }, -}; - -static __init int exynos4_gpiolib_init(void) -{ - struct s3c_gpio_chip *chip; - int i; - int group = 0; - int nr_chips; - - /* GPIO part 1 */ - - chip = exynos4_gpio_part1_4bit; - nr_chips = ARRAY_SIZE(exynos4_gpio_part1_4bit); - - for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) { - chip->config = &gpio_cfg; - /* Assign the GPIO interrupt group */ - chip->group = group++; - } - if (chip->base == NULL) - chip->base = S5P_VA_GPIO1 + (i) * 0x20; - } - - samsung_gpiolib_add_4bit_chips(exynos4_gpio_part1_4bit, nr_chips); - - /* GPIO part 2 */ - - chip = exynos4_gpio_part2_4bit; - nr_chips = ARRAY_SIZE(exynos4_gpio_part2_4bit); - - for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) { - chip->config = &gpio_cfg; - /* Assign the GPIO interrupt group */ - chip->group = group++; - } - if (chip->base == NULL) - chip->base = S5P_VA_GPIO2 + (i) * 0x20; - } - - samsung_gpiolib_add_4bit_chips(exynos4_gpio_part2_4bit, nr_chips); - - /* GPIO part 3 */ - - chip = exynos4_gpio_part3_4bit; - nr_chips = ARRAY_SIZE(exynos4_gpio_part3_4bit); - - for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) { - chip->config = &gpio_cfg; - /* Assign the GPIO interrupt group */ - chip->group = group++; - } - if (chip->base == NULL) - chip->base = S5P_VA_GPIO3 + (i) * 0x20; - } - - samsung_gpiolib_add_4bit_chips(exynos4_gpio_part3_4bit, nr_chips); - s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS); - s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS); - - return 0; -} -core_initcall(exynos4_gpiolib_init); diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index b3b4652e89ec..2de57ce5feb6 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -26,6 +26,7 @@ #include <linux/spi/mc33880.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/module.h> #define DRIVER_NAME "mc33880" diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 1ef46e6c2a2a..c5d83a8a91c2 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -5,6 +5,7 @@ #include <linux/kernel.h> #include <linux/device.h> #include <linux/mutex.h> +#include <linux/module.h> #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/spi/spi.h> diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 3aa6beec8c1e..ea8e73869250 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -14,6 +14,7 @@ * 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/module.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/pci.h> diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c index 52d3ed208105..2c7cef367fc0 100644 --- a/drivers/gpio/gpio-mpc5200.c +++ b/drivers/gpio/gpio-mpc5200.c @@ -23,6 +23,7 @@ #include <linux/of_gpio.h> #include <linux/io.h> #include <linux/of_platform.h> +#include <linux/module.h> #include <asm/gpio.h> #include <asm/mpc52xx.h> diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c new file mode 100644 index 000000000000..ec3fcf0a7e12 --- /dev/null +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -0,0 +1,398 @@ +/* + * GPIOs on MPC512x/8349/8572/8610 and compatible + * + * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/irq.h> + +#define MPC8XXX_GPIO_PINS 32 + +#define GPIO_DIR 0x00 +#define GPIO_ODR 0x04 +#define GPIO_DAT 0x08 +#define GPIO_IER 0x0c +#define GPIO_IMR 0x10 +#define GPIO_ICR 0x14 +#define GPIO_ICR2 0x18 + +struct mpc8xxx_gpio_chip { + struct of_mm_gpio_chip mm_gc; + spinlock_t lock; + + /* + * shadowed data register to be able to clear/set output pins in + * open drain mode safely + */ + u32 data; + struct irq_host *irq; + void *of_dev_id_data; +}; + +static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) +{ + return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio); +} + +static inline struct mpc8xxx_gpio_chip * +to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm) +{ + return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc); +} + +static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + + mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT); +} + +/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs + * defined as output cannot be determined by reading GPDAT register, + * so we use shadow data register instead. The status of input pins + * is determined by reading GPDAT register. + */ +static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + u32 val; + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + + val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR); + + return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio); +} + +static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + + return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio); +} + +static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + if (val) + mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio); + else + mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio); + + out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); +} + +static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + + return 0; +} + +static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + unsigned long flags; + + mpc8xxx_gpio_set(gc, gpio, val); + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + + return 0; +} + +static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + + if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS) + return irq_create_mapping(mpc8xxx_gc->irq, offset); + else + return -ENXIO; +} + +static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned int mask; + + mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR); + if (mask) + generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, + 32 - ffs(mask))); + chip->irq_eoi(&desc->irq_data); +} + +static void mpc8xxx_irq_unmask(struct irq_data *d) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); +} + +static void mpc8xxx_irq_mask(struct irq_data *d) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); +} + +static void mpc8xxx_irq_ack(struct irq_data *d) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + + out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); +} + +static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned long flags; + + switch (flow_type) { + case IRQ_TYPE_EDGE_FALLING: + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + setbits32(mm->regs + GPIO_ICR, + mpc8xxx_gpio2mask(irqd_to_hwirq(d))); + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + break; + + case IRQ_TYPE_EDGE_BOTH: + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + clrbits32(mm->regs + GPIO_ICR, + mpc8xxx_gpio2mask(irqd_to_hwirq(d))); + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned long gpio = irqd_to_hwirq(d); + void __iomem *reg; + unsigned int shift; + unsigned long flags; + + if (gpio < 16) { + reg = mm->regs + GPIO_ICR; + shift = (15 - gpio) * 2; + } else { + reg = mm->regs + GPIO_ICR2; + shift = (15 - (gpio % 16)) * 2; + } + + switch (flow_type) { + case IRQ_TYPE_EDGE_FALLING: + case IRQ_TYPE_LEVEL_LOW: + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + clrsetbits_be32(reg, 3 << shift, 2 << shift); + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + break; + + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_LEVEL_HIGH: + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + clrsetbits_be32(reg, 3 << shift, 1 << shift); + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + break; + + case IRQ_TYPE_EDGE_BOTH: + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + clrbits32(reg, 3 << shift); + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static struct irq_chip mpc8xxx_irq_chip = { + .name = "mpc8xxx-gpio", + .irq_unmask = mpc8xxx_irq_unmask, + .irq_mask = mpc8xxx_irq_mask, + .irq_ack = mpc8xxx_irq_ack, + .irq_set_type = mpc8xxx_irq_set_type, +}; + +static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; + + if (mpc8xxx_gc->of_dev_id_data) + mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data; + + irq_set_chip_data(virq, h->host_data); + irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); + irq_set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, + unsigned int *out_flags) + +{ + /* interrupt sense values coming from the device tree equal either + * EDGE_FALLING or EDGE_BOTH + */ + *out_hwirq = intspec[0]; + *out_flags = intspec[1]; + + return 0; +} + +static struct irq_host_ops mpc8xxx_gpio_irq_ops = { + .map = mpc8xxx_gpio_irq_map, + .xlate = mpc8xxx_gpio_irq_xlate, +}; + +static struct of_device_id mpc8xxx_gpio_ids[] __initdata = { + { .compatible = "fsl,mpc8349-gpio", }, + { .compatible = "fsl,mpc8572-gpio", }, + { .compatible = "fsl,mpc8610-gpio", }, + { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, }, + { .compatible = "fsl,pq3-gpio", }, + { .compatible = "fsl,qoriq-gpio", }, + {} +}; + +static void __init mpc8xxx_add_controller(struct device_node *np) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc; + struct of_mm_gpio_chip *mm_gc; + struct gpio_chip *gc; + const struct of_device_id *id; + unsigned hwirq; + int ret; + + mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL); + if (!mpc8xxx_gc) { + ret = -ENOMEM; + goto err; + } + + spin_lock_init(&mpc8xxx_gc->lock); + + mm_gc = &mpc8xxx_gc->mm_gc; + gc = &mm_gc->gc; + + mm_gc->save_regs = mpc8xxx_gpio_save_regs; + gc->ngpio = MPC8XXX_GPIO_PINS; + gc->direction_input = mpc8xxx_gpio_dir_in; + gc->direction_output = mpc8xxx_gpio_dir_out; + if (of_device_is_compatible(np, "fsl,mpc8572-gpio")) + gc->get = mpc8572_gpio_get; + else + gc->get = mpc8xxx_gpio_get; + gc->set = mpc8xxx_gpio_set; + gc->to_irq = mpc8xxx_gpio_to_irq; + + ret = of_mm_gpiochip_add(np, mm_gc); + if (ret) + goto err; + + hwirq = irq_of_parse_and_map(np, 0); + if (hwirq == NO_IRQ) + goto skip_irq; + + mpc8xxx_gc->irq = + irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS, + &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS); + if (!mpc8xxx_gc->irq) + goto skip_irq; + + id = of_match_node(mpc8xxx_gpio_ids, np); + if (id) + mpc8xxx_gc->of_dev_id_data = id->data; + + mpc8xxx_gc->irq->host_data = mpc8xxx_gc; + + /* ack and mask all irqs */ + out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); + out_be32(mm_gc->regs + GPIO_IMR, 0); + + irq_set_handler_data(hwirq, mpc8xxx_gc); + irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); + +skip_irq: + return; + +err: + pr_err("%s: registration failed with status %d\n", + np->full_name, ret); + kfree(mpc8xxx_gc); + + return; +} + +static int __init mpc8xxx_add_gpiochips(void) +{ + struct device_node *np; + + for_each_matching_node(np, mpc8xxx_gpio_ids) + mpc8xxx_add_controller(np); + + return 0; +} +arch_initcall(mpc8xxx_add_gpiochips); diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index b81c98992114..e79147634573 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -29,6 +29,7 @@ #include <linux/basic_mmio_gpio.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/module.h> #include <asm-generic/bug.h> #include <asm/mach/irq.h> diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 292b50481db9..385c58e8405b 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -28,6 +28,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/basic_mmio_gpio.h> +#include <linux/module.h> #include <mach/mxs.h> #define MXS_SET 0x4 diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 7369fdda92b0..3e1f1ecd07be 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -23,6 +23,7 @@ #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/i2c/pcf857x.h> +#include <linux/module.h> static const struct i2c_device_id pcf857x_id[] = { diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 1e8a4a538810..a6008e123d04 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -14,6 +14,7 @@ * 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/module.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/gpio.h> diff --git a/drivers/gpio/gpio-plat-samsung.c b/drivers/gpio/gpio-plat-samsung.c deleted file mode 100644 index ef67f1952a72..000000000000 --- a/drivers/gpio/gpio-plat-samsung.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * http://armlinux.simtec.co.uk/ - * - * Copyright (c) 2009 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * SAMSUNG - GPIOlib support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <plat/gpio-core.h> -#include <plat/gpio-cfg.h> -#include <plat/gpio-cfg-helpers.h> - -#ifndef DEBUG_GPIO -#define gpio_dbg(x...) do { } while (0) -#else -#define gpio_dbg(x...) printk(KERN_DEBUG x) -#endif - -/* The samsung_gpiolib_4bit routines are to control the gpio banks where - * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the - * following example: - * - * base + 0x00: Control register, 4 bits per gpio - * gpio n: 4 bits starting at (4*n) - * 0000 = input, 0001 = output, others mean special-function - * base + 0x04: Data register, 1 bit per gpio - * bit n: data bit n - * - * Note, since the data register is one bit per gpio and is at base + 0x4 - * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of - * the output. -*/ - -static int samsung_gpiolib_4bit_input(struct gpio_chip *chip, - unsigned int offset) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - unsigned long con; - - con = __raw_readl(base + GPIOCON_OFF); - con &= ~(0xf << con_4bit_shift(offset)); - __raw_writel(con, base + GPIOCON_OFF); - - gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con); - - return 0; -} - -static int samsung_gpiolib_4bit_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - unsigned long con; - unsigned long dat; - - con = __raw_readl(base + GPIOCON_OFF); - con &= ~(0xf << con_4bit_shift(offset)); - con |= 0x1 << con_4bit_shift(offset); - - dat = __raw_readl(base + GPIODAT_OFF); - - if (value) - dat |= 1 << offset; - else - dat &= ~(1 << offset); - - __raw_writel(dat, base + GPIODAT_OFF); - __raw_writel(con, base + GPIOCON_OFF); - __raw_writel(dat, base + GPIODAT_OFF); - - gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); - - return 0; -} - -/* The next set of routines are for the case where the GPIO configuration - * registers are 4 bits per GPIO but there is more than one register (the - * bank has more than 8 GPIOs. - * - * This case is the similar to the 4 bit case, but the registers are as - * follows: - * - * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs) - * gpio n: 4 bits starting at (4*n) - * 0000 = input, 0001 = output, others mean special-function - * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs) - * gpio n: 4 bits starting at (4*n) - * 0000 = input, 0001 = output, others mean special-function - * base + 0x08: Data register, 1 bit per gpio - * bit n: data bit n - * - * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we - * store the 'base + 0x4' address so that these routines see the data - * register at ourchip->base + 0x04. - */ - -static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, - unsigned int offset) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - void __iomem *regcon = base; - unsigned long con; - - if (offset > 7) - offset -= 8; - else - regcon -= 4; - - con = __raw_readl(regcon); - con &= ~(0xf << con_4bit_shift(offset)); - __raw_writel(con, regcon); - - gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con); - - return 0; -} - -static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - void __iomem *regcon = base; - unsigned long con; - unsigned long dat; - unsigned con_offset = offset; - - if (con_offset > 7) - con_offset -= 8; - else - regcon -= 4; - - con = __raw_readl(regcon); - con &= ~(0xf << con_4bit_shift(con_offset)); - con |= 0x1 << con_4bit_shift(con_offset); - - dat = __raw_readl(base + GPIODAT_OFF); - - if (value) - dat |= 1 << offset; - else - dat &= ~(1 << offset); - - __raw_writel(dat, base + GPIODAT_OFF); - __raw_writel(con, regcon); - __raw_writel(dat, base + GPIODAT_OFF); - - gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); - - return 0; -} - -void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip) -{ - chip->chip.direction_input = samsung_gpiolib_4bit_input; - chip->chip.direction_output = samsung_gpiolib_4bit_output; - chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); -} - -void __init samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip) -{ - chip->chip.direction_input = samsung_gpiolib_4bit2_input; - chip->chip.direction_output = samsung_gpiolib_4bit2_output; - chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); -} - -void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip, - int nr_chips) -{ - for (; nr_chips > 0; nr_chips--, chip++) { - samsung_gpiolib_add_4bit(chip); - s3c_gpiolib_add(chip); - } -} - -void __init samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip, - int nr_chips) -{ - for (; nr_chips > 0; nr_chips--, chip++) { - samsung_gpiolib_add_4bit2(chip); - s3c_gpiolib_add(chip); - } -} - -void __init samsung_gpiolib_add_2bit_chips(struct s3c_gpio_chip *chip, - int nr_chips) -{ - for (; nr_chips > 0; nr_chips--, chip++) - s3c_gpiolib_add(chip); -} diff --git a/drivers/gpio/gpio-s5pc100.c b/drivers/gpio/gpio-s5pc100.c deleted file mode 100644 index 7f87b0c76e0b..000000000000 --- a/drivers/gpio/gpio-s5pc100.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * S5PC100 - GPIOlib support - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Copyright 2009 Samsung Electronics Co - * Kyungmin Park <kyungmin.park@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/gpio.h> - -#include <mach/map.h> -#include <mach/regs-gpio.h> - -#include <plat/gpio-core.h> -#include <plat/gpio-cfg.h> -#include <plat/gpio-cfg-helpers.h> - -/* S5PC100 GPIO bank summary: - * - * Bank GPIOs Style INT Type - * A0 8 4Bit GPIO_INT0 - * A1 5 4Bit GPIO_INT1 - * B 8 4Bit GPIO_INT2 - * C 5 4Bit GPIO_INT3 - * D 7 4Bit GPIO_INT4 - * E0 8 4Bit GPIO_INT5 - * E1 6 4Bit GPIO_INT6 - * F0 8 4Bit GPIO_INT7 - * F1 8 4Bit GPIO_INT8 - * F2 8 4Bit GPIO_INT9 - * F3 4 4Bit GPIO_INT10 - * G0 8 4Bit GPIO_INT11 - * G1 3 4Bit GPIO_INT12 - * G2 7 4Bit GPIO_INT13 - * G3 7 4Bit GPIO_INT14 - * H0 8 4Bit WKUP_INT - * H1 8 4Bit WKUP_INT - * H2 8 4Bit WKUP_INT - * H3 8 4Bit WKUP_INT - * I 8 4Bit GPIO_INT15 - * J0 8 4Bit GPIO_INT16 - * J1 5 4Bit GPIO_INT17 - * J2 8 4Bit GPIO_INT18 - * J3 8 4Bit GPIO_INT19 - * J4 4 4Bit GPIO_INT20 - * K0 8 4Bit None - * K1 6 4Bit None - * K2 8 4Bit None - * K3 8 4Bit None - * L0 8 4Bit None - * L1 8 4Bit None - * L2 8 4Bit None - * L3 8 4Bit None - */ - -static struct s3c_gpio_cfg gpio_cfg = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_cfg gpio_cfg_eint = { - .cfg_eint = 0xf, - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_cfg gpio_cfg_noint = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -/* - * GPIO bank's base address given the index of the bank in the - * list of all gpio banks. - */ -#define S5PC100_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)) - -/* - * Following are the gpio banks in S5PC100. - * - * The 'config' member when left to NULL, is initialized to the default - * structure gpio_cfg in the init function below. - * - * The 'base' member is also initialized in the init function below. - * Note: The initialization of 'base' member of s3c_gpio_chip structure - * uses the above macro and depends on the banks being listed in order here. - */ -static struct s3c_gpio_chip s5pc100_gpio_chips[] = { - { - .chip = { - .base = S5PC100_GPA0(0), - .ngpio = S5PC100_GPIO_A0_NR, - .label = "GPA0", - }, - }, { - .chip = { - .base = S5PC100_GPA1(0), - .ngpio = S5PC100_GPIO_A1_NR, - .label = "GPA1", - }, - }, { - .chip = { - .base = S5PC100_GPB(0), - .ngpio = S5PC100_GPIO_B_NR, - .label = "GPB", - }, - }, { - .chip = { - .base = S5PC100_GPC(0), - .ngpio = S5PC100_GPIO_C_NR, - .label = "GPC", - }, - }, { - .chip = { - .base = S5PC100_GPD(0), - .ngpio = S5PC100_GPIO_D_NR, - .label = "GPD", - }, - }, { - .chip = { - .base = S5PC100_GPE0(0), - .ngpio = S5PC100_GPIO_E0_NR, - .label = "GPE0", - }, - }, { - .chip = { - .base = S5PC100_GPE1(0), - .ngpio = S5PC100_GPIO_E1_NR, - .label = "GPE1", - }, - }, { - .chip = { - .base = S5PC100_GPF0(0), - .ngpio = S5PC100_GPIO_F0_NR, - .label = "GPF0", - }, - }, { - .chip = { - .base = S5PC100_GPF1(0), - .ngpio = S5PC100_GPIO_F1_NR, - .label = "GPF1", - }, - }, { - .chip = { - .base = S5PC100_GPF2(0), - .ngpio = S5PC100_GPIO_F2_NR, - .label = "GPF2", - }, - }, { - .chip = { - .base = S5PC100_GPF3(0), - .ngpio = S5PC100_GPIO_F3_NR, - .label = "GPF3", - }, - }, { - .chip = { - .base = S5PC100_GPG0(0), - .ngpio = S5PC100_GPIO_G0_NR, - .label = "GPG0", - }, - }, { - .chip = { - .base = S5PC100_GPG1(0), - .ngpio = S5PC100_GPIO_G1_NR, - .label = "GPG1", - }, - }, { - .chip = { - .base = S5PC100_GPG2(0), - .ngpio = S5PC100_GPIO_G2_NR, - .label = "GPG2", - }, - }, { - .chip = { - .base = S5PC100_GPG3(0), - .ngpio = S5PC100_GPIO_G3_NR, - .label = "GPG3", - }, - }, { - .chip = { - .base = S5PC100_GPI(0), - .ngpio = S5PC100_GPIO_I_NR, - .label = "GPI", - }, - }, { - .chip = { - .base = S5PC100_GPJ0(0), - .ngpio = S5PC100_GPIO_J0_NR, - .label = "GPJ0", - }, - }, { - .chip = { - .base = S5PC100_GPJ1(0), - .ngpio = S5PC100_GPIO_J1_NR, - .label = "GPJ1", - }, - }, { - .chip = { - .base = S5PC100_GPJ2(0), - .ngpio = S5PC100_GPIO_J2_NR, - .label = "GPJ2", - }, - }, { - .chip = { - .base = S5PC100_GPJ3(0), - .ngpio = S5PC100_GPIO_J3_NR, - .label = "GPJ3", - }, - }, { - .chip = { - .base = S5PC100_GPJ4(0), - .ngpio = S5PC100_GPIO_J4_NR, - .label = "GPJ4", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPK0(0), - .ngpio = S5PC100_GPIO_K0_NR, - .label = "GPK0", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPK1(0), - .ngpio = S5PC100_GPIO_K1_NR, - .label = "GPK1", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPK2(0), - .ngpio = S5PC100_GPIO_K2_NR, - .label = "GPK2", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPK3(0), - .ngpio = S5PC100_GPIO_K3_NR, - .label = "GPK3", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPL0(0), - .ngpio = S5PC100_GPIO_L0_NR, - .label = "GPL0", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPL1(0), - .ngpio = S5PC100_GPIO_L1_NR, - .label = "GPL1", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPL2(0), - .ngpio = S5PC100_GPIO_L2_NR, - .label = "GPL2", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPL3(0), - .ngpio = S5PC100_GPIO_L3_NR, - .label = "GPL3", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPL4(0), - .ngpio = S5PC100_GPIO_L4_NR, - .label = "GPL4", - }, - }, { - .base = (S5P_VA_GPIO + 0xC00), - .config = &gpio_cfg_eint, - .irq_base = IRQ_EINT(0), - .chip = { - .base = S5PC100_GPH0(0), - .ngpio = S5PC100_GPIO_H0_NR, - .label = "GPH0", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC20), - .config = &gpio_cfg_eint, - .irq_base = IRQ_EINT(8), - .chip = { - .base = S5PC100_GPH1(0), - .ngpio = S5PC100_GPIO_H1_NR, - .label = "GPH1", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC40), - .config = &gpio_cfg_eint, - .irq_base = IRQ_EINT(16), - .chip = { - .base = S5PC100_GPH2(0), - .ngpio = S5PC100_GPIO_H2_NR, - .label = "GPH2", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC60), - .config = &gpio_cfg_eint, - .irq_base = IRQ_EINT(24), - .chip = { - .base = S5PC100_GPH3(0), - .ngpio = S5PC100_GPIO_H3_NR, - .label = "GPH3", - .to_irq = samsung_gpiolib_to_irq, - }, - }, -}; - -static __init int s5pc100_gpiolib_init(void) -{ - struct s3c_gpio_chip *chip = s5pc100_gpio_chips; - int nr_chips = ARRAY_SIZE(s5pc100_gpio_chips); - int gpioint_group = 0; - int i; - - for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) { - chip->config = &gpio_cfg; - chip->group = gpioint_group++; - } - if (chip->base == NULL) - chip->base = S5PC100_BANK_BASE(i); - } - - samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips); - s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); - - return 0; -} -core_initcall(s5pc100_gpiolib_init); diff --git a/drivers/gpio/gpio-s5pv210.c b/drivers/gpio/gpio-s5pv210.c deleted file mode 100644 index eb12f1602de9..000000000000 --- a/drivers/gpio/gpio-s5pv210.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * S5PV210 - GPIOlib support - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <plat/gpio-core.h> -#include <plat/gpio-cfg.h> -#include <plat/gpio-cfg-helpers.h> -#include <mach/map.h> - -static struct s3c_gpio_cfg gpio_cfg = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_cfg gpio_cfg_noint = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -/* GPIO bank's base address given the index of the bank in the - * list of all gpio banks. - */ -#define S5PV210_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)) - -/* - * Following are the gpio banks in v210. - * - * The 'config' member when left to NULL, is initialized to the default - * structure gpio_cfg in the init function below. - * - * The 'base' member is also initialized in the init function below. - * Note: The initialization of 'base' member of s3c_gpio_chip structure - * uses the above macro and depends on the banks being listed in order here. - */ -static struct s3c_gpio_chip s5pv210_gpio_4bit[] = { - { - .chip = { - .base = S5PV210_GPA0(0), - .ngpio = S5PV210_GPIO_A0_NR, - .label = "GPA0", - }, - }, { - .chip = { - .base = S5PV210_GPA1(0), - .ngpio = S5PV210_GPIO_A1_NR, - .label = "GPA1", - }, - }, { - .chip = { - .base = S5PV210_GPB(0), - .ngpio = S5PV210_GPIO_B_NR, - .label = "GPB", - }, - }, { - .chip = { - .base = S5PV210_GPC0(0), - .ngpio = S5PV210_GPIO_C0_NR, - .label = "GPC0", - }, - }, { - .chip = { - .base = S5PV210_GPC1(0), - .ngpio = S5PV210_GPIO_C1_NR, - .label = "GPC1", - }, - }, { - .chip = { - .base = S5PV210_GPD0(0), - .ngpio = S5PV210_GPIO_D0_NR, - .label = "GPD0", - }, - }, { - .chip = { - .base = S5PV210_GPD1(0), - .ngpio = S5PV210_GPIO_D1_NR, - .label = "GPD1", - }, - }, { - .chip = { - .base = S5PV210_GPE0(0), - .ngpio = S5PV210_GPIO_E0_NR, - .label = "GPE0", - }, - }, { - .chip = { - .base = S5PV210_GPE1(0), - .ngpio = S5PV210_GPIO_E1_NR, - .label = "GPE1", - }, - }, { - .chip = { - .base = S5PV210_GPF0(0), - .ngpio = S5PV210_GPIO_F0_NR, - .label = "GPF0", - }, - }, { - .chip = { - .base = S5PV210_GPF1(0), - .ngpio = S5PV210_GPIO_F1_NR, - .label = "GPF1", - }, - }, { - .chip = { - .base = S5PV210_GPF2(0), - .ngpio = S5PV210_GPIO_F2_NR, - .label = "GPF2", - }, - }, { - .chip = { - .base = S5PV210_GPF3(0), - .ngpio = S5PV210_GPIO_F3_NR, - .label = "GPF3", - }, - }, { - .chip = { - .base = S5PV210_GPG0(0), - .ngpio = S5PV210_GPIO_G0_NR, - .label = "GPG0", - }, - }, { - .chip = { - .base = S5PV210_GPG1(0), - .ngpio = S5PV210_GPIO_G1_NR, - .label = "GPG1", - }, - }, { - .chip = { - .base = S5PV210_GPG2(0), - .ngpio = S5PV210_GPIO_G2_NR, - .label = "GPG2", - }, - }, { - .chip = { - .base = S5PV210_GPG3(0), - .ngpio = S5PV210_GPIO_G3_NR, - .label = "GPG3", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_GPI(0), - .ngpio = S5PV210_GPIO_I_NR, - .label = "GPI", - }, - }, { - .chip = { - .base = S5PV210_GPJ0(0), - .ngpio = S5PV210_GPIO_J0_NR, - .label = "GPJ0", - }, - }, { - .chip = { - .base = S5PV210_GPJ1(0), - .ngpio = S5PV210_GPIO_J1_NR, - .label = "GPJ1", - }, - }, { - .chip = { - .base = S5PV210_GPJ2(0), - .ngpio = S5PV210_GPIO_J2_NR, - .label = "GPJ2", - }, - }, { - .chip = { - .base = S5PV210_GPJ3(0), - .ngpio = S5PV210_GPIO_J3_NR, - .label = "GPJ3", - }, - }, { - .chip = { - .base = S5PV210_GPJ4(0), - .ngpio = S5PV210_GPIO_J4_NR, - .label = "GPJ4", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_MP01(0), - .ngpio = S5PV210_GPIO_MP01_NR, - .label = "MP01", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_MP02(0), - .ngpio = S5PV210_GPIO_MP02_NR, - .label = "MP02", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_MP03(0), - .ngpio = S5PV210_GPIO_MP03_NR, - .label = "MP03", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_MP04(0), - .ngpio = S5PV210_GPIO_MP04_NR, - .label = "MP04", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_MP05(0), - .ngpio = S5PV210_GPIO_MP05_NR, - .label = "MP05", - }, - }, { - .base = (S5P_VA_GPIO + 0xC00), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(0), - .chip = { - .base = S5PV210_GPH0(0), - .ngpio = S5PV210_GPIO_H0_NR, - .label = "GPH0", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC20), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(8), - .chip = { - .base = S5PV210_GPH1(0), - .ngpio = S5PV210_GPIO_H1_NR, - .label = "GPH1", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC40), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(16), - .chip = { - .base = S5PV210_GPH2(0), - .ngpio = S5PV210_GPIO_H2_NR, - .label = "GPH2", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC60), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(24), - .chip = { - .base = S5PV210_GPH3(0), - .ngpio = S5PV210_GPIO_H3_NR, - .label = "GPH3", - .to_irq = samsung_gpiolib_to_irq, - }, - }, -}; - -static __init int s5pv210_gpiolib_init(void) -{ - struct s3c_gpio_chip *chip = s5pv210_gpio_4bit; - int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit); - int gpioint_group = 0; - int i = 0; - - for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) { - chip->config = &gpio_cfg; - chip->group = gpioint_group++; - } - if (chip->base == NULL) - chip->base = S5PV210_BANK_BASE(i); - } - - samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); - s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); - - return 0; -} -core_initcall(s5pv210_gpiolib_init); diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c new file mode 100644 index 000000000000..866251852719 --- /dev/null +++ b/drivers/gpio/gpio-samsung.c @@ -0,0 +1,2712 @@ +/* + * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * SAMSUNG - GPIOlib support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/sysdev.h> +#include <linux/ioport.h> + +#include <asm/irq.h> + +#include <mach/hardware.h> +#include <mach/map.h> +#include <mach/regs-clock.h> +#include <mach/regs-gpio.h> + +#include <plat/cpu.h> +#include <plat/gpio-core.h> +#include <plat/gpio-cfg.h> +#include <plat/gpio-cfg-helpers.h> +#include <plat/gpio-fns.h> +#include <plat/pm.h> + +#ifndef DEBUG_GPIO +#define gpio_dbg(x...) do { } while (0) +#else +#define gpio_dbg(x...) printk(KERN_DEBUG x) +#endif + +int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + void __iomem *reg = chip->base + 0x08; + int shift = off * 2; + u32 pup; + + pup = __raw_readl(reg); + pup &= ~(3 << shift); + pup |= pull << shift; + __raw_writel(pup, reg); + + return 0; +} + +samsung_gpio_pull_t samsung_gpio_getpull_updown(struct samsung_gpio_chip *chip, + unsigned int off) +{ + void __iomem *reg = chip->base + 0x08; + int shift = off * 2; + u32 pup = __raw_readl(reg); + + pup >>= shift; + pup &= 0x3; + + return (__force samsung_gpio_pull_t)pup; +} + +int s3c2443_gpio_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + switch (pull) { + case S3C_GPIO_PULL_NONE: + pull = 0x01; + break; + case S3C_GPIO_PULL_UP: + pull = 0x00; + break; + case S3C_GPIO_PULL_DOWN: + pull = 0x02; + break; + } + return samsung_gpio_setpull_updown(chip, off, pull); +} + +samsung_gpio_pull_t s3c2443_gpio_getpull(struct samsung_gpio_chip *chip, + unsigned int off) +{ + samsung_gpio_pull_t pull; + + pull = samsung_gpio_getpull_updown(chip, off); + + switch (pull) { + case 0x00: + pull = S3C_GPIO_PULL_UP; + break; + case 0x01: + case 0x03: + pull = S3C_GPIO_PULL_NONE; + break; + case 0x02: + pull = S3C_GPIO_PULL_DOWN; + break; + } + + return pull; +} + +static int s3c24xx_gpio_setpull_1(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull, + samsung_gpio_pull_t updown) +{ + void __iomem *reg = chip->base + 0x08; + u32 pup = __raw_readl(reg); + + if (pull == updown) + pup &= ~(1 << off); + else if (pull == S3C_GPIO_PULL_NONE) + pup |= (1 << off); + else + return -EINVAL; + + __raw_writel(pup, reg); + return 0; +} + +static samsung_gpio_pull_t s3c24xx_gpio_getpull_1(struct samsung_gpio_chip *chip, + unsigned int off, + samsung_gpio_pull_t updown) +{ + void __iomem *reg = chip->base + 0x08; + u32 pup = __raw_readl(reg); + + pup &= (1 << off); + return pup ? S3C_GPIO_PULL_NONE : updown; +} + +samsung_gpio_pull_t s3c24xx_gpio_getpull_1up(struct samsung_gpio_chip *chip, + unsigned int off) +{ + return s3c24xx_gpio_getpull_1(chip, off, S3C_GPIO_PULL_UP); +} + +int s3c24xx_gpio_setpull_1up(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_UP); +} + +samsung_gpio_pull_t s3c24xx_gpio_getpull_1down(struct samsung_gpio_chip *chip, + unsigned int off) +{ + return s3c24xx_gpio_getpull_1(chip, off, S3C_GPIO_PULL_DOWN); +} + +int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN); +} + +static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + if (pull == S3C_GPIO_PULL_UP) + pull = 3; + + return samsung_gpio_setpull_updown(chip, off, pull); +} + +static samsung_gpio_pull_t exynos4_gpio_getpull(struct samsung_gpio_chip *chip, + unsigned int off) +{ + samsung_gpio_pull_t pull; + + pull = samsung_gpio_getpull_updown(chip, off); + + if (pull == 3) + pull = S3C_GPIO_PULL_UP; + + return pull; +} + +/* + * samsung_gpio_setcfg_2bit - Samsung 2bit style GPIO configuration. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @cfg: The configuration value to set. + * + * This helper deal with the GPIO cases where the control register + * has two bits of configuration per gpio, which have the following + * functions: + * 00 = input + * 01 = output + * 1x = special function + */ + +static int samsung_gpio_setcfg_2bit(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift = off * 2; + u32 con; + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + if (cfg > 3) + return -EINVAL; + + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0x3 << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} + +/* + * samsung_gpio_getcfg_2bit - Samsung 2bit style GPIO configuration read. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * + * The reverse of samsung_gpio_setcfg_2bit(). Will return a value whicg + * could be directly passed back to samsung_gpio_setcfg_2bit(), from the + * S3C_GPIO_SPECIAL() macro. + */ + +static unsigned int samsung_gpio_getcfg_2bit(struct samsung_gpio_chip *chip, + unsigned int off) +{ + u32 con; + + con = __raw_readl(chip->base); + con >>= off * 2; + con &= 3; + + /* this conversion works for IN and OUT as well as special mode */ + return S3C_GPIO_SPECIAL(con); +} + +/* + * samsung_gpio_setcfg_4bit - Samsung 4bit single register GPIO config. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @cfg: The configuration value to set. + * + * This helper deal with the GPIO cases where the control register has 4 bits + * of control per GPIO, generally in the form of: + * 0000 = Input + * 0001 = Output + * others = Special functions (dependent on bank) + * + * Note, since the code to deal with the case where there are two control + * registers instead of one, we do not have a separate set of functions for + * each case. + */ + +static int samsung_gpio_setcfg_4bit(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift = (off & 7) * 4; + u32 con; + + if (off < 8 && chip->chip.ngpio > 8) + reg -= 4; + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0xf << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} + +/* + * samsung_gpio_getcfg_4bit - Samsung 4bit single register GPIO config read. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * + * The reverse of samsung_gpio_setcfg_4bit(), turning a gpio configuration + * register setting into a value the software can use, such as could be passed + * to samsung_gpio_setcfg_4bit(). + * + * @sa samsung_gpio_getcfg_2bit + */ + +static unsigned samsung_gpio_getcfg_4bit(struct samsung_gpio_chip *chip, + unsigned int off) +{ + void __iomem *reg = chip->base; + unsigned int shift = (off & 7) * 4; + u32 con; + + if (off < 8 && chip->chip.ngpio > 8) + reg -= 4; + + con = __raw_readl(reg); + con >>= shift; + con &= 0xf; + + /* this conversion works for IN and OUT as well as special mode */ + return S3C_GPIO_SPECIAL(con); +} + +#ifdef CONFIG_PLAT_S3C24XX +/* + * s3c24xx_gpio_setcfg_abank - S3C24XX style GPIO configuration (Bank A) + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @cfg: The configuration value to set. + * + * This helper deal with the GPIO cases where the control register + * has one bit of configuration for the gpio, where setting the bit + * means the pin is in special function mode and unset means output. + */ + +static int s3c24xx_gpio_setcfg_abank(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift = off; + u32 con; + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + + /* Map output to 0, and SFN2 to 1 */ + cfg -= 1; + if (cfg > 1) + return -EINVAL; + + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0x1 << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} + +/* + * s3c24xx_gpio_getcfg_abank - S3C24XX style GPIO configuration read (Bank A) + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * + * The reverse of s3c24xx_gpio_setcfg_abank() turning an GPIO into a usable + * GPIO configuration value. + * + * @sa samsung_gpio_getcfg_2bit + * @sa samsung_gpio_getcfg_4bit + */ + +static unsigned s3c24xx_gpio_getcfg_abank(struct samsung_gpio_chip *chip, + unsigned int off) +{ + u32 con; + + con = __raw_readl(chip->base); + con >>= off; + con &= 1; + con++; + + return S3C_GPIO_SFN(con); +} +#endif + +#if defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450) +static int s5p64x0_gpio_setcfg_rbank(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift; + u32 con; + + switch (off) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + shift = (off & 7) * 4; + reg -= 4; + break; + case 6: + shift = ((off + 1) & 7) * 4; + reg -= 4; + default: + shift = ((off + 1) & 7) * 4; + break; + } + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0xf << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} +#endif + +static void __init samsung_gpiolib_set_cfg(struct samsung_gpio_cfg *chipcfg, + int nr_chips) +{ + for (; nr_chips > 0; nr_chips--, chipcfg++) { + if (!chipcfg->set_config) + chipcfg->set_config = samsung_gpio_setcfg_4bit; + if (!chipcfg->get_config) + chipcfg->get_config = samsung_gpio_getcfg_4bit; + if (!chipcfg->set_pull) + chipcfg->set_pull = samsung_gpio_setpull_updown; + if (!chipcfg->get_pull) + chipcfg->get_pull = samsung_gpio_getpull_updown; + } +} + +struct samsung_gpio_cfg s3c24xx_gpiocfg_default = { + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, +}; + +#ifdef CONFIG_PLAT_S3C24XX +static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = { + .set_config = s3c24xx_gpio_setcfg_abank, + .get_config = s3c24xx_gpio_getcfg_abank, +}; +#endif + +static struct samsung_gpio_cfg exynos4_gpio_cfg = { + .set_pull = exynos4_gpio_setpull, + .get_pull = exynos4_gpio_getpull, + .set_config = samsung_gpio_setcfg_4bit, + .get_config = samsung_gpio_getcfg_4bit, +}; + +#if defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450) +static struct samsung_gpio_cfg s5p64x0_gpio_cfg_rbank = { + .cfg_eint = 0x3, + .set_config = s5p64x0_gpio_setcfg_rbank, + .get_config = samsung_gpio_getcfg_4bit, + .set_pull = samsung_gpio_setpull_updown, + .get_pull = samsung_gpio_getpull_updown, +}; +#endif + +static struct samsung_gpio_cfg samsung_gpio_cfgs[] = { + { + .cfg_eint = 0x0, + }, { + .cfg_eint = 0x3, + }, { + .cfg_eint = 0x7, + }, { + .cfg_eint = 0xF, + }, { + .cfg_eint = 0x0, + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, { + .cfg_eint = 0x2, + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, { + .cfg_eint = 0x3, + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, { + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, { + .set_pull = exynos4_gpio_setpull, + .get_pull = exynos4_gpio_getpull, + }, { + .cfg_eint = 0x3, + .set_pull = exynos4_gpio_setpull, + .get_pull = exynos4_gpio_getpull, + } +}; + +/* + * Default routines for controlling GPIO, based on the original S3C24XX + * GPIO functions which deal with the case where each gpio bank of the + * chip is as following: + * + * base + 0x00: Control register, 2 bits per gpio + * gpio n: 2 bits starting at (2*n) + * 00 = input, 01 = output, others mean special-function + * base + 0x04: Data register, 1 bit per gpio + * bit n: data bit n +*/ + +static int samsung_gpiolib_2bit_input(struct gpio_chip *chip, unsigned offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long con; + + samsung_gpio_lock(ourchip, flags); + + con = __raw_readl(base + 0x00); + con &= ~(3 << (offset * 2)); + + __raw_writel(con, base + 0x00); + + samsung_gpio_unlock(ourchip, flags); + return 0; +} + +static int samsung_gpiolib_2bit_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long dat; + unsigned long con; + + samsung_gpio_lock(ourchip, flags); + + dat = __raw_readl(base + 0x04); + dat &= ~(1 << offset); + if (value) + dat |= 1 << offset; + __raw_writel(dat, base + 0x04); + + con = __raw_readl(base + 0x00); + con &= ~(3 << (offset * 2)); + con |= 1 << (offset * 2); + + __raw_writel(con, base + 0x00); + __raw_writel(dat, base + 0x04); + + samsung_gpio_unlock(ourchip, flags); + return 0; +} + +/* + * The samsung_gpiolib_4bit routines are to control the gpio banks where + * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the + * following example: + * + * base + 0x00: Control register, 4 bits per gpio + * gpio n: 4 bits starting at (4*n) + * 0000 = input, 0001 = output, others mean special-function + * base + 0x04: Data register, 1 bit per gpio + * bit n: data bit n + * + * Note, since the data register is one bit per gpio and is at base + 0x4 + * we can use samsung_gpiolib_get and samsung_gpiolib_set to change the + * state of the output. + */ + +static int samsung_gpiolib_4bit_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long con; + + con = __raw_readl(base + GPIOCON_OFF); + con &= ~(0xf << con_4bit_shift(offset)); + __raw_writel(con, base + GPIOCON_OFF); + + gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con); + + return 0; +} + +static int samsung_gpiolib_4bit_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long con; + unsigned long dat; + + con = __raw_readl(base + GPIOCON_OFF); + con &= ~(0xf << con_4bit_shift(offset)); + con |= 0x1 << con_4bit_shift(offset); + + dat = __raw_readl(base + GPIODAT_OFF); + + if (value) + dat |= 1 << offset; + else + dat &= ~(1 << offset); + + __raw_writel(dat, base + GPIODAT_OFF); + __raw_writel(con, base + GPIOCON_OFF); + __raw_writel(dat, base + GPIODAT_OFF); + + gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); + + return 0; +} + +/* + * The next set of routines are for the case where the GPIO configuration + * registers are 4 bits per GPIO but there is more than one register (the + * bank has more than 8 GPIOs. + * + * This case is the similar to the 4 bit case, but the registers are as + * follows: + * + * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs) + * gpio n: 4 bits starting at (4*n) + * 0000 = input, 0001 = output, others mean special-function + * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs) + * gpio n: 4 bits starting at (4*n) + * 0000 = input, 0001 = output, others mean special-function + * base + 0x08: Data register, 1 bit per gpio + * bit n: data bit n + * + * To allow us to use the samsung_gpiolib_get and samsung_gpiolib_set + * routines we store the 'base + 0x4' address so that these routines see + * the data register at ourchip->base + 0x04. + */ + +static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + void __iomem *regcon = base; + unsigned long con; + + if (offset > 7) + offset -= 8; + else + regcon -= 4; + + con = __raw_readl(regcon); + con &= ~(0xf << con_4bit_shift(offset)); + __raw_writel(con, regcon); + + gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con); + + return 0; +} + +static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + void __iomem *regcon = base; + unsigned long con; + unsigned long dat; + unsigned con_offset = offset; + + if (con_offset > 7) + con_offset -= 8; + else + regcon -= 4; + + con = __raw_readl(regcon); + con &= ~(0xf << con_4bit_shift(con_offset)); + con |= 0x1 << con_4bit_shift(con_offset); + + dat = __raw_readl(base + GPIODAT_OFF); + + if (value) + dat |= 1 << offset; + else + dat &= ~(1 << offset); + + __raw_writel(dat, base + GPIODAT_OFF); + __raw_writel(con, regcon); + __raw_writel(dat, base + GPIODAT_OFF); + + gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); + + return 0; +} + +#ifdef CONFIG_PLAT_S3C24XX +/* The next set of routines are for the case of s3c24xx bank a */ + +static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset) +{ + return -EINVAL; +} + +static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long dat; + unsigned long con; + + local_irq_save(flags); + + con = __raw_readl(base + 0x00); + dat = __raw_readl(base + 0x04); + + dat &= ~(1 << offset); + if (value) + dat |= 1 << offset; + + __raw_writel(dat, base + 0x04); + + con &= ~(1 << offset); + + __raw_writel(con, base + 0x00); + __raw_writel(dat, base + 0x04); + + local_irq_restore(flags); + return 0; +} +#endif + +/* The next set of routines are for the case of s5p64x0 bank r */ + +static int s5p64x0_gpiolib_rbank_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + void __iomem *regcon = base; + unsigned long con; + unsigned long flags; + + switch (offset) { + case 6: + offset += 1; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + regcon -= 4; + break; + default: + offset -= 7; + break; + } + + samsung_gpio_lock(ourchip, flags); + + con = __raw_readl(regcon); + con &= ~(0xf << con_4bit_shift(offset)); + __raw_writel(con, regcon); + + samsung_gpio_unlock(ourchip, flags); + + return 0; +} + +static int s5p64x0_gpiolib_rbank_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + void __iomem *regcon = base; + unsigned long con; + unsigned long dat; + unsigned long flags; + unsigned con_offset = offset; + + switch (con_offset) { + case 6: + con_offset += 1; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + regcon -= 4; + break; + default: + con_offset -= 7; + break; + } + + samsung_gpio_lock(ourchip, flags); + + con = __raw_readl(regcon); + con &= ~(0xf << con_4bit_shift(con_offset)); + con |= 0x1 << con_4bit_shift(con_offset); + + dat = __raw_readl(base + GPIODAT_OFF); + if (value) + dat |= 1 << offset; + else + dat &= ~(1 << offset); + + __raw_writel(con, regcon); + __raw_writel(dat, base + GPIODAT_OFF); + + samsung_gpio_unlock(ourchip, flags); + + return 0; +} + +static void samsung_gpiolib_set(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long dat; + + samsung_gpio_lock(ourchip, flags); + + dat = __raw_readl(base + 0x04); + dat &= ~(1 << offset); + if (value) + dat |= 1 << offset; + __raw_writel(dat, base + 0x04); + + samsung_gpio_unlock(ourchip, flags); +} + +static int samsung_gpiolib_get(struct gpio_chip *chip, unsigned offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + unsigned long val; + + val = __raw_readl(ourchip->base + 0x04); + val >>= offset; + val &= 1; + + return val; +} + +/* + * CONFIG_S3C_GPIO_TRACK enables the tracking of the s3c specific gpios + * for use with the configuration calls, and other parts of the s3c gpiolib + * support code. + * + * Not all s3c support code will need this, as some configurations of cpu + * may only support one or two different configuration options and have an + * easy gpio to samsung_gpio_chip mapping function. If this is the case, then + * the machine support file should provide its own samsung_gpiolib_getchip() + * and any other necessary functions. + */ + +#ifdef CONFIG_S3C_GPIO_TRACK +struct samsung_gpio_chip *s3c_gpios[S3C_GPIO_END]; + +static __init void s3c_gpiolib_track(struct samsung_gpio_chip *chip) +{ + unsigned int gpn; + int i; + + gpn = chip->chip.base; + for (i = 0; i < chip->chip.ngpio; i++, gpn++) { + BUG_ON(gpn >= ARRAY_SIZE(s3c_gpios)); + s3c_gpios[gpn] = chip; + } +} +#endif /* CONFIG_S3C_GPIO_TRACK */ + +/* + * samsung_gpiolib_add() - add the Samsung gpio_chip. + * @chip: The chip to register + * + * This is a wrapper to gpiochip_add() that takes our specific gpio chip + * information and makes the necessary alterations for the platform and + * notes the information for use with the configuration systems and any + * other parts of the system. + */ + +static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) +{ + struct gpio_chip *gc = &chip->chip; + int ret; + + BUG_ON(!chip->base); + BUG_ON(!gc->label); + BUG_ON(!gc->ngpio); + + spin_lock_init(&chip->lock); + + if (!gc->direction_input) + gc->direction_input = samsung_gpiolib_2bit_input; + if (!gc->direction_output) + gc->direction_output = samsung_gpiolib_2bit_output; + if (!gc->set) + gc->set = samsung_gpiolib_set; + if (!gc->get) + gc->get = samsung_gpiolib_get; + +#ifdef CONFIG_PM + if (chip->pm != NULL) { + if (!chip->pm->save || !chip->pm->resume) + printk(KERN_ERR "gpio: %s has missing PM functions\n", + gc->label); + } else + printk(KERN_ERR "gpio: %s has no PM function\n", gc->label); +#endif + + /* gpiochip_add() prints own failure message on error. */ + ret = gpiochip_add(gc); + if (ret >= 0) + s3c_gpiolib_track(chip); +} + +static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, + int nr_chips, void __iomem *base) +{ + int i; + struct gpio_chip *gc = &chip->chip; + + for (i = 0 ; i < nr_chips; i++, chip++) { + /* skip banks not present on SoC */ + if (chip->chip.base >= S3C_GPIO_END) + continue; + + if (!chip->config) + chip->config = &s3c24xx_gpiocfg_default; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_2bit); + if ((base != NULL) && (chip->base == NULL)) + chip->base = base + ((i) * 0x10); + + if (!gc->direction_input) + gc->direction_input = samsung_gpiolib_2bit_input; + if (!gc->direction_output) + gc->direction_output = samsung_gpiolib_2bit_output; + + samsung_gpiolib_add(chip); + } +} + +static void __init samsung_gpiolib_add_2bit_chips(struct samsung_gpio_chip *chip, + int nr_chips, void __iomem *base, + unsigned int offset) +{ + int i; + + for (i = 0 ; i < nr_chips; i++, chip++) { + chip->chip.direction_input = samsung_gpiolib_2bit_input; + chip->chip.direction_output = samsung_gpiolib_2bit_output; + + if (!chip->config) + chip->config = &samsung_gpio_cfgs[7]; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_2bit); + if ((base != NULL) && (chip->base == NULL)) + chip->base = base + ((i) * offset); + + samsung_gpiolib_add(chip); + } +} + +/* + * samsung_gpiolib_add_4bit_chips - 4bit single register GPIO config. + * @chip: The gpio chip that is being configured. + * @nr_chips: The no of chips (gpio ports) for the GPIO being configured. + * + * This helper deal with the GPIO cases where the control register has 4 bits + * of control per GPIO, generally in the form of: + * 0000 = Input + * 0001 = Output + * others = Special functions (dependent on bank) + * + * Note, since the code to deal with the case where there are two control + * registers instead of one, we do not have a separate set of function + * (samsung_gpiolib_add_4bit2_chips)for each case. + */ + +static void __init samsung_gpiolib_add_4bit_chips(struct samsung_gpio_chip *chip, + int nr_chips, void __iomem *base) +{ + int i; + + for (i = 0 ; i < nr_chips; i++, chip++) { + chip->chip.direction_input = samsung_gpiolib_4bit_input; + chip->chip.direction_output = samsung_gpiolib_4bit_output; + + if (!chip->config) + chip->config = &samsung_gpio_cfgs[2]; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); + if ((base != NULL) && (chip->base == NULL)) + chip->base = base + ((i) * 0x20); + + samsung_gpiolib_add(chip); + } +} + +static void __init samsung_gpiolib_add_4bit2_chips(struct samsung_gpio_chip *chip, + int nr_chips) +{ + for (; nr_chips > 0; nr_chips--, chip++) { + chip->chip.direction_input = samsung_gpiolib_4bit2_input; + chip->chip.direction_output = samsung_gpiolib_4bit2_output; + + if (!chip->config) + chip->config = &samsung_gpio_cfgs[2]; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); + + samsung_gpiolib_add(chip); + } +} + +static void __init s5p64x0_gpiolib_add_rbank(struct samsung_gpio_chip *chip, + int nr_chips) +{ + for (; nr_chips > 0; nr_chips--, chip++) { + chip->chip.direction_input = s5p64x0_gpiolib_rbank_input; + chip->chip.direction_output = s5p64x0_gpiolib_rbank_output; + + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); + + samsung_gpiolib_add(chip); + } +} + +int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct samsung_gpio_chip *samsung_chip = container_of(chip, struct samsung_gpio_chip, chip); + + return samsung_chip->irq_base + offset; +} + +#ifdef CONFIG_PLAT_S3C24XX +static int s3c24xx_gpiolib_fbank_to_irq(struct gpio_chip *chip, unsigned offset) +{ + if (offset < 4) + return IRQ_EINT0 + offset; + + if (offset < 8) + return IRQ_EINT4 + offset - 4; + + return -EINVAL; +} +#endif + +#ifdef CONFIG_PLAT_S3C64XX +static int s3c64xx_gpiolib_mbank_to_irq(struct gpio_chip *chip, unsigned pin) +{ + return pin < 5 ? IRQ_EINT(23) + pin : -ENXIO; +} + +static int s3c64xx_gpiolib_lbank_to_irq(struct gpio_chip *chip, unsigned pin) +{ + return pin >= 8 ? IRQ_EINT(16) + pin - 8 : -ENXIO; +} +#endif + +struct samsung_gpio_chip s3c24xx_gpios[] = { +#ifdef CONFIG_PLAT_S3C24XX + { + .config = &s3c24xx_gpiocfg_banka, + .chip = { + .base = S3C2410_GPA(0), + .owner = THIS_MODULE, + .label = "GPIOA", + .ngpio = 24, + .direction_input = s3c24xx_gpiolib_banka_input, + .direction_output = s3c24xx_gpiolib_banka_output, + }, + }, { + .chip = { + .base = S3C2410_GPB(0), + .owner = THIS_MODULE, + .label = "GPIOB", + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPC(0), + .owner = THIS_MODULE, + .label = "GPIOC", + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPD(0), + .owner = THIS_MODULE, + .label = "GPIOD", + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPE(0), + .label = "GPIOE", + .owner = THIS_MODULE, + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPF(0), + .owner = THIS_MODULE, + .label = "GPIOF", + .ngpio = 8, + .to_irq = s3c24xx_gpiolib_fbank_to_irq, + }, + }, { + .irq_base = IRQ_EINT8, + .chip = { + .base = S3C2410_GPG(0), + .owner = THIS_MODULE, + .label = "GPIOG", + .ngpio = 16, + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .chip = { + .base = S3C2410_GPH(0), + .owner = THIS_MODULE, + .label = "GPIOH", + .ngpio = 11, + }, + }, + /* GPIOS for the S3C2443 and later devices. */ + { + .base = S3C2440_GPJCON, + .chip = { + .base = S3C2410_GPJ(0), + .owner = THIS_MODULE, + .label = "GPIOJ", + .ngpio = 16, + }, + }, { + .base = S3C2443_GPKCON, + .chip = { + .base = S3C2410_GPK(0), + .owner = THIS_MODULE, + .label = "GPIOK", + .ngpio = 16, + }, + }, { + .base = S3C2443_GPLCON, + .chip = { + .base = S3C2410_GPL(0), + .owner = THIS_MODULE, + .label = "GPIOL", + .ngpio = 15, + }, + }, { + .base = S3C2443_GPMCON, + .chip = { + .base = S3C2410_GPM(0), + .owner = THIS_MODULE, + .label = "GPIOM", + .ngpio = 2, + }, + }, +#endif +}; + +/* + * GPIO bank summary: + * + * Bank GPIOs Style SlpCon ExtInt Group + * A 8 4Bit Yes 1 + * B 7 4Bit Yes 1 + * C 8 4Bit Yes 2 + * D 5 4Bit Yes 3 + * E 5 4Bit Yes None + * F 16 2Bit Yes 4 [1] + * G 7 4Bit Yes 5 + * H 10 4Bit[2] Yes 6 + * I 16 2Bit Yes None + * J 12 2Bit Yes None + * K 16 4Bit[2] No None + * L 15 4Bit[2] No None + * M 6 4Bit No IRQ_EINT + * N 16 2Bit No IRQ_EINT + * O 16 2Bit Yes 7 + * P 15 2Bit Yes 8 + * Q 9 2Bit Yes 9 + * + * [1] BANKF pins 14,15 do not form part of the external interrupt sources + * [2] BANK has two control registers, GPxCON0 and GPxCON1 + */ + +static struct samsung_gpio_chip s3c64xx_gpios_4bit[] = { +#ifdef CONFIG_PLAT_S3C64XX + { + .chip = { + .base = S3C64XX_GPA(0), + .ngpio = S3C64XX_GPIO_A_NR, + .label = "GPA", + }, + }, { + .chip = { + .base = S3C64XX_GPB(0), + .ngpio = S3C64XX_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S3C64XX_GPC(0), + .ngpio = S3C64XX_GPIO_C_NR, + .label = "GPC", + }, + }, { + .chip = { + .base = S3C64XX_GPD(0), + .ngpio = S3C64XX_GPIO_D_NR, + .label = "GPD", + }, + }, { + .config = &samsung_gpio_cfgs[0], + .chip = { + .base = S3C64XX_GPE(0), + .ngpio = S3C64XX_GPIO_E_NR, + .label = "GPE", + }, + }, { + .base = S3C64XX_GPG_BASE, + .chip = { + .base = S3C64XX_GPG(0), + .ngpio = S3C64XX_GPIO_G_NR, + .label = "GPG", + }, + }, { + .base = S3C64XX_GPM_BASE, + .config = &samsung_gpio_cfgs[1], + .chip = { + .base = S3C64XX_GPM(0), + .ngpio = S3C64XX_GPIO_M_NR, + .label = "GPM", + .to_irq = s3c64xx_gpiolib_mbank_to_irq, + }, + }, +#endif +}; + +static struct samsung_gpio_chip s3c64xx_gpios_4bit2[] = { +#ifdef CONFIG_PLAT_S3C64XX + { + .base = S3C64XX_GPH_BASE + 0x4, + .chip = { + .base = S3C64XX_GPH(0), + .ngpio = S3C64XX_GPIO_H_NR, + .label = "GPH", + }, + }, { + .base = S3C64XX_GPK_BASE + 0x4, + .config = &samsung_gpio_cfgs[0], + .chip = { + .base = S3C64XX_GPK(0), + .ngpio = S3C64XX_GPIO_K_NR, + .label = "GPK", + }, + }, { + .base = S3C64XX_GPL_BASE + 0x4, + .config = &samsung_gpio_cfgs[1], + .chip = { + .base = S3C64XX_GPL(0), + .ngpio = S3C64XX_GPIO_L_NR, + .label = "GPL", + .to_irq = s3c64xx_gpiolib_lbank_to_irq, + }, + }, +#endif +}; + +static struct samsung_gpio_chip s3c64xx_gpios_2bit[] = { +#ifdef CONFIG_PLAT_S3C64XX + { + .base = S3C64XX_GPF_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPF(0), + .ngpio = S3C64XX_GPIO_F_NR, + .label = "GPF", + }, + }, { + .config = &samsung_gpio_cfgs[7], + .chip = { + .base = S3C64XX_GPI(0), + .ngpio = S3C64XX_GPIO_I_NR, + .label = "GPI", + }, + }, { + .config = &samsung_gpio_cfgs[7], + .chip = { + .base = S3C64XX_GPJ(0), + .ngpio = S3C64XX_GPIO_J_NR, + .label = "GPJ", + }, + }, { + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPO(0), + .ngpio = S3C64XX_GPIO_O_NR, + .label = "GPO", + }, + }, { + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPP(0), + .ngpio = S3C64XX_GPIO_P_NR, + .label = "GPP", + }, + }, { + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPQ(0), + .ngpio = S3C64XX_GPIO_Q_NR, + .label = "GPQ", + }, + }, { + .base = S3C64XX_GPN_BASE, + .irq_base = IRQ_EINT(0), + .config = &samsung_gpio_cfgs[5], + .chip = { + .base = S3C64XX_GPN(0), + .ngpio = S3C64XX_GPIO_N_NR, + .label = "GPN", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +/* + * S5P6440 GPIO bank summary: + * + * Bank GPIOs Style SlpCon ExtInt Group + * A 6 4Bit Yes 1 + * B 7 4Bit Yes 1 + * C 8 4Bit Yes 2 + * F 2 2Bit Yes 4 [1] + * G 7 4Bit Yes 5 + * H 10 4Bit[2] Yes 6 + * I 16 2Bit Yes None + * J 12 2Bit Yes None + * N 16 2Bit No IRQ_EINT + * P 8 2Bit Yes 8 + * R 15 4Bit[2] Yes 8 + */ + +static struct samsung_gpio_chip s5p6440_gpios_4bit[] = { +#ifdef CONFIG_CPU_S5P6440 + { + .chip = { + .base = S5P6440_GPA(0), + .ngpio = S5P6440_GPIO_A_NR, + .label = "GPA", + }, + }, { + .chip = { + .base = S5P6440_GPB(0), + .ngpio = S5P6440_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S5P6440_GPC(0), + .ngpio = S5P6440_GPIO_C_NR, + .label = "GPC", + }, + }, { + .base = S5P64X0_GPG_BASE, + .chip = { + .base = S5P6440_GPG(0), + .ngpio = S5P6440_GPIO_G_NR, + .label = "GPG", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6440_gpios_4bit2[] = { +#ifdef CONFIG_CPU_S5P6440 + { + .base = S5P64X0_GPH_BASE + 0x4, + .chip = { + .base = S5P6440_GPH(0), + .ngpio = S5P6440_GPIO_H_NR, + .label = "GPH", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6440_gpios_rbank[] = { +#ifdef CONFIG_CPU_S5P6440 + { + .base = S5P64X0_GPR_BASE + 0x4, + .config = &s5p64x0_gpio_cfg_rbank, + .chip = { + .base = S5P6440_GPR(0), + .ngpio = S5P6440_GPIO_R_NR, + .label = "GPR", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6440_gpios_2bit[] = { +#ifdef CONFIG_CPU_S5P6440 + { + .base = S5P64X0_GPF_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S5P6440_GPF(0), + .ngpio = S5P6440_GPIO_F_NR, + .label = "GPF", + }, + }, { + .base = S5P64X0_GPI_BASE, + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = S5P6440_GPI(0), + .ngpio = S5P6440_GPIO_I_NR, + .label = "GPI", + }, + }, { + .base = S5P64X0_GPJ_BASE, + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = S5P6440_GPJ(0), + .ngpio = S5P6440_GPIO_J_NR, + .label = "GPJ", + }, + }, { + .base = S5P64X0_GPN_BASE, + .config = &samsung_gpio_cfgs[5], + .chip = { + .base = S5P6440_GPN(0), + .ngpio = S5P6440_GPIO_N_NR, + .label = "GPN", + }, + }, { + .base = S5P64X0_GPP_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S5P6440_GPP(0), + .ngpio = S5P6440_GPIO_P_NR, + .label = "GPP", + }, + }, +#endif +}; + +/* + * S5P6450 GPIO bank summary: + * + * Bank GPIOs Style SlpCon ExtInt Group + * A 6 4Bit Yes 1 + * B 7 4Bit Yes 1 + * C 8 4Bit Yes 2 + * D 8 4Bit Yes None + * F 2 2Bit Yes None + * G 14 4Bit[2] Yes 5 + * H 10 4Bit[2] Yes 6 + * I 16 2Bit Yes None + * J 12 2Bit Yes None + * K 5 4Bit Yes None + * N 16 2Bit No IRQ_EINT + * P 11 2Bit Yes 8 + * Q 14 2Bit Yes None + * R 15 4Bit[2] Yes None + * S 8 2Bit Yes None + * + * [1] BANKF pins 14,15 do not form part of the external interrupt sources + * [2] BANK has two control registers, GPxCON0 and GPxCON1 + */ + +static struct samsung_gpio_chip s5p6450_gpios_4bit[] = { +#ifdef CONFIG_CPU_S5P6450 + { + .chip = { + .base = S5P6450_GPA(0), + .ngpio = S5P6450_GPIO_A_NR, + .label = "GPA", + }, + }, { + .chip = { + .base = S5P6450_GPB(0), + .ngpio = S5P6450_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S5P6450_GPC(0), + .ngpio = S5P6450_GPIO_C_NR, + .label = "GPC", + }, + }, { + .chip = { + .base = S5P6450_GPD(0), + .ngpio = S5P6450_GPIO_D_NR, + .label = "GPD", + }, + }, { + .base = S5P6450_GPK_BASE, + .chip = { + .base = S5P6450_GPK(0), + .ngpio = S5P6450_GPIO_K_NR, + .label = "GPK", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6450_gpios_4bit2[] = { +#ifdef CONFIG_CPU_S5P6450 + { + .base = S5P64X0_GPG_BASE + 0x4, + .chip = { + .base = S5P6450_GPG(0), + .ngpio = S5P6450_GPIO_G_NR, + .label = "GPG", + }, + }, { + .base = S5P64X0_GPH_BASE + 0x4, + .chip = { + .base = S5P6450_GPH(0), + .ngpio = S5P6450_GPIO_H_NR, + .label = "GPH", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6450_gpios_rbank[] = { +#ifdef CONFIG_CPU_S5P6450 + { + .base = S5P64X0_GPR_BASE + 0x4, + .config = &s5p64x0_gpio_cfg_rbank, + .chip = { + .base = S5P6450_GPR(0), + .ngpio = S5P6450_GPIO_R_NR, + .label = "GPR", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6450_gpios_2bit[] = { +#ifdef CONFIG_CPU_S5P6450 + { + .base = S5P64X0_GPF_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S5P6450_GPF(0), + .ngpio = S5P6450_GPIO_F_NR, + .label = "GPF", + }, + }, { + .base = S5P64X0_GPI_BASE, + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = S5P6450_GPI(0), + .ngpio = S5P6450_GPIO_I_NR, + .label = "GPI", + }, + }, { + .base = S5P64X0_GPJ_BASE, + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = S5P6450_GPJ(0), + .ngpio = S5P6450_GPIO_J_NR, + .label = "GPJ", + }, + }, { + .base = S5P64X0_GPN_BASE, + .config = &samsung_gpio_cfgs[5], + .chip = { + .base = S5P6450_GPN(0), + .ngpio = S5P6450_GPIO_N_NR, + .label = "GPN", + }, + }, { + .base = S5P64X0_GPP_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S5P6450_GPP(0), + .ngpio = S5P6450_GPIO_P_NR, + .label = "GPP", + }, + }, { + .base = S5P6450_GPQ_BASE, + .config = &samsung_gpio_cfgs[5], + .chip = { + .base = S5P6450_GPQ(0), + .ngpio = S5P6450_GPIO_Q_NR, + .label = "GPQ", + }, + }, { + .base = S5P6450_GPS_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S5P6450_GPS(0), + .ngpio = S5P6450_GPIO_S_NR, + .label = "GPS", + }, + }, +#endif +}; + +/* + * S5PC100 GPIO bank summary: + * + * Bank GPIOs Style INT Type + * A0 8 4Bit GPIO_INT0 + * A1 5 4Bit GPIO_INT1 + * B 8 4Bit GPIO_INT2 + * C 5 4Bit GPIO_INT3 + * D 7 4Bit GPIO_INT4 + * E0 8 4Bit GPIO_INT5 + * E1 6 4Bit GPIO_INT6 + * F0 8 4Bit GPIO_INT7 + * F1 8 4Bit GPIO_INT8 + * F2 8 4Bit GPIO_INT9 + * F3 4 4Bit GPIO_INT10 + * G0 8 4Bit GPIO_INT11 + * G1 3 4Bit GPIO_INT12 + * G2 7 4Bit GPIO_INT13 + * G3 7 4Bit GPIO_INT14 + * H0 8 4Bit WKUP_INT + * H1 8 4Bit WKUP_INT + * H2 8 4Bit WKUP_INT + * H3 8 4Bit WKUP_INT + * I 8 4Bit GPIO_INT15 + * J0 8 4Bit GPIO_INT16 + * J1 5 4Bit GPIO_INT17 + * J2 8 4Bit GPIO_INT18 + * J3 8 4Bit GPIO_INT19 + * J4 4 4Bit GPIO_INT20 + * K0 8 4Bit None + * K1 6 4Bit None + * K2 8 4Bit None + * K3 8 4Bit None + * L0 8 4Bit None + * L1 8 4Bit None + * L2 8 4Bit None + * L3 8 4Bit None + */ + +static struct samsung_gpio_chip s5pc100_gpios_4bit[] = { +#ifdef CONFIG_CPU_S5PC100 + { + .chip = { + .base = S5PC100_GPA0(0), + .ngpio = S5PC100_GPIO_A0_NR, + .label = "GPA0", + }, + }, { + .chip = { + .base = S5PC100_GPA1(0), + .ngpio = S5PC100_GPIO_A1_NR, + .label = "GPA1", + }, + }, { + .chip = { + .base = S5PC100_GPB(0), + .ngpio = S5PC100_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S5PC100_GPC(0), + .ngpio = S5PC100_GPIO_C_NR, + .label = "GPC", + }, + }, { + .chip = { + .base = S5PC100_GPD(0), + .ngpio = S5PC100_GPIO_D_NR, + .label = "GPD", + }, + }, { + .chip = { + .base = S5PC100_GPE0(0), + .ngpio = S5PC100_GPIO_E0_NR, + .label = "GPE0", + }, + }, { + .chip = { + .base = S5PC100_GPE1(0), + .ngpio = S5PC100_GPIO_E1_NR, + .label = "GPE1", + }, + }, { + .chip = { + .base = S5PC100_GPF0(0), + .ngpio = S5PC100_GPIO_F0_NR, + .label = "GPF0", + }, + }, { + .chip = { + .base = S5PC100_GPF1(0), + .ngpio = S5PC100_GPIO_F1_NR, + .label = "GPF1", + }, + }, { + .chip = { + .base = S5PC100_GPF2(0), + .ngpio = S5PC100_GPIO_F2_NR, + .label = "GPF2", + }, + }, { + .chip = { + .base = S5PC100_GPF3(0), + .ngpio = S5PC100_GPIO_F3_NR, + .label = "GPF3", + }, + }, { + .chip = { + .base = S5PC100_GPG0(0), + .ngpio = S5PC100_GPIO_G0_NR, + .label = "GPG0", + }, + }, { + .chip = { + .base = S5PC100_GPG1(0), + .ngpio = S5PC100_GPIO_G1_NR, + .label = "GPG1", + }, + }, { + .chip = { + .base = S5PC100_GPG2(0), + .ngpio = S5PC100_GPIO_G2_NR, + .label = "GPG2", + }, + }, { + .chip = { + .base = S5PC100_GPG3(0), + .ngpio = S5PC100_GPIO_G3_NR, + .label = "GPG3", + }, + }, { + .chip = { + .base = S5PC100_GPI(0), + .ngpio = S5PC100_GPIO_I_NR, + .label = "GPI", + }, + }, { + .chip = { + .base = S5PC100_GPJ0(0), + .ngpio = S5PC100_GPIO_J0_NR, + .label = "GPJ0", + }, + }, { + .chip = { + .base = S5PC100_GPJ1(0), + .ngpio = S5PC100_GPIO_J1_NR, + .label = "GPJ1", + }, + }, { + .chip = { + .base = S5PC100_GPJ2(0), + .ngpio = S5PC100_GPIO_J2_NR, + .label = "GPJ2", + }, + }, { + .chip = { + .base = S5PC100_GPJ3(0), + .ngpio = S5PC100_GPIO_J3_NR, + .label = "GPJ3", + }, + }, { + .chip = { + .base = S5PC100_GPJ4(0), + .ngpio = S5PC100_GPIO_J4_NR, + .label = "GPJ4", + }, + }, { + .chip = { + .base = S5PC100_GPK0(0), + .ngpio = S5PC100_GPIO_K0_NR, + .label = "GPK0", + }, + }, { + .chip = { + .base = S5PC100_GPK1(0), + .ngpio = S5PC100_GPIO_K1_NR, + .label = "GPK1", + }, + }, { + .chip = { + .base = S5PC100_GPK2(0), + .ngpio = S5PC100_GPIO_K2_NR, + .label = "GPK2", + }, + }, { + .chip = { + .base = S5PC100_GPK3(0), + .ngpio = S5PC100_GPIO_K3_NR, + .label = "GPK3", + }, + }, { + .chip = { + .base = S5PC100_GPL0(0), + .ngpio = S5PC100_GPIO_L0_NR, + .label = "GPL0", + }, + }, { + .chip = { + .base = S5PC100_GPL1(0), + .ngpio = S5PC100_GPIO_L1_NR, + .label = "GPL1", + }, + }, { + .chip = { + .base = S5PC100_GPL2(0), + .ngpio = S5PC100_GPIO_L2_NR, + .label = "GPL2", + }, + }, { + .chip = { + .base = S5PC100_GPL3(0), + .ngpio = S5PC100_GPIO_L3_NR, + .label = "GPL3", + }, + }, { + .chip = { + .base = S5PC100_GPL4(0), + .ngpio = S5PC100_GPIO_L4_NR, + .label = "GPL4", + }, + }, { + .base = (S5P_VA_GPIO + 0xC00), + .irq_base = IRQ_EINT(0), + .chip = { + .base = S5PC100_GPH0(0), + .ngpio = S5PC100_GPIO_H0_NR, + .label = "GPH0", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC20), + .irq_base = IRQ_EINT(8), + .chip = { + .base = S5PC100_GPH1(0), + .ngpio = S5PC100_GPIO_H1_NR, + .label = "GPH1", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC40), + .irq_base = IRQ_EINT(16), + .chip = { + .base = S5PC100_GPH2(0), + .ngpio = S5PC100_GPIO_H2_NR, + .label = "GPH2", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC60), + .irq_base = IRQ_EINT(24), + .chip = { + .base = S5PC100_GPH3(0), + .ngpio = S5PC100_GPIO_H3_NR, + .label = "GPH3", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +/* + * Followings are the gpio banks in S5PV210/S5PC110 + * + * The 'config' member when left to NULL, is initialized to the default + * structure samsung_gpio_cfgs[3] in the init function below. + * + * The 'base' member is also initialized in the init function below. + * Note: The initialization of 'base' member of samsung_gpio_chip structure + * uses the above macro and depends on the banks being listed in order here. + */ + +static struct samsung_gpio_chip s5pv210_gpios_4bit[] = { +#ifdef CONFIG_CPU_S5PV210 + { + .chip = { + .base = S5PV210_GPA0(0), + .ngpio = S5PV210_GPIO_A0_NR, + .label = "GPA0", + }, + }, { + .chip = { + .base = S5PV210_GPA1(0), + .ngpio = S5PV210_GPIO_A1_NR, + .label = "GPA1", + }, + }, { + .chip = { + .base = S5PV210_GPB(0), + .ngpio = S5PV210_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S5PV210_GPC0(0), + .ngpio = S5PV210_GPIO_C0_NR, + .label = "GPC0", + }, + }, { + .chip = { + .base = S5PV210_GPC1(0), + .ngpio = S5PV210_GPIO_C1_NR, + .label = "GPC1", + }, + }, { + .chip = { + .base = S5PV210_GPD0(0), + .ngpio = S5PV210_GPIO_D0_NR, + .label = "GPD0", + }, + }, { + .chip = { + .base = S5PV210_GPD1(0), + .ngpio = S5PV210_GPIO_D1_NR, + .label = "GPD1", + }, + }, { + .chip = { + .base = S5PV210_GPE0(0), + .ngpio = S5PV210_GPIO_E0_NR, + .label = "GPE0", + }, + }, { + .chip = { + .base = S5PV210_GPE1(0), + .ngpio = S5PV210_GPIO_E1_NR, + .label = "GPE1", + }, + }, { + .chip = { + .base = S5PV210_GPF0(0), + .ngpio = S5PV210_GPIO_F0_NR, + .label = "GPF0", + }, + }, { + .chip = { + .base = S5PV210_GPF1(0), + .ngpio = S5PV210_GPIO_F1_NR, + .label = "GPF1", + }, + }, { + .chip = { + .base = S5PV210_GPF2(0), + .ngpio = S5PV210_GPIO_F2_NR, + .label = "GPF2", + }, + }, { + .chip = { + .base = S5PV210_GPF3(0), + .ngpio = S5PV210_GPIO_F3_NR, + .label = "GPF3", + }, + }, { + .chip = { + .base = S5PV210_GPG0(0), + .ngpio = S5PV210_GPIO_G0_NR, + .label = "GPG0", + }, + }, { + .chip = { + .base = S5PV210_GPG1(0), + .ngpio = S5PV210_GPIO_G1_NR, + .label = "GPG1", + }, + }, { + .chip = { + .base = S5PV210_GPG2(0), + .ngpio = S5PV210_GPIO_G2_NR, + .label = "GPG2", + }, + }, { + .chip = { + .base = S5PV210_GPG3(0), + .ngpio = S5PV210_GPIO_G3_NR, + .label = "GPG3", + }, + }, { + .chip = { + .base = S5PV210_GPI(0), + .ngpio = S5PV210_GPIO_I_NR, + .label = "GPI", + }, + }, { + .chip = { + .base = S5PV210_GPJ0(0), + .ngpio = S5PV210_GPIO_J0_NR, + .label = "GPJ0", + }, + }, { + .chip = { + .base = S5PV210_GPJ1(0), + .ngpio = S5PV210_GPIO_J1_NR, + .label = "GPJ1", + }, + }, { + .chip = { + .base = S5PV210_GPJ2(0), + .ngpio = S5PV210_GPIO_J2_NR, + .label = "GPJ2", + }, + }, { + .chip = { + .base = S5PV210_GPJ3(0), + .ngpio = S5PV210_GPIO_J3_NR, + .label = "GPJ3", + }, + }, { + .chip = { + .base = S5PV210_GPJ4(0), + .ngpio = S5PV210_GPIO_J4_NR, + .label = "GPJ4", + }, + }, { + .chip = { + .base = S5PV210_MP01(0), + .ngpio = S5PV210_GPIO_MP01_NR, + .label = "MP01", + }, + }, { + .chip = { + .base = S5PV210_MP02(0), + .ngpio = S5PV210_GPIO_MP02_NR, + .label = "MP02", + }, + }, { + .chip = { + .base = S5PV210_MP03(0), + .ngpio = S5PV210_GPIO_MP03_NR, + .label = "MP03", + }, + }, { + .chip = { + .base = S5PV210_MP04(0), + .ngpio = S5PV210_GPIO_MP04_NR, + .label = "MP04", + }, + }, { + .chip = { + .base = S5PV210_MP05(0), + .ngpio = S5PV210_GPIO_MP05_NR, + .label = "MP05", + }, + }, { + .base = (S5P_VA_GPIO + 0xC00), + .irq_base = IRQ_EINT(0), + .chip = { + .base = S5PV210_GPH0(0), + .ngpio = S5PV210_GPIO_H0_NR, + .label = "GPH0", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC20), + .irq_base = IRQ_EINT(8), + .chip = { + .base = S5PV210_GPH1(0), + .ngpio = S5PV210_GPIO_H1_NR, + .label = "GPH1", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC40), + .irq_base = IRQ_EINT(16), + .chip = { + .base = S5PV210_GPH2(0), + .ngpio = S5PV210_GPIO_H2_NR, + .label = "GPH2", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC60), + .irq_base = IRQ_EINT(24), + .chip = { + .base = S5PV210_GPH3(0), + .ngpio = S5PV210_GPIO_H3_NR, + .label = "GPH3", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +/* + * Followings are the gpio banks in EXYNOS4210 + * + * The 'config' member when left to NULL, is initialized to the default + * structure samsung_gpio_cfgs[3] in the init function below. + * + * The 'base' member is also initialized in the init function below. + * Note: The initialization of 'base' member of samsung_gpio_chip structure + * uses the above macro and depends on the banks being listed in order here. + */ + +static struct samsung_gpio_chip exynos4_gpios_1[] = { +#ifdef CONFIG_ARCH_EXYNOS4 + { + .chip = { + .base = EXYNOS4_GPA0(0), + .ngpio = EXYNOS4_GPIO_A0_NR, + .label = "GPA0", + }, + }, { + .chip = { + .base = EXYNOS4_GPA1(0), + .ngpio = EXYNOS4_GPIO_A1_NR, + .label = "GPA1", + }, + }, { + .chip = { + .base = EXYNOS4_GPB(0), + .ngpio = EXYNOS4_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = EXYNOS4_GPC0(0), + .ngpio = EXYNOS4_GPIO_C0_NR, + .label = "GPC0", + }, + }, { + .chip = { + .base = EXYNOS4_GPC1(0), + .ngpio = EXYNOS4_GPIO_C1_NR, + .label = "GPC1", + }, + }, { + .chip = { + .base = EXYNOS4_GPD0(0), + .ngpio = EXYNOS4_GPIO_D0_NR, + .label = "GPD0", + }, + }, { + .chip = { + .base = EXYNOS4_GPD1(0), + .ngpio = EXYNOS4_GPIO_D1_NR, + .label = "GPD1", + }, + }, { + .chip = { + .base = EXYNOS4_GPE0(0), + .ngpio = EXYNOS4_GPIO_E0_NR, + .label = "GPE0", + }, + }, { + .chip = { + .base = EXYNOS4_GPE1(0), + .ngpio = EXYNOS4_GPIO_E1_NR, + .label = "GPE1", + }, + }, { + .chip = { + .base = EXYNOS4_GPE2(0), + .ngpio = EXYNOS4_GPIO_E2_NR, + .label = "GPE2", + }, + }, { + .chip = { + .base = EXYNOS4_GPE3(0), + .ngpio = EXYNOS4_GPIO_E3_NR, + .label = "GPE3", + }, + }, { + .chip = { + .base = EXYNOS4_GPE4(0), + .ngpio = EXYNOS4_GPIO_E4_NR, + .label = "GPE4", + }, + }, { + .chip = { + .base = EXYNOS4_GPF0(0), + .ngpio = EXYNOS4_GPIO_F0_NR, + .label = "GPF0", + }, + }, { + .chip = { + .base = EXYNOS4_GPF1(0), + .ngpio = EXYNOS4_GPIO_F1_NR, + .label = "GPF1", + }, + }, { + .chip = { + .base = EXYNOS4_GPF2(0), + .ngpio = EXYNOS4_GPIO_F2_NR, + .label = "GPF2", + }, + }, { + .chip = { + .base = EXYNOS4_GPF3(0), + .ngpio = EXYNOS4_GPIO_F3_NR, + .label = "GPF3", + }, + }, +#endif +}; + +static struct samsung_gpio_chip exynos4_gpios_2[] = { +#ifdef CONFIG_ARCH_EXYNOS4 + { + .chip = { + .base = EXYNOS4_GPJ0(0), + .ngpio = EXYNOS4_GPIO_J0_NR, + .label = "GPJ0", + }, + }, { + .chip = { + .base = EXYNOS4_GPJ1(0), + .ngpio = EXYNOS4_GPIO_J1_NR, + .label = "GPJ1", + }, + }, { + .chip = { + .base = EXYNOS4_GPK0(0), + .ngpio = EXYNOS4_GPIO_K0_NR, + .label = "GPK0", + }, + }, { + .chip = { + .base = EXYNOS4_GPK1(0), + .ngpio = EXYNOS4_GPIO_K1_NR, + .label = "GPK1", + }, + }, { + .chip = { + .base = EXYNOS4_GPK2(0), + .ngpio = EXYNOS4_GPIO_K2_NR, + .label = "GPK2", + }, + }, { + .chip = { + .base = EXYNOS4_GPK3(0), + .ngpio = EXYNOS4_GPIO_K3_NR, + .label = "GPK3", + }, + }, { + .chip = { + .base = EXYNOS4_GPL0(0), + .ngpio = EXYNOS4_GPIO_L0_NR, + .label = "GPL0", + }, + }, { + .chip = { + .base = EXYNOS4_GPL1(0), + .ngpio = EXYNOS4_GPIO_L1_NR, + .label = "GPL1", + }, + }, { + .chip = { + .base = EXYNOS4_GPL2(0), + .ngpio = EXYNOS4_GPIO_L2_NR, + .label = "GPL2", + }, + }, { + .config = &samsung_gpio_cfgs[8], + .chip = { + .base = EXYNOS4_GPY0(0), + .ngpio = EXYNOS4_GPIO_Y0_NR, + .label = "GPY0", + }, + }, { + .config = &samsung_gpio_cfgs[8], + .chip = { + .base = EXYNOS4_GPY1(0), + .ngpio = EXYNOS4_GPIO_Y1_NR, + .label = "GPY1", + }, + }, { + .config = &samsung_gpio_cfgs[8], + .chip = { + .base = EXYNOS4_GPY2(0), + .ngpio = EXYNOS4_GPIO_Y2_NR, + .label = "GPY2", + }, + }, { + .config = &samsung_gpio_cfgs[8], + .chip = { + .base = EXYNOS4_GPY3(0), + .ngpio = EXYNOS4_GPIO_Y3_NR, + .label = "GPY3", + }, + }, { + .config = &samsung_gpio_cfgs[8], + .chip = { + .base = EXYNOS4_GPY4(0), + .ngpio = EXYNOS4_GPIO_Y4_NR, + .label = "GPY4", + }, + }, { + .config = &samsung_gpio_cfgs[8], + .chip = { + .base = EXYNOS4_GPY5(0), + .ngpio = EXYNOS4_GPIO_Y5_NR, + .label = "GPY5", + }, + }, { + .config = &samsung_gpio_cfgs[8], + .chip = { + .base = EXYNOS4_GPY6(0), + .ngpio = EXYNOS4_GPIO_Y6_NR, + .label = "GPY6", + }, + }, { + .base = (S5P_VA_GPIO2 + 0xC00), + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(0), + .chip = { + .base = EXYNOS4_GPX0(0), + .ngpio = EXYNOS4_GPIO_X0_NR, + .label = "GPX0", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO2 + 0xC20), + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(8), + .chip = { + .base = EXYNOS4_GPX1(0), + .ngpio = EXYNOS4_GPIO_X1_NR, + .label = "GPX1", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO2 + 0xC40), + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(16), + .chip = { + .base = EXYNOS4_GPX2(0), + .ngpio = EXYNOS4_GPIO_X2_NR, + .label = "GPX2", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO2 + 0xC60), + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(24), + .chip = { + .base = EXYNOS4_GPX3(0), + .ngpio = EXYNOS4_GPIO_X3_NR, + .label = "GPX3", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +static struct samsung_gpio_chip exynos4_gpios_3[] = { +#ifdef CONFIG_ARCH_EXYNOS4 + { + .chip = { + .base = EXYNOS4_GPZ(0), + .ngpio = EXYNOS4_GPIO_Z_NR, + .label = "GPZ", + }, + }, +#endif +}; + +/* TODO: cleanup soc_is_* */ +static __init int samsung_gpiolib_init(void) +{ + struct samsung_gpio_chip *chip; + int i, nr_chips; + int group = 0; + + samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs)); + + if (soc_is_s3c24xx()) { + s3c24xx_gpiolib_add_chips(s3c24xx_gpios, + ARRAY_SIZE(s3c24xx_gpios), S3C24XX_VA_GPIO); + } else if (soc_is_s3c64xx()) { + samsung_gpiolib_add_2bit_chips(s3c64xx_gpios_2bit, + ARRAY_SIZE(s3c64xx_gpios_2bit), + S3C64XX_VA_GPIO + 0xE0, 0x20); + samsung_gpiolib_add_4bit_chips(s3c64xx_gpios_4bit, + ARRAY_SIZE(s3c64xx_gpios_4bit), + S3C64XX_VA_GPIO); + samsung_gpiolib_add_4bit2_chips(s3c64xx_gpios_4bit2, + ARRAY_SIZE(s3c64xx_gpios_4bit2)); + } else if (soc_is_s5p6440()) { + samsung_gpiolib_add_2bit_chips(s5p6440_gpios_2bit, + ARRAY_SIZE(s5p6440_gpios_2bit), NULL, 0x0); + samsung_gpiolib_add_4bit_chips(s5p6440_gpios_4bit, + ARRAY_SIZE(s5p6440_gpios_4bit), S5P_VA_GPIO); + samsung_gpiolib_add_4bit2_chips(s5p6440_gpios_4bit2, + ARRAY_SIZE(s5p6440_gpios_4bit2)); + s5p64x0_gpiolib_add_rbank(s5p6440_gpios_rbank, + ARRAY_SIZE(s5p6440_gpios_rbank)); + } else if (soc_is_s5p6450()) { + samsung_gpiolib_add_2bit_chips(s5p6450_gpios_2bit, + ARRAY_SIZE(s5p6450_gpios_2bit), NULL, 0x0); + samsung_gpiolib_add_4bit_chips(s5p6450_gpios_4bit, + ARRAY_SIZE(s5p6450_gpios_4bit), S5P_VA_GPIO); + samsung_gpiolib_add_4bit2_chips(s5p6450_gpios_4bit2, + ARRAY_SIZE(s5p6450_gpios_4bit2)); + s5p64x0_gpiolib_add_rbank(s5p6450_gpios_rbank, + ARRAY_SIZE(s5p6450_gpios_rbank)); + } else if (soc_is_s5pc100()) { + group = 0; + chip = s5pc100_gpios_4bit; + nr_chips = ARRAY_SIZE(s5pc100_gpios_4bit); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &samsung_gpio_cfgs[3]; + chip->group = group++; + } + } + samsung_gpiolib_add_4bit_chips(s5pc100_gpios_4bit, nr_chips, S5P_VA_GPIO); +#if defined(CONFIG_CPU_S5PC100) && defined(CONFIG_S5P_GPIO_INT) + s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); +#endif + } else if (soc_is_s5pv210()) { + group = 0; + chip = s5pv210_gpios_4bit; + nr_chips = ARRAY_SIZE(s5pv210_gpios_4bit); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &samsung_gpio_cfgs[3]; + chip->group = group++; + } + } + samsung_gpiolib_add_4bit_chips(s5pv210_gpios_4bit, nr_chips, S5P_VA_GPIO); +#if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_S5P_GPIO_INT) + s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); +#endif + } else if (soc_is_exynos4210()) { + group = 0; + + /* gpio part1 */ + chip = exynos4_gpios_1; + nr_chips = ARRAY_SIZE(exynos4_gpios_1); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos4_gpio_cfg; + chip->group = group++; + } + } + samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, nr_chips, S5P_VA_GPIO1); + + /* gpio part2 */ + chip = exynos4_gpios_2; + nr_chips = ARRAY_SIZE(exynos4_gpios_2); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos4_gpio_cfg; + chip->group = group++; + } + } + samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, nr_chips, S5P_VA_GPIO2); + + /* gpio part3 */ + chip = exynos4_gpios_3; + nr_chips = ARRAY_SIZE(exynos4_gpios_3); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos4_gpio_cfg; + chip->group = group++; + } + } + samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, nr_chips, S5P_VA_GPIO3); + +#if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT) + s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS); + s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS); +#endif + } else { + WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n"); + return -ENODEV; + } + + return 0; +} +core_initcall(samsung_gpiolib_init); + +int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + int offset; + int ret; + + if (!chip) + return -EINVAL; + + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + ret = samsung_gpio_do_setcfg(chip, offset, config); + samsung_gpio_unlock(chip, flags); + + return ret; +} +EXPORT_SYMBOL(s3c_gpio_cfgpin); + +int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, + unsigned int cfg) +{ + int ret; + + for (; nr > 0; nr--, start++) { + ret = s3c_gpio_cfgpin(start, cfg); + if (ret != 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(s3c_gpio_cfgpin_range); + +int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, + unsigned int cfg, samsung_gpio_pull_t pull) +{ + int ret; + + for (; nr > 0; nr--, start++) { + s3c_gpio_setpull(start, pull); + ret = s3c_gpio_cfgpin(start, cfg); + if (ret != 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(s3c_gpio_cfgall_range); + +unsigned s3c_gpio_getcfg(unsigned int pin) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + unsigned ret = 0; + int offset; + + if (chip) { + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + ret = samsung_gpio_do_getcfg(chip, offset); + samsung_gpio_unlock(chip, flags); + } + + return ret; +} +EXPORT_SYMBOL(s3c_gpio_getcfg); + +int s3c_gpio_setpull(unsigned int pin, samsung_gpio_pull_t pull) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + int offset, ret; + + if (!chip) + return -EINVAL; + + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + ret = samsung_gpio_do_setpull(chip, offset, pull); + samsung_gpio_unlock(chip, flags); + + return ret; +} +EXPORT_SYMBOL(s3c_gpio_setpull); + +samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + int offset; + u32 pup = 0; + + if (chip) { + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + pup = samsung_gpio_do_getpull(chip, offset); + samsung_gpio_unlock(chip, flags); + } + + return (__force samsung_gpio_pull_t)pup; +} +EXPORT_SYMBOL(s3c_gpio_getpull); + +/* gpiolib wrappers until these are totally eliminated */ + +void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) +{ + int ret; + + WARN_ON(to); /* should be none of these left */ + + if (!to) { + /* if pull is enabled, try first with up, and if that + * fails, try using down */ + + ret = s3c_gpio_setpull(pin, S3C_GPIO_PULL_UP); + if (ret) + s3c_gpio_setpull(pin, S3C_GPIO_PULL_DOWN); + } else { + s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE); + } +} +EXPORT_SYMBOL(s3c2410_gpio_pullup); + +void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) +{ + /* do this via gpiolib until all users removed */ + + gpio_request(pin, "temporary"); + gpio_set_value(pin, to); + gpio_free(pin); +} +EXPORT_SYMBOL(s3c2410_gpio_setpin); + +unsigned int s3c2410_gpio_getpin(unsigned int pin) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long offs = pin - chip->chip.base; + + return __raw_readl(chip->base + 0x04) & (1 << offs); +} +EXPORT_SYMBOL(s3c2410_gpio_getpin); + +#ifdef CONFIG_S5P_GPIO_DRVSTR +s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned int off; + void __iomem *reg; + int shift; + u32 drvstr; + + if (!chip) + return -EINVAL; + + off = pin - chip->chip.base; + shift = off * 2; + reg = chip->base + 0x0C; + + drvstr = __raw_readl(reg); + drvstr = drvstr >> shift; + drvstr &= 0x3; + + return (__force s5p_gpio_drvstr_t)drvstr; +} +EXPORT_SYMBOL(s5p_gpio_get_drvstr); + +int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned int off; + void __iomem *reg; + int shift; + u32 tmp; + + if (!chip) + return -EINVAL; + + off = pin - chip->chip.base; + shift = off * 2; + reg = chip->base + 0x0C; + + tmp = __raw_readl(reg); + tmp &= ~(0x3 << shift); + tmp |= drvstr << shift; + + __raw_writel(tmp, reg); + + return 0; +} +EXPORT_SYMBOL(s5p_gpio_set_drvstr); +#endif /* CONFIG_S5P_GPIO_DRVSTR */ + +#ifdef CONFIG_PLAT_S3C24XX +unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) +{ + unsigned long flags; + unsigned long misccr; + + local_irq_save(flags); + misccr = __raw_readl(S3C24XX_MISCCR); + misccr &= ~clear; + misccr ^= change; + __raw_writel(misccr, S3C24XX_MISCCR); + local_irq_restore(flags); + + return misccr; +} +EXPORT_SYMBOL(s3c2410_modify_misccr); +#endif diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 846fbd5e31bf..0ce6ac9898b1 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/errno.h> +#include <linux/module.h> #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c index 1c3649242208..9afe495c12c7 100644 --- a/drivers/gpu/drm/ati_pcigart.c +++ b/drivers/gpu/drm/ati_pcigart.c @@ -31,6 +31,7 @@ * DEALINGS IN THE SOFTWARE. */ +#include <linux/export.h> #include "drmP.h" # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ diff --git a/drivers/gpu/drm/drm_buffer.c b/drivers/gpu/drm/drm_buffer.c index 529a0dbe9fc6..08ccefedb327 100644 --- a/drivers/gpu/drm/drm_buffer.c +++ b/drivers/gpu/drm/drm_buffer.c @@ -32,6 +32,7 @@ * Pauli Nieminen <suokkos-at-gmail-dot-com> */ +#include <linux/export.h> #include "drm_buffer.h" /** diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 61e1ef90d4e5..30372f7b2d45 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -36,6 +36,7 @@ #include <linux/vmalloc.h> #include <linux/slab.h> #include <linux/log2.h> +#include <linux/export.h> #include <asm/shmparam.h> #include "drmP.h" diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index 0e3bd5b54b78..592865381c6e 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -28,6 +28,7 @@ * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> */ +#include <linux/export.h> #include "drmP.h" #if defined(CONFIG_X86) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index fe738f05309b..9a2e2a14b3bb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -31,6 +31,7 @@ */ #include <linux/list.h> #include <linux/slab.h> +#include <linux/export.h> #include "drm.h" #include "drmP.h" #include "drm_crtc.h" @@ -162,6 +163,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 }, { DRM_MODE_CONNECTOR_TV, "TV", 0 }, { DRM_MODE_CONNECTOR_eDP, "eDP", 0 }, + { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0}, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = @@ -170,6 +172,7 @@ static struct drm_prop_enum_list drm_encoder_enum_list[] = { DRM_MODE_ENCODER_TMDS, "TMDS" }, { DRM_MODE_ENCODER_LVDS, "LVDS" }, { DRM_MODE_ENCODER_TVDAC, "TV" }, + { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, }; char *drm_get_encoder_name(struct drm_encoder *encoder) @@ -463,8 +466,10 @@ void drm_connector_init(struct drm_device *dev, list_add_tail(&connector->head, &dev->mode_config.connector_list); dev->mode_config.num_connector++; - drm_connector_attach_property(connector, - dev->mode_config.edid_property, 0); + if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) + drm_connector_attach_property(connector, + dev->mode_config.edid_property, + 0); drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index f2366440b738..2957636161e8 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -29,6 +29,9 @@ * Jesse Barnes <jesse.barnes@intel.com> */ +#include <linux/export.h> +#include <linux/moduleparam.h> + #include "drmP.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index b9dc2629ea9a..d067c12ba940 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -33,6 +33,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/export.h> #include "drmP.h" #if defined(CONFIG_DEBUG_FS) diff --git a/drivers/gpu/drm/drm_dma.c b/drivers/gpu/drm/drm_dma.c index 252cbd74df0e..cfb4e333ec0f 100644 --- a/drivers/gpu/drm/drm_dma.c +++ b/drivers/gpu/drm/drm_dma.c @@ -33,6 +33,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include <linux/export.h> #include "drmP.h" /** diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 7a87e0878f30..fc81af9dbf42 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -48,6 +48,7 @@ #include <linux/debugfs.h> #include <linux/slab.h> +#include <linux/export.h> #include "drmP.h" #include "drm_core.h" diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index fe39c3570538..3e927ce7557d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -30,6 +30,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/export.h> #include "drmP.h" #include "drm_edid.h" #include "drm_edid_modes.h" diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c index d62c064fbaa0..fb943551060e 100644 --- a/drivers/gpu/drm/drm_encoder_slave.c +++ b/drivers/gpu/drm/drm_encoder_slave.c @@ -24,6 +24,8 @@ * */ +#include <linux/module.h> + #include "drm_encoder_slave.h" /** diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index f7c6854eb4dd..80fe39d98b0c 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -31,6 +31,7 @@ #include <linux/sysrq.h> #include <linux/slab.h> #include <linux/fb.h> +#include <linux/module.h> #include "drmP.h" #include "drm_crtc.h" #include "drm_fb_helper.h" diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 2ec7d48fc4a8..4911e1d1dcf2 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -37,6 +37,7 @@ #include "drmP.h" #include <linux/poll.h> #include <linux/slab.h> +#include <linux/module.h> /* from BKL pushdown: note that nothing else serializes idr_find() */ DEFINE_MUTEX(drm_global_mutex); diff --git a/drivers/gpu/drm/drm_hashtab.c b/drivers/gpu/drm/drm_hashtab.c index e3a75688f3cd..68dc8744b630 100644 --- a/drivers/gpu/drm/drm_hashtab.c +++ b/drivers/gpu/drm/drm_hashtab.c @@ -36,6 +36,7 @@ #include "drm_hashtab.h" #include <linux/hash.h> #include <linux/slab.h> +#include <linux/export.h> int drm_ht_create(struct drm_open_hash *ht, unsigned int order) { diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 4a058c7af6c0..ddd70db45f76 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -29,6 +29,7 @@ */ #include <linux/compat.h> #include <linux/ratelimit.h> +#include <linux/export.h> #include "drmP.h" #include "drm_core.h" diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 3830e9e478c0..cb3794a00f98 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -40,6 +40,7 @@ #include <linux/slab.h> #include <linux/vgaarb.h> +#include <linux/export.h> /* Access macro for slots in vblank timestamp ringbuffer. */ #define vblanktimestamp(dev, crtc, count) ( \ diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index c9b805000a11..c8b6b66d428d 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c @@ -34,6 +34,7 @@ */ #include <linux/highmem.h> +#include <linux/export.h> #include "drmP.h" /** diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 959186cbf328..961fb54f4266 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -45,6 +45,7 @@ #include "drm_mm.h" #include <linux/slab.h> #include <linux/seq_file.h> +#include <linux/export.h> #define MM_UNUSED_TARGET 4 diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ad74fb4dc542..fb8e46b4e8bc 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -32,6 +32,7 @@ #include <linux/list.h> #include <linux/list_sort.h> +#include <linux/export.h> #include "drmP.h" #include "drm.h" #include "drm_crtc.h" diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index b6a19cb07caf..d4d10b7880cf 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -39,6 +39,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/dma-mapping.h> +#include <linux/export.h> #include "drmP.h" /**********************************************************************/ diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 2a8b6265ad3d..ae9db5e2b27c 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -25,6 +25,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include <linux/export.h> #include "drmP.h" /** diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c index 0f3c4e3cafc3..fff87221f9e9 100644 --- a/drivers/gpu/drm/drm_proc.c +++ b/drivers/gpu/drm/drm_proc.c @@ -39,6 +39,7 @@ #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/export.h> #include "drmP.h" /*************************************************** diff --git a/drivers/gpu/drm/drm_sman.c b/drivers/gpu/drm/drm_sman.c index 34664587a74e..cebce45f4429 100644 --- a/drivers/gpu/drm/drm_sman.c +++ b/drivers/gpu/drm/drm_sman.c @@ -36,6 +36,7 @@ * Thomas Hellström <thomas-at-tungstengraphics-dot-com> */ +#include <linux/export.h> #include "drm_sman.h" struct drm_owner_item { diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 2eee8e016b38..0f9ef9bf6730 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -16,6 +16,7 @@ #include <linux/kdev_t.h> #include <linux/gfp.h> #include <linux/err.h> +#include <linux/export.h> #include "drm_sysfs.h" #include "drm_core.h" diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c index 206d2300d873..445003f4dc93 100644 --- a/drivers/gpu/drm/drm_usb.c +++ b/drivers/gpu/drm/drm_usb.c @@ -1,5 +1,6 @@ #include "drmP.h" #include <linux/usb.h> +#include <linux/export.h> #ifdef CONFIG_USB int drm_get_usb_dev(struct usb_interface *interface, diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 5db96d45fc71..8c03eaf41448 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -34,6 +34,7 @@ */ #include "drmP.h" +#include <linux/export.h> #if defined(__ia64__) #include <linux/efi.h> #include <linux/slab.h> diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index 08792a740f18..07d55df6623e 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c @@ -24,6 +24,8 @@ * */ +#include <linux/module.h> + #include "ch7006_priv.h" /* DRM encoder functions */ diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c index 0b6773290c08..b7d45ab4ba69 100644 --- a/drivers/gpu/drm/i2c/sil164_drv.c +++ b/drivers/gpu/drm/i2c/sil164_drv.c @@ -24,6 +24,8 @@ * */ +#include <linux/module.h> + #include "drmP.h" #include "drm_crtc_helper.h" #include "drm_encoder_slave.h" diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c index 6f98d059f68a..d4266bdf6fb4 100644 --- a/drivers/gpu/drm/i810/i810_drv.c +++ b/drivers/gpu/drm/i810/i810_drv.c @@ -30,6 +30,8 @@ * Gareth Hughes <gareth@valinux.com> */ +#include <linux/module.h> + #include "drmP.h" #include "drm.h" #include "i810_drm.h" diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 8e95d66800b0..d14b44e13f51 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -29,6 +29,7 @@ #include <linux/seq_file.h> #include <linux/debugfs.h> #include <linux/slab.h> +#include <linux/export.h> #include "drmP.h" #include "drm.h" #include "intel_drv.h" diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2eac955dee18..a9533c54c93c 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -41,6 +41,7 @@ #include <linux/pnp.h> #include <linux/vga_switcheroo.h> #include <linux/slab.h> +#include <linux/module.h> #include <acpi/video.h> static void i915_write_hws_pga(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 4c8d681c2151..cc531bb59c26 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -35,6 +35,7 @@ #include "intel_drv.h" #include <linux/console.h> +#include <linux/module.h> #include "drm_crtc_helper.h" static int i915_modeset __read_mostly = -1; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fc1a0832af4f..09b318b0227f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -27,6 +27,7 @@ #include <linux/i2c.h> #include <linux/slab.h> +#include <linux/export.h> #include "drmP.h" #include "drm.h" #include "drm_crtc.h" diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 9ed5380e5a53..d30ccccb9d73 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -28,6 +28,7 @@ */ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> +#include <linux/export.h> #include "drmP.h" #include "drm.h" #include "intel_drv.h" diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 6db3b1ccb6eb..3003fb25aefd 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -28,6 +28,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/export.h> #include "drmP.h" #include "drm.h" #include "drm_crtc.h" diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c index 42d31874edf2..33daa29eea66 100644 --- a/drivers/gpu/drm/mga/mga_drv.c +++ b/drivers/gpu/drm/mga/mga_drv.c @@ -29,6 +29,8 @@ * Gareth Hughes <gareth@valinux.com> */ +#include <linux/module.h> + #include "drmP.h" #include "drm.h" #include "mga_drm.h" diff --git a/drivers/gpu/drm/mga/mga_warp.c b/drivers/gpu/drm/mga/mga_warp.c index f172bd5c257f..722a91b69b0c 100644 --- a/drivers/gpu/drm/mga/mga_warp.c +++ b/drivers/gpu/drm/mga/mga_warp.c @@ -30,6 +30,7 @@ #include <linux/firmware.h> #include <linux/ihex.h> #include <linux/platform_device.h> +#include <linux/module.h> #include "drmP.h" #include "drm.h" diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index c1e01f37b9d1..9f7bb1295262 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -23,6 +23,7 @@ */ #include <linux/console.h> +#include <linux/module.h> #include "drmP.h" #include "drm.h" diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index f6a27fabcfe0..c6143df48b9f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -22,6 +22,8 @@ * Authors: Ben Skeggs */ +#include <linux/module.h> + #include "drmP.h" #include "nouveau_drv.h" #include "nouveau_i2c.h" diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c index 081ca7b03e8a..5a46446dd5a8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_temp.c +++ b/drivers/gpu/drm/nouveau/nouveau_temp.c @@ -22,6 +22,8 @@ * Authors: Martin Peres */ +#include <linux/module.h> + #include "drmP.h" #include "nouveau_drv.h" diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index 4b8d0b3f7d2b..bbdbc51830c8 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -23,6 +23,7 @@ */ #include <linux/firmware.h> +#include <linux/module.h> #include "drmP.h" diff --git a/drivers/gpu/drm/r128/r128_cce.c b/drivers/gpu/drm/r128/r128_cce.c index 570e190710bd..bcac90b543ad 100644 --- a/drivers/gpu/drm/r128/r128_cce.c +++ b/drivers/gpu/drm/r128/r128_cce.c @@ -32,6 +32,7 @@ #include <linux/firmware.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/module.h> #include "drmP.h" #include "drm.h" diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c index b9e8efd2b754..4c8796ba6dd8 100644 --- a/drivers/gpu/drm/r128/r128_drv.c +++ b/drivers/gpu/drm/r128/r128_drv.c @@ -29,6 +29,8 @@ * Gareth Hughes <gareth@valinux.com> */ +#include <linux/module.h> + #include "drmP.h" #include "drm.h" #include "r128_drm.h" diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 9f363e0c4b60..cf8b4bc3e73d 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -70,7 +70,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \ evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \ - radeon_trace_points.o ni.o cayman_blit_shaders.o + radeon_trace_points.o ni.o cayman_blit_shaders.o atombios_encoders.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index a515b2a09d85..87921c88a95c 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -558,7 +558,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, bpc = connector->display_info.bpc; encoder_mode = atombios_get_encoder_mode(encoder); if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || - radeon_encoder_is_dp_bridge(encoder)) { + (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { if (connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector_atom_dig *dig_connector = @@ -638,44 +638,29 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (ss_enabled && ss->percentage) args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_SS_ENABLE; - if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT) || - radeon_encoder_is_dp_bridge(encoder)) { + if (ENCODER_MODE_IS_DP(encoder_mode)) { + args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_COHERENT_MODE; + /* 16200 or 27000 */ + args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); + } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - if (encoder_mode == ATOM_ENCODER_MODE_DP) { + if (encoder_mode == ATOM_ENCODER_MODE_HDMI) + /* deep color support */ + args.v3.sInput.usPixelClock = + cpu_to_le16((mode->clock * bpc / 8) / 10); + if (dig->coherent_mode) args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_COHERENT_MODE; - /* 16200 or 27000 */ - args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); - } else { - if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { - /* deep color support */ - args.v3.sInput.usPixelClock = - cpu_to_le16((mode->clock * bpc / 8) / 10); - } - if (dig->coherent_mode) - args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_COHERENT_MODE; - if (mode->clock > 165000) - args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_DUAL_LINK; - } - } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (encoder_mode == ATOM_ENCODER_MODE_DP) { + if (mode->clock > 165000) args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_COHERENT_MODE; - /* 16200 or 27000 */ - args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); - } else if (encoder_mode != ATOM_ENCODER_MODE_LVDS) { - if (mode->clock > 165000) - args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_DUAL_LINK; - } + DISPPLL_CONFIG_DUAL_LINK; } - if (radeon_encoder_is_dp_bridge(encoder)) { - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); - args.v3.sInput.ucExtTransmitterID = ext_radeon_encoder->encoder_id; - } else + if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != + ENCODER_OBJECT_ID_NONE) + args.v3.sInput.ucExtTransmitterID = + radeon_encoder_get_dp_bridge_encoder_id(encoder); + else args.v3.sInput.ucExtTransmitterID = 0; atom_execute_table(rdev->mode_info.atom_context, @@ -945,6 +930,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode bpc = connector->display_info.bpc; switch (encoder_mode) { + case ATOM_ENCODER_MODE_DP_MST: case ATOM_ENCODER_MODE_DP: /* DP/eDP */ dp_clock = dig_connector->dp_clock / 10; @@ -1450,7 +1436,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) * PPLL/DCPLL programming and only program the DP DTO for the * crtc virtual pixel clock. */ - if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) { + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { if (ASIC_IS_DCE5(rdev) || rdev->clock.dp_extclk) return ATOM_PPLL_INVALID; } diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 79e8ebc05307..a0de48542f71 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -482,7 +482,8 @@ static int radeon_dp_get_dp_link_clock(struct drm_connector *connector, int bpp = convert_bpc_to_bpp(connector->display_info.bpc); int lane_num, max_pix_clock; - if (radeon_connector_encoder_is_dp_bridge(connector)) + if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == + ENCODER_OBJECT_ID_NUTMEG) return 270000; lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock); @@ -553,17 +554,32 @@ static void radeon_dp_set_panel_mode(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; if (!ASIC_IS_DCE4(rdev)) return; - if (radeon_connector_encoder_is_dp_bridge(connector)) + if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == + ENCODER_OBJECT_ID_NUTMEG) panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; + else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == + ENCODER_OBJECT_ID_TRAVIS) + panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; + else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + u8 tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); + if (tmp & 1) + panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; + } atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP_PANEL_MODE, panel_mode); + + if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) && + (panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) { + radeon_write_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_SET, 1); + } } void radeon_dp_set_link_config(struct drm_connector *connector, diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c new file mode 100644 index 000000000000..39c04c1b8472 --- /dev/null +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -0,0 +1,2369 @@ +/* + * Copyright 2007-11 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "drm_crtc_helper.h" +#include "radeon_drm.h" +#include "radeon.h" +#include "atom.h" + +extern int atom_debug; + +/* evil but including atombios.h is much worse */ +bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, + struct drm_display_mode *mode); + + +static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + return true; + default: + return false; + } +} + +static struct drm_connector * +radeon_get_connector_for_encoder_init(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + if (radeon_encoder->devices & radeon_connector->devices) + return connector; + } + return NULL; +} + +static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + + /* set the active encoder to connector routing */ + radeon_encoder_set_active_device(encoder); + drm_mode_set_crtcinfo(adjusted_mode, 0); + + /* hw bug */ + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) + && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; + + /* get the native mode for LVDS */ + if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) + radeon_panel_mode_fixup(encoder, adjusted_mode); + + /* get the native mode for TV */ + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { + struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; + if (tv_dac) { + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M) + radeon_atom_get_tv_timings(rdev, 0, adjusted_mode); + else + radeon_atom_get_tv_timings(rdev, 1, adjusted_mode); + } + } + + if (ASIC_IS_DCE3(rdev) && + ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || + (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE))) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + radeon_dp_set_link_config(connector, mode); + } + + return true; +} + +static void +atombios_dac_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DAC_ENCODER_CONTROL_PS_ALLOCATION args; + int index = 0; + struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); + break; + } + + args.ucAction = action; + + if (radeon_encoder->active_device & (ATOM_DEVICE_CRT_SUPPORT)) + args.ucDacStandard = ATOM_DAC1_PS2; + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.ucDacStandard = ATOM_DAC1_CV; + else { + switch (dac_info->tv_std) { + case TV_STD_PAL: + case TV_STD_PAL_M: + case TV_STD_SCART_PAL: + case TV_STD_SECAM: + case TV_STD_PAL_CN: + args.ucDacStandard = ATOM_DAC1_PAL; + break; + case TV_STD_NTSC: + case TV_STD_NTSC_J: + case TV_STD_PAL_60: + default: + args.ucDacStandard = ATOM_DAC1_NTSC; + break; + } + } + args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void +atombios_tv_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + TV_ENCODER_CONTROL_PS_ALLOCATION args; + int index = 0; + struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; + + memset(&args, 0, sizeof(args)); + + index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); + + args.sTVEncoder.ucAction = action; + + if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.sTVEncoder.ucTvStandard = ATOM_TV_CV; + else { + switch (dac_info->tv_std) { + case TV_STD_NTSC: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; + break; + case TV_STD_PAL: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; + break; + case TV_STD_PAL_M: + args.sTVEncoder.ucTvStandard = ATOM_TV_PALM; + break; + case TV_STD_PAL_60: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; + break; + case TV_STD_NTSC_J: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; + break; + case TV_STD_SCART_PAL: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ + break; + case TV_STD_SECAM: + args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; + break; + case TV_STD_PAL_CN: + args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; + break; + default: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; + break; + } + } + + args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +union dvo_encoder_control { + ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; + DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; + DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; +}; + +void +atombios_dvo_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + union dvo_encoder_control args; + int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + uint8_t frev, crev; + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + switch (crev) { + case 1: + /* R4xx, R5xx */ + args.ext_tmds.sXTmdsEncoder.ucEnable = action; + + if (radeon_encoder->pixel_clock > 165000) + args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL; + + args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB; + break; + case 2: + /* RS600/690/740 */ + args.dvo.sDVOEncoder.ucAction = action; + args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + /* DFP1, CRT1, TV1 depending on the type of port */ + args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX; + + if (radeon_encoder->pixel_clock > 165000) + args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL; + break; + case 3: + /* R6xx */ + args.dvo_v3.ucAction = action; + args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.dvo_v3.ucDVOConfig = 0; /* XXX */ + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +union lvds_encoder_control { + LVDS_ENCODER_CONTROL_PS_ALLOCATION v1; + LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2; +}; + +void +atombios_digital_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + union lvds_encoder_control args; + int index = 0; + int hdmi_detected = 0; + uint8_t frev, crev; + + if (!dig) + return; + + if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) + hdmi_detected = 1; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); + break; + } + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + case 2: + switch (crev) { + case 1: + args.v1.ucMisc = 0; + args.v1.ucAction = action; + if (hdmi_detected) + args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) + args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) + args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; + } else { + if (dig->linkb) + args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; + /*if (pScrn->rgbBits == 8) */ + args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; + } + break; + case 2: + case 3: + args.v2.ucMisc = 0; + args.v2.ucAction = action; + if (crev == 3) { + if (dig->coherent_mode) + args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; + } + if (hdmi_detected) + args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v2.ucTruncate = 0; + args.v2.ucSpatial = 0; + args.v2.ucTemporal = 0; + args.v2.ucFRC = 0; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) + args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) { + args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; + if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) + args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; + } + if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) { + args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; + if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) + args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; + if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2) + args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; + } + } else { + if (dig->linkb) + args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; + if (radeon_encoder->pixel_clock > 165000) + args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +int +atombios_get_encoder_mode(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *dig_connector; + + /* dp bridges are always DP */ + if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) + return ATOM_ENCODER_MODE_DP; + + /* DVO is always DVO */ + if (radeon_encoder->encoder_id == ATOM_ENCODER_MODE_DVO) + return ATOM_ENCODER_MODE_DVO; + + connector = radeon_get_connector_for_encoder(encoder); + /* if we don't have an active device yet, just use one of + * the connectors tied to the encoder. + */ + if (!connector) + connector = radeon_get_connector_for_encoder_init(encoder); + radeon_connector = to_radeon_connector(connector); + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ + if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else if (radeon_connector->use_digital) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_CRT; + break; + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_HDMIA: + default: + if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else + return ATOM_ENCODER_MODE_DVI; + break; + case DRM_MODE_CONNECTOR_LVDS: + return ATOM_ENCODER_MODE_LVDS; + break; + case DRM_MODE_CONNECTOR_DisplayPort: + dig_connector = radeon_connector->con_priv; + if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || + (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) + return ATOM_ENCODER_MODE_DP; + else if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else + return ATOM_ENCODER_MODE_DVI; + break; + case DRM_MODE_CONNECTOR_eDP: + return ATOM_ENCODER_MODE_DP; + case DRM_MODE_CONNECTOR_DVIA: + case DRM_MODE_CONNECTOR_VGA: + return ATOM_ENCODER_MODE_CRT; + break; + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_9PinDIN: + /* fix me */ + return ATOM_ENCODER_MODE_TV; + /*return ATOM_ENCODER_MODE_CV;*/ + break; + } +} + +/* + * DIG Encoder/Transmitter Setup + * + * DCE 3.0/3.1 + * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. + * Supports up to 3 digital outputs + * - 2 DIG encoder blocks. + * DIG1 can drive UNIPHY link A or link B + * DIG2 can drive UNIPHY link B or LVTMA + * + * DCE 3.2 + * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). + * Supports up to 5 digital outputs + * - 2 DIG encoder blocks. + * DIG1/2 can drive UNIPHY0/1/2 link A or link B + * + * DCE 4.0/5.0 + * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). + * Supports up to 6 digital outputs + * - 6 DIG encoder blocks. + * - DIG to PHY mapping is hardcoded + * DIG1 drives UNIPHY0 link A, A+B + * DIG2 drives UNIPHY0 link B + * DIG3 drives UNIPHY1 link A, A+B + * DIG4 drives UNIPHY1 link B + * DIG5 drives UNIPHY2 link A, A+B + * DIG6 drives UNIPHY2 link B + * + * DCE 4.1 + * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). + * Supports up to 6 digital outputs + * - 2 DIG encoder blocks. + * DIG1/2 can drive UNIPHY0/1/2 link A or link B + * + * Routing + * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) + * Examples: + * crtc0 -> dig2 -> LVTMA links A+B -> TMDS/HDMI + * crtc1 -> dig1 -> UNIPHY0 link B -> DP + * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS + * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI + */ + +union dig_encoder_control { + DIG_ENCODER_CONTROL_PS_ALLOCATION v1; + DIG_ENCODER_CONTROL_PARAMETERS_V2 v2; + DIG_ENCODER_CONTROL_PARAMETERS_V3 v3; + DIG_ENCODER_CONTROL_PARAMETERS_V4 v4; +}; + +void +atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + union dig_encoder_control args; + int index = 0; + uint8_t frev, crev; + int dp_clock = 0; + int dp_lane_count = 0; + int hpd_id = RADEON_HPD_NONE; + int bpc = 8; + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + hpd_id = radeon_connector->hpd.hpd; + bpc = connector->display_info.bpc; + } + + /* no dig encoder assigned */ + if (dig->dig_encoder == -1) + return; + + memset(&args, 0, sizeof(args)); + + if (ASIC_IS_DCE4(rdev)) + index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl); + else { + if (dig->dig_encoder) + index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + } + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + switch (crev) { + case 1: + args.v1.ucAction = action; + args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) + args.v3.ucPanelMode = panel_mode; + else + args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) + args.v1.ucLaneNum = dp_lane_count; + else if (radeon_encoder->pixel_clock > 165000) + args.v1.ucLaneNum = 8; + else + args.v1.ucLaneNum = 4; + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; + break; + } + if (dig->linkb) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; + else + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; + break; + case 2: + case 3: + args.v3.ucAction = action; + args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) + args.v3.ucPanelMode = panel_mode; + else + args.v3.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) + args.v3.ucLaneNum = dp_lane_count; + else if (radeon_encoder->pixel_clock > 165000) + args.v3.ucLaneNum = 8; + else + args.v3.ucLaneNum = 4; + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; + args.v3.acConfig.ucDigSel = dig->dig_encoder; + switch (bpc) { + case 0: + args.v3.ucBitPerColor = PANEL_BPC_UNDEFINE; + break; + case 6: + args.v3.ucBitPerColor = PANEL_6BIT_PER_COLOR; + break; + case 8: + default: + args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR; + break; + case 10: + args.v3.ucBitPerColor = PANEL_10BIT_PER_COLOR; + break; + case 12: + args.v3.ucBitPerColor = PANEL_12BIT_PER_COLOR; + break; + case 16: + args.v3.ucBitPerColor = PANEL_16BIT_PER_COLOR; + break; + } + break; + case 4: + args.v4.ucAction = action; + args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) + args.v4.ucPanelMode = panel_mode; + else + args.v4.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) + args.v4.ucLaneNum = dp_lane_count; + else if (radeon_encoder->pixel_clock > 165000) + args.v4.ucLaneNum = 8; + else + args.v4.ucLaneNum = 4; + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) { + if (dp_clock == 270000) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ; + else if (dp_clock == 540000) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; + } + args.v4.acConfig.ucDigSel = dig->dig_encoder; + switch (bpc) { + case 0: + args.v4.ucBitPerColor = PANEL_BPC_UNDEFINE; + break; + case 6: + args.v4.ucBitPerColor = PANEL_6BIT_PER_COLOR; + break; + case 8: + default: + args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR; + break; + case 10: + args.v4.ucBitPerColor = PANEL_10BIT_PER_COLOR; + break; + case 12: + args.v4.ucBitPerColor = PANEL_12BIT_PER_COLOR; + break; + case 16: + args.v4.ucBitPerColor = PANEL_16BIT_PER_COLOR; + break; + } + if (hpd_id == RADEON_HPD_NONE) + args.v4.ucHPD_ID = 0; + else + args.v4.ucHPD_ID = hpd_id + 1; + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +union dig_transmitter_control { + DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4; +}; + +void +atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct drm_connector *connector; + union dig_transmitter_control args; + int index = 0; + uint8_t frev, crev; + bool is_dp = false; + int pll_id = 0; + int dp_clock = 0; + int dp_lane_count = 0; + int connector_object_id = 0; + int igp_lane_info = 0; + int dig_encoder = dig->dig_encoder; + + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + connector = radeon_get_connector_for_encoder_init(encoder); + /* just needed to avoid bailing in the encoder check. the encoder + * isn't used for init + */ + dig_encoder = 0; + } else + connector = radeon_get_connector_for_encoder(encoder); + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + connector_object_id = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + igp_lane_info = dig_connector->igp_lane_info; + } + + if (encoder->crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + pll_id = radeon_crtc->pll_id; + } + + /* no dig encoder assigned */ + if (dig_encoder == -1) + return; + + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder))) + is_dp = true; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); + break; + } + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + switch (crev) { + case 1: + args.v1.ucAction = action; + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + args.v1.usInitInfo = cpu_to_le16(connector_object_id); + } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { + args.v1.asMode.ucLaneSel = lane_num; + args.v1.asMode.ucLaneSet = lane_set; + } else { + if (is_dp) + args.v1.usPixelClock = + cpu_to_le16(dp_clock / 10); + else if (radeon_encoder->pixel_clock > 165000) + args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); + else + args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + } + + args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; + + if (dig_encoder) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; + + if ((rdev->flags & RADEON_IS_IGP) && + (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) { + if (is_dp || (radeon_encoder->pixel_clock <= 165000)) { + if (igp_lane_info & 0x1) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else if (igp_lane_info & 0x2) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; + else if (igp_lane_info & 0x4) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; + else if (igp_lane_info & 0x8) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; + } else { + if (igp_lane_info & 0x3) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; + else if (igp_lane_info & 0xc) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; + } + } + + if (dig->linkb) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; + + if (is_dp) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; + else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; + } + break; + case 2: + args.v2.ucAction = action; + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + args.v2.usInitInfo = cpu_to_le16(connector_object_id); + } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { + args.v2.asMode.ucLaneSel = lane_num; + args.v2.asMode.ucLaneSet = lane_set; + } else { + if (is_dp) + args.v2.usPixelClock = + cpu_to_le16(dp_clock / 10); + else if (radeon_encoder->pixel_clock > 165000) + args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); + else + args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + } + + args.v2.acConfig.ucEncoderSel = dig_encoder; + if (dig->linkb) + args.v2.acConfig.ucLinkSel = 1; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v2.acConfig.ucTransmitterSel = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.v2.acConfig.ucTransmitterSel = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v2.acConfig.ucTransmitterSel = 2; + break; + } + + if (is_dp) { + args.v2.acConfig.fCoherentMode = 1; + args.v2.acConfig.fDPConnector = 1; + } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v2.acConfig.fCoherentMode = 1; + if (radeon_encoder->pixel_clock > 165000) + args.v2.acConfig.fDualLinkConnector = 1; + } + break; + case 3: + args.v3.ucAction = action; + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + args.v3.usInitInfo = cpu_to_le16(connector_object_id); + } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { + args.v3.asMode.ucLaneSel = lane_num; + args.v3.asMode.ucLaneSet = lane_set; + } else { + if (is_dp) + args.v3.usPixelClock = + cpu_to_le16(dp_clock / 10); + else if (radeon_encoder->pixel_clock > 165000) + args.v3.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); + else + args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + } + + if (is_dp) + args.v3.ucLaneNum = dp_lane_count; + else if (radeon_encoder->pixel_clock > 165000) + args.v3.ucLaneNum = 8; + else + args.v3.ucLaneNum = 4; + + if (dig->linkb) + args.v3.acConfig.ucLinkSel = 1; + if (dig_encoder & 1) + args.v3.acConfig.ucEncoderSel = 1; + + /* Select the PLL for the PHY + * DP PHY should be clocked from external src if there is + * one. + */ + /* On DCE4, if there is an external clock, it generates the DP ref clock */ + if (is_dp && rdev->clock.dp_extclk) + args.v3.acConfig.ucRefClkSource = 2; /* external src */ + else + args.v3.acConfig.ucRefClkSource = pll_id; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v3.acConfig.ucTransmitterSel = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.v3.acConfig.ucTransmitterSel = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v3.acConfig.ucTransmitterSel = 2; + break; + } + + if (is_dp) + args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */ + else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v3.acConfig.fCoherentMode = 1; + if (radeon_encoder->pixel_clock > 165000) + args.v3.acConfig.fDualLinkConnector = 1; + } + break; + case 4: + args.v4.ucAction = action; + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + args.v4.usInitInfo = cpu_to_le16(connector_object_id); + } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { + args.v4.asMode.ucLaneSel = lane_num; + args.v4.asMode.ucLaneSet = lane_set; + } else { + if (is_dp) + args.v4.usPixelClock = + cpu_to_le16(dp_clock / 10); + else if (radeon_encoder->pixel_clock > 165000) + args.v4.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); + else + args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + } + + if (is_dp) + args.v4.ucLaneNum = dp_lane_count; + else if (radeon_encoder->pixel_clock > 165000) + args.v4.ucLaneNum = 8; + else + args.v4.ucLaneNum = 4; + + if (dig->linkb) + args.v4.acConfig.ucLinkSel = 1; + if (dig_encoder & 1) + args.v4.acConfig.ucEncoderSel = 1; + + /* Select the PLL for the PHY + * DP PHY should be clocked from external src if there is + * one. + */ + /* On DCE5 DCPLL usually generates the DP ref clock */ + if (is_dp) { + if (rdev->clock.dp_extclk) + args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK; + else + args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL; + } else + args.v4.acConfig.ucRefClkSource = pll_id; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v4.acConfig.ucTransmitterSel = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.v4.acConfig.ucTransmitterSel = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v4.acConfig.ucTransmitterSel = 2; + break; + } + + if (is_dp) + args.v4.acConfig.fCoherentMode = 1; /* DP requires coherent */ + else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v4.acConfig.fCoherentMode = 1; + if (radeon_encoder->pixel_clock > 165000) + args.v4.acConfig.fDualLinkConnector = 1; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +bool +atombios_set_edp_panel_power(struct drm_connector *connector, int action) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_device *dev = radeon_connector->base.dev; + struct radeon_device *rdev = dev->dev_private; + union dig_transmitter_control args; + int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + uint8_t frev, crev; + + if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) + goto done; + + if (!ASIC_IS_DCE4(rdev)) + goto done; + + if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) && + (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) + goto done; + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + goto done; + + memset(&args, 0, sizeof(args)); + + args.v1.ucAction = action; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + /* wait for the panel to power up */ + if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) { + int i; + + for (i = 0; i < 300; i++) { + if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) + return true; + mdelay(1); + } + return false; + } +done: + return true; +} + +union external_encoder_control { + EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; + EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3; +}; + +static void +atombios_external_encoder_setup(struct drm_encoder *encoder, + struct drm_encoder *ext_encoder, + int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); + union external_encoder_control args; + struct drm_connector *connector; + int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); + u8 frev, crev; + int dp_clock = 0; + int dp_lane_count = 0; + int connector_object_id = 0; + u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; + int bpc = 8; + + if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) + connector = radeon_get_connector_for_encoder_init(encoder); + else + connector = radeon_get_connector_for_encoder(encoder); + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + connector_object_id = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + bpc = connector->display_info.bpc; + } + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + /* no params on frev 1 */ + break; + case 2: + switch (crev) { + case 1: + case 2: + args.v1.sDigEncoder.ucAction = action; + args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (ENCODER_MODE_IS_DP(args.v1.sDigEncoder.ucEncoderMode)) { + if (dp_clock == 270000) + args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + args.v1.sDigEncoder.ucLaneNum = dp_lane_count; + } else if (radeon_encoder->pixel_clock > 165000) + args.v1.sDigEncoder.ucLaneNum = 8; + else + args.v1.sDigEncoder.ucLaneNum = 4; + break; + case 3: + args.v3.sExtEncoder.ucAction = action; + if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) + args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id); + else + args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (ENCODER_MODE_IS_DP(args.v3.sExtEncoder.ucEncoderMode)) { + if (dp_clock == 270000) + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; + else if (dp_clock == 540000) + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ; + args.v3.sExtEncoder.ucLaneNum = dp_lane_count; + } else if (radeon_encoder->pixel_clock > 165000) + args.v3.sExtEncoder.ucLaneNum = 8; + else + args.v3.sExtEncoder.ucLaneNum = 4; + switch (ext_enum) { + case GRAPH_OBJECT_ENUM_ID1: + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1; + break; + case GRAPH_OBJECT_ENUM_ID2: + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2; + break; + case GRAPH_OBJECT_ENUM_ID3: + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3; + break; + } + switch (bpc) { + case 0: + args.v3.sExtEncoder.ucBitPerColor = PANEL_BPC_UNDEFINE; + break; + case 6: + args.v3.sExtEncoder.ucBitPerColor = PANEL_6BIT_PER_COLOR; + break; + case 8: + default: + args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR; + break; + case 10: + args.v3.sExtEncoder.ucBitPerColor = PANEL_10BIT_PER_COLOR; + break; + case 12: + args.v3.sExtEncoder.ucBitPerColor = PANEL_12BIT_PER_COLOR; + break; + case 16: + args.v3.sExtEncoder.ucBitPerColor = PANEL_16BIT_PER_COLOR; + break; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +static void +atombios_yuv_setup(struct drm_encoder *encoder, bool enable) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + ENABLE_YUV_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, EnableYUV); + uint32_t temp, reg; + + memset(&args, 0, sizeof(args)); + + if (rdev->family >= CHIP_R600) + reg = R600_BIOS_3_SCRATCH; + else + reg = RADEON_BIOS_3_SCRATCH; + + /* XXX: fix up scratch reg handling */ + temp = RREG32(reg); + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + WREG32(reg, (ATOM_S3_TV1_ACTIVE | + (radeon_crtc->crtc_id << 18))); + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24))); + else + WREG32(reg, 0); + + if (enable) + args.ucEnable = ATOM_ENABLE; + args.ucCRTC = radeon_crtc->crtc_id; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + WREG32(reg, temp); +} + +static void +radeon_atom_encoder_dpms_avivo(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; + int index = 0; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); + break; + default: + return; + } + + switch (mode) { + case DRM_MODE_DPMS_ON: + args.ucAction = ATOM_ENABLE; + /* workaround for DVOOutputControl on some RS690 systems */ + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) { + u32 reg = RREG32(RADEON_BIOS_3_SCRATCH); + WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + WREG32(RADEON_BIOS_3_SCRATCH, reg); + } else + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + args.ucAction = ATOM_LCD_BLON; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + args.ucAction = ATOM_DISABLE; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + args.ucAction = ATOM_LCD_BLOFF; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } + break; + } +} + +static void +radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + struct radeon_connector *radeon_connector = NULL; + struct radeon_connector_atom_dig *radeon_dig_connector = NULL; + + if (connector) { + radeon_connector = to_radeon_connector(connector); + radeon_dig_connector = radeon_connector->con_priv; + } + + switch (mode) { + case DRM_MODE_DPMS_ON: + /* some early dce3.2 boards have a bug in their transmitter control table */ + if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + else + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); + radeon_dig_connector->edp_on = true; + } + if (ASIC_IS_DCE4(rdev)) + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); + radeon_dp_link_train(encoder, connector); + if (ASIC_IS_DCE4(rdev)) + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); + } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { + if (ASIC_IS_DCE4(rdev)) + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); + radeon_dig_connector->edp_on = false; + } + } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); + break; + } +} + +static void +radeon_atom_encoder_dpms_ext(struct drm_encoder *encoder, + struct drm_encoder *ext_encoder, + int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + + switch (mode) { + case DRM_MODE_DPMS_ON: + default: + if (ASIC_IS_DCE41(rdev)) { + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT); + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF); + } else + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + if (ASIC_IS_DCE41(rdev)) { + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING); + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT); + } else + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); + break; + } +} + +static void +radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + + DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", + radeon_encoder->encoder_id, mode, radeon_encoder->devices, + radeon_encoder->active_device); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + radeon_atom_encoder_dpms_avivo(encoder, mode); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + radeon_atom_encoder_dpms_dig(encoder, mode); + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + if (ASIC_IS_DCE5(rdev)) { + switch (mode) { + case DRM_MODE_DPMS_ON: + atombios_dvo_setup(encoder, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_dvo_setup(encoder, ATOM_DISABLE); + break; + } + } else if (ASIC_IS_DCE3(rdev)) + radeon_atom_encoder_dpms_dig(encoder, mode); + else + radeon_atom_encoder_dpms_avivo(encoder, mode); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (ASIC_IS_DCE5(rdev)) { + switch (mode) { + case DRM_MODE_DPMS_ON: + atombios_dac_setup(encoder, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_dac_setup(encoder, ATOM_DISABLE); + break; + } + } else + radeon_atom_encoder_dpms_avivo(encoder, mode); + break; + default: + return; + } + + if (ext_encoder) + radeon_atom_encoder_dpms_ext(encoder, ext_encoder, mode); + + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + +} + +union crtc_source_param { + SELECT_CRTC_SOURCE_PS_ALLOCATION v1; + SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; +}; + +static void +atombios_set_encoder_crtc_source(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + union crtc_source_param args; + int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); + uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + switch (crev) { + case 1: + default: + if (ASIC_IS_AVIVO(rdev)) + args.v1.ucCRTC = radeon_crtc->crtc_id; + else { + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) { + args.v1.ucCRTC = radeon_crtc->crtc_id; + } else { + args.v1.ucCRTC = radeon_crtc->crtc_id << 2; + } + } + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) + args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; + break; + } + break; + case 2: + args.v2.ucCRTC = radeon_crtc->crtc_id; + if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + + if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) + args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; + else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA) + args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT; + else + args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); + } else + args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + dig = radeon_encoder->enc_priv; + switch (dig->dig_encoder) { + case 0: + args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; + break; + case 1: + args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + break; + case 2: + args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; + break; + case 3: + args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; + break; + case 4: + args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; + break; + case 5: + args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; + break; + } + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; + break; + } + break; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + /* update scratch regs with new routing */ + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); +} + +static void +atombios_apply_encoder_quirks(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + + /* Funky macbooks */ + if ((dev->pdev->device == 0x71C5) && + (dev->pdev->subsystem_vendor == 0x106b) && + (dev->pdev->subsystem_device == 0x0080)) { + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { + uint32_t lvtma_bit_depth_control = RREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL); + + lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; + lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; + + WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); + } + } + + /* set scaler clears this on some chips */ + if (ASIC_IS_AVIVO(rdev) && + (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) { + if (ASIC_IS_DCE4(rdev)) { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, + EVERGREEN_INTERLEAVE_EN); + else + WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); + } else { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, + AVIVO_D1MODE_INTERLEAVE_EN); + else + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); + } + } +} + +static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *test_encoder; + struct radeon_encoder_atom_dig *dig; + uint32_t dig_enc_in_use = 0; + + /* DCE4/5 */ + if (ASIC_IS_DCE4(rdev)) { + dig = radeon_encoder->enc_priv; + if (ASIC_IS_DCE41(rdev)) { + /* ontario follows DCE4 */ + if (rdev->family == CHIP_PALM) { + if (dig->linkb) + return 1; + else + return 0; + } else + /* llano follows DCE3.2 */ + return radeon_crtc->crtc_id; + } else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + if (dig->linkb) + return 1; + else + return 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + if (dig->linkb) + return 3; + else + return 2; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (dig->linkb) + return 5; + else + return 4; + break; + } + } + } + + /* on DCE32 and encoder can driver any block so just crtc id */ + if (ASIC_IS_DCE32(rdev)) { + return radeon_crtc->crtc_id; + } + + /* on DCE3 - LVTMA can only be driven by DIGB */ + list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { + struct radeon_encoder *radeon_test_encoder; + + if (encoder == test_encoder) + continue; + + if (!radeon_encoder_is_digital(test_encoder)) + continue; + + radeon_test_encoder = to_radeon_encoder(test_encoder); + dig = radeon_test_encoder->enc_priv; + + if (dig->dig_encoder >= 0) + dig_enc_in_use |= (1 << dig->dig_encoder); + } + + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { + if (dig_enc_in_use & 0x2) + DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); + return 1; + } + if (!(dig_enc_in_use & 1)) + return 0; + return 1; +} + +/* This only needs to be called once at startup */ +void +radeon_atom_encoder_init(struct radeon_device *rdev) +{ + struct drm_device *dev = rdev->ddev; + struct drm_encoder *encoder; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); + break; + default: + break; + } + + if (ext_encoder && ASIC_IS_DCE41(rdev)) + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); + } +} + +static void +radeon_atom_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + + radeon_encoder->pixel_clock = adjusted_mode->clock; + + if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) { + if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) + atombios_yuv_setup(encoder, true); + else + atombios_yuv_setup(encoder, false); + } + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + if (ASIC_IS_DCE4(rdev)) { + /* disable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + /* setup and enable the encoder */ + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); + + /* enable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + } else { + /* disable the encoder and transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); + + /* setup and enable the encoder and transmitter */ + atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + } + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + atombios_dvo_setup(encoder, ATOM_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + atombios_dac_setup(encoder, ATOM_ENABLE); + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) { + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + atombios_tv_setup(encoder, ATOM_ENABLE); + else + atombios_tv_setup(encoder, ATOM_DISABLE); + } + break; + } + + if (ext_encoder) { + if (ASIC_IS_DCE41(rdev)) + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); + else + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); + } + + atombios_apply_encoder_quirks(encoder, adjusted_mode); + + if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { + r600_hdmi_enable(encoder); + r600_hdmi_setmode(encoder, adjusted_mode); + } +} + +static bool +atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | + ATOM_DEVICE_CV_SUPPORT | + ATOM_DEVICE_CRT_SUPPORT)) { + DAC_LOAD_DETECTION_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); + uint8_t frev, crev; + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return false; + + args.sDacload.ucMisc = 0; + + if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || + (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) + args.sDacload.ucDacType = ATOM_DAC_A; + else + args.sDacload.ucDacType = ATOM_DAC_B; + + if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); + else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); + else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); + if (crev >= 3) + args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; + } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); + if (crev >= 3) + args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + return true; + } else + return false; +} + +static enum drm_connector_status +radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + uint32_t bios_0_scratch; + + if (!atombios_dac_load_detect(encoder, connector)) { + DRM_DEBUG_KMS("detect returned false \n"); + return connector_status_unknown; + } + + if (rdev->family >= CHIP_R600) + bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); + else + bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); + + DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); + if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT1_MASK) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT2_MASK) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) + return connector_status_connected; /* CTV */ + else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) + return connector_status_connected; /* STV */ + } + return connector_status_disconnected; +} + +static enum drm_connector_status +radeon_atom_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + u32 bios_0_scratch; + + if (!ASIC_IS_DCE4(rdev)) + return connector_status_unknown; + + if (!ext_encoder) + return connector_status_unknown; + + if ((radeon_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0) + return connector_status_unknown; + + /* load detect on the dp bridge */ + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION); + + bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); + + DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); + if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT1_MASK) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT2_MASK) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) + return connector_status_connected; /* CTV */ + else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) + return connector_status_connected; /* STV */ + } + return connector_status_disconnected; +} + +void +radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder) +{ + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + + if (ext_encoder) + /* ddc_setup on the dp bridge */ + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); + +} + +static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + + if ((radeon_encoder->active_device & + (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || + (radeon_encoder_get_dp_bridge_encoder_id(encoder) != + ENCODER_OBJECT_ID_NONE)) { + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + if (dig) + dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); + } + + radeon_atom_output_lock(encoder, true); + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + /* select the clock/data port if it uses a router */ + if (radeon_connector->router.cd_valid) + radeon_router_select_cd_port(radeon_connector); + + /* turn eDP panel on for mode set */ + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); + } + + /* this is needed for the pll/ss setup to work correctly in some cases */ + atombios_set_encoder_crtc_source(encoder); +} + +static void radeon_atom_encoder_commit(struct drm_encoder *encoder) +{ + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); + radeon_atom_output_lock(encoder, false); +} + +static void radeon_atom_encoder_disable(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig; + + /* check for pre-DCE3 cards with shared encoders; + * can't really use the links individually, so don't disable + * the encoder if it's in use by another connector + */ + if (!ASIC_IS_DCE3(rdev)) { + struct drm_encoder *other_encoder; + struct radeon_encoder *other_radeon_encoder; + + list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { + other_radeon_encoder = to_radeon_encoder(other_encoder); + if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) && + drm_helper_encoder_in_use(other_encoder)) + goto disable_done; + } + } + + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_DISABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + if (ASIC_IS_DCE4(rdev)) + /* disable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + else { + /* disable the encoder and transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); + } + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + atombios_dvo_setup(encoder, ATOM_DISABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + atombios_dac_setup(encoder, ATOM_DISABLE); + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + atombios_tv_setup(encoder, ATOM_DISABLE); + break; + } + +disable_done: + if (radeon_encoder_is_digital(encoder)) { + if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) + r600_hdmi_disable(encoder); + dig = radeon_encoder->enc_priv; + dig->dig_encoder = -1; + } + radeon_encoder->active_device = 0; +} + +/* these are handled by the primary encoders */ +static void radeon_atom_ext_prepare(struct drm_encoder *encoder) +{ + +} + +static void radeon_atom_ext_commit(struct drm_encoder *encoder) +{ + +} + +static void +radeon_atom_ext_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + +} + +static void radeon_atom_ext_disable(struct drm_encoder *encoder) +{ + +} + +static void +radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) +{ + +} + +static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { + .dpms = radeon_atom_ext_dpms, + .mode_fixup = radeon_atom_ext_mode_fixup, + .prepare = radeon_atom_ext_prepare, + .mode_set = radeon_atom_ext_mode_set, + .commit = radeon_atom_ext_commit, + .disable = radeon_atom_ext_disable, + /* no detect for TMDS/LVDS yet */ +}; + +static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { + .dpms = radeon_atom_encoder_dpms, + .mode_fixup = radeon_atom_mode_fixup, + .prepare = radeon_atom_encoder_prepare, + .mode_set = radeon_atom_encoder_mode_set, + .commit = radeon_atom_encoder_commit, + .disable = radeon_atom_encoder_disable, + .detect = radeon_atom_dig_detect, +}; + +static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { + .dpms = radeon_atom_encoder_dpms, + .mode_fixup = radeon_atom_mode_fixup, + .prepare = radeon_atom_encoder_prepare, + .mode_set = radeon_atom_encoder_mode_set, + .commit = radeon_atom_encoder_commit, + .detect = radeon_atom_dac_detect, +}; + +void radeon_enc_destroy(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + kfree(radeon_encoder->enc_priv); + drm_encoder_cleanup(encoder); + kfree(radeon_encoder); +} + +static const struct drm_encoder_funcs radeon_atom_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +struct radeon_encoder_atom_dac * +radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL); + + if (!dac) + return NULL; + + dac->tv_std = radeon_atombios_get_tv_info(rdev); + return dac; +} + +struct radeon_encoder_atom_dig * +radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) +{ + int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; + struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); + + if (!dig) + return NULL; + + /* coherent mode by default */ + dig->coherent_mode = true; + dig->dig_encoder = -1; + + if (encoder_enum == 2) + dig->linkb = true; + else + dig->linkb = false; + + return dig; +} + +void +radeon_add_atom_encoder(struct drm_device *dev, + uint32_t encoder_enum, + uint32_t supported_device, + u16 caps) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + + /* see if we already added it */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->encoder_enum == encoder_enum) { + radeon_encoder->devices |= supported_device; + return; + } + + } + + /* add a new one */ + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) + return; + + encoder = &radeon_encoder->base; + switch (rdev->num_crtc) { + case 1: + encoder->possible_crtcs = 0x1; + break; + case 2: + default: + encoder->possible_crtcs = 0x3; + break; + case 4: + encoder->possible_crtcs = 0xf; + break; + case 6: + encoder->possible_crtcs = 0x3f; + break; + } + + radeon_encoder->enc_priv = NULL; + + radeon_encoder->encoder_enum = encoder_enum; + radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + radeon_encoder->devices = supported_device; + radeon_encoder->rmx_type = RMX_OFF; + radeon_encoder->underscan_type = UNDERSCAN_OFF; + radeon_encoder->is_ext_encoder = false; + radeon_encoder->caps = caps; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + radeon_encoder->rmx_type = RMX_FULL; + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + } else { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + } + drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); + drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC); + radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); + drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + radeon_encoder->rmx_type = RMX_FULL; + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + } else { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + } + drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); + break; + case ENCODER_OBJECT_ID_SI170B: + case ENCODER_OBJECT_ID_CH7303: + case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: + case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: + case ENCODER_OBJECT_ID_TITFP513: + case ENCODER_OBJECT_ID_VT1623: + case ENCODER_OBJECT_ID_HDMI_SI1930: + case ENCODER_OBJECT_ID_TRAVIS: + case ENCODER_OBJECT_ID_NUTMEG: + /* these are handled by the primary encoders */ + radeon_encoder->is_ext_encoder = true; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + else + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); + break; + } +} diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index ed406e8404a3..e4c384b9511c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -353,6 +353,7 @@ void evergreen_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) evergreen_irq_set(rdev); @@ -893,7 +894,7 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) u32 tmp; int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -945,7 +946,6 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) void evergreen_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int r; /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); @@ -965,14 +965,7 @@ void evergreen_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void evergreen_pcie_gart_fini(struct radeon_device *rdev) @@ -3031,6 +3024,10 @@ static int evergreen_startup(struct radeon_device *rdev) } } + r = r600_vram_scratch_init(rdev); + if (r) + return r; + evergreen_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { evergreen_agp_enable(rdev); @@ -3235,6 +3232,7 @@ void evergreen_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); evergreen_pcie_gart_fini(rdev); + r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_agp_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c index dcf11bbc06d9..914e5af84163 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c @@ -94,6 +94,15 @@ cp_set_surface_sync(struct radeon_device *rdev, else cp_coher_size = ((size + 255) >> 8); + if (rdev->family >= CHIP_CAYMAN) { + /* CP_COHER_CNTL2 has to be set manually when submitting a surface_sync + * to the RB directly. For IBs, the CP programs this as part of the + * surface_sync packet. + */ + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(rdev, (0x85e8 - PACKET3_SET_CONFIG_REG_START) >> 2); + radeon_ring_write(rdev, 0); /* CP_COHER_CNTL2 */ + } radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_SYNC, 3)); radeon_ring_write(rdev, sync_type); radeon_ring_write(rdev, cp_coher_size); @@ -174,7 +183,7 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr) static void set_tex_resource(struct radeon_device *rdev, int format, int w, int h, int pitch, - u64 gpu_addr) + u64 gpu_addr, u32 size) { u32 sq_tex_resource_word0, sq_tex_resource_word1; u32 sq_tex_resource_word4, sq_tex_resource_word7; @@ -196,6 +205,9 @@ set_tex_resource(struct radeon_device *rdev, sq_tex_resource_word7 = format | S__SQ_CONSTANT_TYPE(SQ_TEX_VTX_VALID_TEXTURE); + cp_set_surface_sync(rdev, + PACKET3_TC_ACTION_ENA, size, gpu_addr); + radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 8)); radeon_ring_write(rdev, 0); radeon_ring_write(rdev, sq_tex_resource_word0); @@ -613,11 +625,13 @@ int evergreen_blit_init(struct radeon_device *rdev) rdev->r600_blit.primitives.set_default_state = set_default_state; rdev->r600_blit.ring_size_common = 55; /* shaders + def state */ - rdev->r600_blit.ring_size_common += 10; /* fence emit for VB IB */ + rdev->r600_blit.ring_size_common += 16; /* fence emit for VB IB */ rdev->r600_blit.ring_size_common += 5; /* done copy */ - rdev->r600_blit.ring_size_common += 10; /* fence emit for done copy */ + rdev->r600_blit.ring_size_common += 16; /* fence emit for done copy */ rdev->r600_blit.ring_size_per_loop = 74; + if (rdev->family >= CHIP_CAYMAN) + rdev->r600_blit.ring_size_per_loop += 9; /* additional DWs for surface sync */ rdev->r600_blit.max_dim = 16384; diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 556b7bc3418b..0e5799857465 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -24,6 +24,7 @@ #include <linux/firmware.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/module.h> #include "drmP.h" #include "radeon.h" #include "radeon_asic.h" @@ -261,8 +262,11 @@ int ni_mc_load_microcode(struct radeon_device *rdev) WREG32(MC_SEQ_SUP_CNTL, 0x00000001); /* wait for training to complete */ - while (!(RREG32(MC_IO_PAD_CNTL_D0) & MEM_FALL_OUT_CMD)) - udelay(10); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(MC_IO_PAD_CNTL_D0) & MEM_FALL_OUT_CMD) + break; + udelay(1); + } if (running) WREG32(MC_SHARED_BLACKOUT_CNTL, blackout); @@ -932,7 +936,7 @@ int cayman_pcie_gart_enable(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -977,8 +981,6 @@ int cayman_pcie_gart_enable(struct radeon_device *rdev) void cayman_pcie_gart_disable(struct radeon_device *rdev) { - int r; - /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); WREG32(VM_CONTEXT1_CNTL, 0); @@ -994,14 +996,7 @@ void cayman_pcie_gart_disable(struct radeon_device *rdev) WREG32(VM_L2_CNTL2, 0); WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY | L2_CACHE_BIGK_FRAGMENT_SIZE(6)); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void cayman_pcie_gart_fini(struct radeon_device *rdev) @@ -1361,6 +1356,10 @@ static int cayman_startup(struct radeon_device *rdev) return r; } + r = r600_vram_scratch_init(rdev); + if (r) + return r; + evergreen_mc_program(rdev); r = cayman_pcie_gart_enable(rdev); if (r) @@ -1556,6 +1555,7 @@ void cayman_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); cayman_pcie_gart_fini(rdev); + r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_bo_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 8f8b8fa14357..ad158ea49901 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -41,6 +41,7 @@ #include <linux/firmware.h> #include <linux/platform_device.h> +#include <linux/module.h> #include "r100_reg_safe.h" #include "rn50_reg_safe.h" @@ -536,6 +537,7 @@ void r100_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) r100_irq_set(rdev); @@ -576,7 +578,7 @@ int r100_pci_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.ram.ptr) { + if (rdev->gart.ptr) { WARN(1, "R100 PCI GART already initialized\n"); return 0; } @@ -635,10 +637,12 @@ void r100_pci_gart_disable(struct radeon_device *rdev) int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { + u32 *gtt = rdev->gart.ptr; + if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; } - rdev->gart.table.ram.ptr[i] = cpu_to_le32(lower_32_bits(addr)); + gtt[i] = cpu_to_le32(lower_32_bits(addr)); return 0; } diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 33f2b68c680b..400b26df652a 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -74,7 +74,7 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + void __iomem *ptr = rdev->gart.ptr; if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; @@ -93,7 +93,7 @@ int rv370_pcie_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj) { + if (rdev->gart.robj) { WARN(1, "RV370 PCIE GART already initialized\n"); return 0; } @@ -116,7 +116,7 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev) uint32_t tmp; int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -154,7 +154,6 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev) void rv370_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int r; WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, 0); WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, 0); @@ -163,14 +162,7 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev) tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void rv370_pcie_gart_fini(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 12470b090ddf..19afc43ad173 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -29,6 +29,7 @@ #include <linux/seq_file.h> #include <linux/firmware.h> #include <linux/platform_device.h> +#include <linux/module.h> #include "drmP.h" #include "radeon_drm.h" #include "radeon.h" @@ -762,13 +763,14 @@ void r600_hpd_init(struct radeon_device *rdev) struct drm_device *dev = rdev->ddev; struct drm_connector *connector; - if (ASIC_IS_DCE3(rdev)) { - u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa); - if (ASIC_IS_DCE32(rdev)) - tmp |= DC_HPDx_EN; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (ASIC_IS_DCE3(rdev)) { + u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa); + if (ASIC_IS_DCE32(rdev)) + tmp |= DC_HPDx_EN; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); switch (radeon_connector->hpd.hpd) { case RADEON_HPD_1: WREG32(DC_HPD1_CONTROL, tmp); @@ -798,10 +800,7 @@ void r600_hpd_init(struct radeon_device *rdev) default: break; } - } - } else { - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); + } else { switch (radeon_connector->hpd.hpd) { case RADEON_HPD_1: WREG32(DC_HOT_PLUG_DETECT1_CONTROL, DC_HOT_PLUG_DETECTx_EN); @@ -819,6 +818,7 @@ void r600_hpd_init(struct radeon_device *rdev) break; } } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) r600_irq_set(rdev); @@ -896,7 +896,7 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev) /* flush hdp cache so updates hit vram */ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) && !(rdev->flags & RADEON_IS_AGP)) { - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + void __iomem *ptr = (void *)rdev->gart.ptr; u32 tmp; /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read @@ -931,7 +931,7 @@ int r600_pcie_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj) { + if (rdev->gart.robj) { WARN(1, "R600 PCIE GART already initialized\n"); return 0; } @@ -948,7 +948,7 @@ int r600_pcie_gart_enable(struct radeon_device *rdev) u32 tmp; int r, i; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -1003,7 +1003,7 @@ int r600_pcie_gart_enable(struct radeon_device *rdev) void r600_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int i, r; + int i; /* Disable all tables */ for (i = 0; i < 7; i++) @@ -1030,14 +1030,7 @@ void r600_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void r600_pcie_gart_fini(struct radeon_device *rdev) @@ -1137,7 +1130,7 @@ static void r600_mc_program(struct radeon_device *rdev) WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.vram_start >> 12); WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, rdev->mc.vram_end >> 12); } - WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); + WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, rdev->vram_scratch.gpu_addr >> 12); tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); WREG32(MC_VM_FB_LOCATION, tmp); @@ -1276,6 +1269,53 @@ int r600_mc_init(struct radeon_device *rdev) return 0; } +int r600_vram_scratch_init(struct radeon_device *rdev) +{ + int r; + + if (rdev->vram_scratch.robj == NULL) { + r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, + PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, + &rdev->vram_scratch.robj); + if (r) { + return r; + } + } + + r = radeon_bo_reserve(rdev->vram_scratch.robj, false); + if (unlikely(r != 0)) + return r; + r = radeon_bo_pin(rdev->vram_scratch.robj, + RADEON_GEM_DOMAIN_VRAM, &rdev->vram_scratch.gpu_addr); + if (r) { + radeon_bo_unreserve(rdev->vram_scratch.robj); + return r; + } + r = radeon_bo_kmap(rdev->vram_scratch.robj, + (void **)&rdev->vram_scratch.ptr); + if (r) + radeon_bo_unpin(rdev->vram_scratch.robj); + radeon_bo_unreserve(rdev->vram_scratch.robj); + + return r; +} + +void r600_vram_scratch_fini(struct radeon_device *rdev) +{ + int r; + + if (rdev->vram_scratch.robj == NULL) { + return; + } + r = radeon_bo_reserve(rdev->vram_scratch.robj, false); + if (likely(r == 0)) { + radeon_bo_kunmap(rdev->vram_scratch.robj); + radeon_bo_unpin(rdev->vram_scratch.robj); + radeon_bo_unreserve(rdev->vram_scratch.robj); + } + radeon_bo_unref(&rdev->vram_scratch.robj); +} + /* We doesn't check that the GPU really needs a reset we simply do the * reset, it's up to the caller to determine if the GPU needs one. We * might add an helper function to check that. @@ -2331,6 +2371,14 @@ void r600_fence_ring_emit(struct radeon_device *rdev, if (rdev->wb.use_event) { u64 addr = rdev->wb.gpu_addr + R600_WB_EVENT_OFFSET + (u64)(rdev->fence_drv.scratch_reg - rdev->scratch.reg_base); + /* flush read cache over gart */ + radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_SYNC, 3)); + radeon_ring_write(rdev, PACKET3_TC_ACTION_ENA | + PACKET3_VC_ACTION_ENA | + PACKET3_SH_ACTION_ENA); + radeon_ring_write(rdev, 0xFFFFFFFF); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, 10); /* poll interval */ /* EVENT_WRITE_EOP - flush caches, send int */ radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE_EOP, 4)); radeon_ring_write(rdev, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT_TS) | EVENT_INDEX(5)); @@ -2339,6 +2387,14 @@ void r600_fence_ring_emit(struct radeon_device *rdev, radeon_ring_write(rdev, fence->seq); radeon_ring_write(rdev, 0); } else { + /* flush read cache over gart */ + radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_SYNC, 3)); + radeon_ring_write(rdev, PACKET3_TC_ACTION_ENA | + PACKET3_VC_ACTION_ENA | + PACKET3_SH_ACTION_ENA); + radeon_ring_write(rdev, 0xFFFFFFFF); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, 10); /* poll interval */ radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0)); radeon_ring_write(rdev, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT) | EVENT_INDEX(0)); /* wait for 3D idle clean */ @@ -2420,6 +2476,10 @@ int r600_startup(struct radeon_device *rdev) } } + r = r600_vram_scratch_init(rdev); + if (r) + return r; + r600_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { r600_agp_enable(rdev); @@ -2640,6 +2700,7 @@ void r600_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); r600_pcie_gart_fini(rdev); + r600_vram_scratch_fini(rdev); radeon_agp_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index c4cf1308d4a1..e09d2818f949 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -201,7 +201,7 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr) static void set_tex_resource(struct radeon_device *rdev, int format, int w, int h, int pitch, - u64 gpu_addr) + u64 gpu_addr, u32 size) { uint32_t sq_tex_resource_word0, sq_tex_resource_word1, sq_tex_resource_word4; @@ -222,6 +222,9 @@ set_tex_resource(struct radeon_device *rdev, S_038010_DST_SEL_Z(SQ_SEL_Z) | S_038010_DST_SEL_W(SQ_SEL_W); + cp_set_surface_sync(rdev, + PACKET3_TC_ACTION_ENA, size, gpu_addr); + radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 7)); radeon_ring_write(rdev, 0); radeon_ring_write(rdev, sq_tex_resource_word0); @@ -500,9 +503,9 @@ int r600_blit_init(struct radeon_device *rdev) rdev->r600_blit.primitives.set_default_state = set_default_state; rdev->r600_blit.ring_size_common = 40; /* shaders + def state */ - rdev->r600_blit.ring_size_common += 10; /* fence emit for VB IB */ + rdev->r600_blit.ring_size_common += 16; /* fence emit for VB IB */ rdev->r600_blit.ring_size_common += 5; /* done copy */ - rdev->r600_blit.ring_size_common += 10; /* fence emit for done copy */ + rdev->r600_blit.ring_size_common += 16; /* fence emit for done copy */ rdev->r600_blit.ring_size_per_loop = 76; /* set_render_target emits 2 extra dwords on rv6xx */ @@ -760,10 +763,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev, vb[11] = i2f(h); rdev->r600_blit.primitives.set_tex_resource(rdev, FMT_8_8_8_8, - w, h, w, src_gpu_addr); - rdev->r600_blit.primitives.cp_set_surface_sync(rdev, - PACKET3_TC_ACTION_ENA, - size_in_bytes, src_gpu_addr); + w, h, w, src_gpu_addr, size_in_bytes); rdev->r600_blit.primitives.set_render_target(rdev, COLOR_8_8_8_8, w, h, dst_gpu_addr); rdev->r600_blit.primitives.set_scissors(rdev, 0, 0, w, h); diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 45fd592f9606..c9db4931913f 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -26,6 +26,8 @@ * Alex Deucher <alexander.deucher@amd.com> */ +#include <linux/module.h> + #include "drmP.h" #include "drm.h" #include "radeon_drm.h" diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e3170c794c1d..b316b301152f 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -93,6 +93,7 @@ extern int radeon_audio; extern int radeon_disp_priority; extern int radeon_hw_i2c; extern int radeon_pcie_gen2; +extern int radeon_msi; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting @@ -306,30 +307,17 @@ int radeon_mode_dumb_destroy(struct drm_file *file_priv, */ struct radeon_mc; -struct radeon_gart_table_ram { - volatile uint32_t *ptr; -}; - -struct radeon_gart_table_vram { - struct radeon_bo *robj; - volatile uint32_t *ptr; -}; - -union radeon_gart_table { - struct radeon_gart_table_ram ram; - struct radeon_gart_table_vram vram; -}; - #define RADEON_GPU_PAGE_SIZE 4096 #define RADEON_GPU_PAGE_MASK (RADEON_GPU_PAGE_SIZE - 1) #define RADEON_GPU_PAGE_SHIFT 12 struct radeon_gart { dma_addr_t table_addr; + struct radeon_bo *robj; + void *ptr; unsigned num_gpu_pages; unsigned num_cpu_pages; unsigned table_size; - union radeon_gart_table table; struct page **pages; dma_addr_t *pages_addr; bool *ttm_alloced; @@ -340,6 +328,8 @@ int radeon_gart_table_ram_alloc(struct radeon_device *rdev); void radeon_gart_table_ram_free(struct radeon_device *rdev); int radeon_gart_table_vram_alloc(struct radeon_device *rdev); void radeon_gart_table_vram_free(struct radeon_device *rdev); +int radeon_gart_table_vram_pin(struct radeon_device *rdev); +void radeon_gart_table_vram_unpin(struct radeon_device *rdev); int radeon_gart_init(struct radeon_device *rdev); void radeon_gart_fini(struct radeon_device *rdev); void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, @@ -347,6 +337,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, int pages, struct page **pagelist, dma_addr_t *dma_addr); +void radeon_gart_restore(struct radeon_device *rdev); /* @@ -437,25 +428,26 @@ union radeon_irq_stat_regs { struct evergreen_irq_stat_regs evergreen; }; +#define RADEON_MAX_HPD_PINS 6 +#define RADEON_MAX_CRTCS 6 +#define RADEON_MAX_HDMI_BLOCKS 2 + struct radeon_irq { bool installed; bool sw_int; - /* FIXME: use a define max crtc rather than hardcode it */ - bool crtc_vblank_int[6]; - bool pflip[6]; + bool crtc_vblank_int[RADEON_MAX_CRTCS]; + bool pflip[RADEON_MAX_CRTCS]; wait_queue_head_t vblank_queue; - /* FIXME: use defines for max hpd/dacs */ - bool hpd[6]; + bool hpd[RADEON_MAX_HPD_PINS]; bool gui_idle; bool gui_idle_acked; wait_queue_head_t idle_queue; - /* FIXME: use defines for max HDMI blocks */ - bool hdmi[2]; + bool hdmi[RADEON_MAX_HDMI_BLOCKS]; spinlock_t sw_lock; int sw_refcount; union radeon_irq_stat_regs stat_regs; - spinlock_t pflip_lock[6]; - int pflip_refcount[6]; + spinlock_t pflip_lock[RADEON_MAX_CRTCS]; + int pflip_refcount[RADEON_MAX_CRTCS]; }; int radeon_irq_kms_init(struct radeon_device *rdev); @@ -533,7 +525,7 @@ struct r600_blit_cp_primitives { void (*set_vtx_resource)(struct radeon_device *rdev, u64 gpu_addr); void (*set_tex_resource)(struct radeon_device *rdev, int format, int w, int h, int pitch, - u64 gpu_addr); + u64 gpu_addr, u32 size); void (*set_scissors)(struct radeon_device *rdev, int x1, int y1, int x2, int y2); void (*draw_auto)(struct radeon_device *rdev); @@ -1143,10 +1135,11 @@ int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data, int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); -/* VRAM scratch page for HDP bug */ -struct r700_vram_scratch { +/* VRAM scratch page for HDP bug, default vram page */ +struct r600_vram_scratch { struct radeon_bo *robj; volatile uint32_t *ptr; + u64 gpu_addr; }; /* @@ -1218,7 +1211,7 @@ struct radeon_device { const struct firmware *rlc_fw; /* r6/700 RLC firmware */ const struct firmware *mc_fw; /* NI MC firmware */ struct r600_blit r600_blit; - struct r700_vram_scratch vram_scratch; + struct r600_vram_scratch vram_scratch; int msi_enabled; /* msi enabled */ struct r600_ih ih; /* r6/700 interrupt ring */ struct work_struct hotplug_work; @@ -1442,8 +1435,6 @@ void radeon_ring_write(struct radeon_device *rdev, uint32_t v); /* AGP */ extern int radeon_gpu_reset(struct radeon_device *rdev); extern void radeon_agp_disable(struct radeon_device *rdev); -extern int radeon_gart_table_vram_pin(struct radeon_device *rdev); -extern void radeon_gart_restore(struct radeon_device *rdev); extern int radeon_modeset_init(struct radeon_device *rdev); extern void radeon_modeset_fini(struct radeon_device *rdev); extern bool radeon_card_posted(struct radeon_device *rdev); @@ -1467,6 +1458,12 @@ extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state); extern void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size); /* + * R600 vram scratch functions + */ +int r600_vram_scratch_init(struct radeon_device *rdev); +void r600_vram_scratch_fini(struct radeon_device *rdev); + +/* * r600 functions used by radeon_encoder.c */ extern void r600_hdmi_enable(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index dec6cbe6a0a6..e7cb3ab09243 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -44,8 +44,6 @@ extern void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, struct drm_connector *drm_connector); -bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector); - void radeon_connector_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -432,55 +430,6 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr return 0; } -/* - * Some integrated ATI Radeon chipset implementations (e. g. - * Asus M2A-VM HDMI) may indicate the availability of a DDC, - * even when there's no monitor connected. For these connectors - * following DDC probe extension will be applied: check also for the - * availability of EDID with at least a correct EDID header. Only then, - * DDC is assumed to be available. This prevents drm_get_edid() and - * drm_edid_block_valid() from periodically dumping data and kernel - * errors into the logs and onto the terminal. - */ -static bool radeon_connector_needs_extended_probe(struct radeon_device *dev, - uint32_t supported_device, - int connector_type) -{ - /* Asus M2A-VM HDMI board sends data to i2c bus even, - * if HDMI add-on card is not plugged in or HDMI is disabled in - * BIOS. Valid DDC can only be assumed, if also a valid EDID header - * can be retrieved via i2c bus during DDC probe */ - if ((dev->pdev->device == 0x791e) && - (dev->pdev->subsystem_vendor == 0x1043) && - (dev->pdev->subsystem_device == 0x826d)) { - if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) && - (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) - return true; - } - /* ECS A740GM-M with ATI RADEON 2100 sends data to i2c bus - * for a DVI connector that is not implemented */ - if ((dev->pdev->device == 0x796e) && - (dev->pdev->subsystem_vendor == 0x1019) && - (dev->pdev->subsystem_device == 0x2615)) { - if ((connector_type == DRM_MODE_CONNECTOR_DVID) && - (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) - return true; - } - /* TOSHIBA Satellite L300D with ATI Mobility Radeon x1100 - * (RS690M) sends data to i2c bus for a HDMI connector that - * is not implemented */ - if ((dev->pdev->device == 0x791f) && - (dev->pdev->subsystem_vendor == 0x1179) && - (dev->pdev->subsystem_device == 0xff68)) { - if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) && - (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) - return true; - } - - /* Default: no EDID header probe required for DDC probing */ - return false; -} - static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, struct drm_connector *connector) { @@ -721,8 +670,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) ret = connector_status_disconnected; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe); + dret = radeon_ddc_probe(radeon_connector); if (dret) { radeon_connector->detected_by_load = false; if (radeon_connector->edid) { @@ -764,7 +712,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) if (radeon_connector->dac_load_detect && encoder) { encoder_funcs = encoder->helper_private; ret = encoder_funcs->detect(encoder, connector); - if (ret == connector_status_connected) + if (ret != connector_status_disconnected) radeon_connector->detected_by_load = true; } } @@ -904,8 +852,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) bool dret = false; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe); + dret = radeon_ddc_probe(radeon_connector); if (dret) { radeon_connector->detected_by_load = false; if (radeon_connector->edid) { @@ -1005,8 +952,9 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) ret = encoder_funcs->detect(encoder, connector); if (ret == connector_status_connected) { radeon_connector->use_digital = false; - radeon_connector->detected_by_load = true; } + if (ret != connector_status_disconnected) + radeon_connector->detected_by_load = true; } break; } @@ -1203,7 +1151,8 @@ static int radeon_dp_get_modes(struct drm_connector *connector) } } else { /* need to setup ddc on the bridge */ - if (radeon_connector_encoder_is_dp_bridge(connector)) { + if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != + ENCODER_OBJECT_ID_NONE) { if (encoder) radeon_atom_ext_encoder_setup_ddc(encoder); } @@ -1213,13 +1162,12 @@ static int radeon_dp_get_modes(struct drm_connector *connector) return ret; } -bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector) +u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector) { struct drm_mode_object *obj; struct drm_encoder *encoder; struct radeon_encoder *radeon_encoder; int i; - bool found = false; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] == 0) @@ -1235,14 +1183,13 @@ bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector) switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_TRAVIS: case ENCODER_OBJECT_ID_NUTMEG: - found = true; - break; + return radeon_encoder->encoder_id; default: break; } } - return found; + return ENCODER_OBJECT_ID_NONE; } bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) @@ -1319,7 +1266,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (!radeon_dig_connector->edp_on) atombios_set_edp_panel_power(connector, ATOM_TRANSMITTER_ACTION_POWER_OFF); - } else if (radeon_connector_encoder_is_dp_bridge(connector)) { + } else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != + ENCODER_OBJECT_ID_NONE) { /* DP bridges are always DP */ radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; /* get the DPCD from the bridge */ @@ -1328,8 +1276,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (encoder) { /* setup ddc on the bridge */ radeon_atom_ext_encoder_setup_ddc(encoder); - if (radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe)) /* try DDC */ + if (radeon_ddc_probe(radeon_connector)) /* try DDC */ ret = connector_status_connected; else if (radeon_connector->dac_load_detect) { /* try load detection */ struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; @@ -1347,8 +1294,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; } else { - if (radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe)) + if (radeon_ddc_probe(radeon_connector)) ret = connector_status_connected; } } @@ -1493,9 +1439,7 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_connector->shared_ddc = shared_ddc; radeon_connector->connector_object_id = connector_object_id; radeon_connector->hpd = *hpd; - radeon_connector->requires_extended_probe = - radeon_connector_needs_extended_probe(rdev, supported_device, - connector_type); + radeon_connector->router = *router; if (router->ddc_valid || router->cd_valid) { radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); @@ -1842,9 +1786,7 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_connector->devices = supported_device; radeon_connector->connector_object_id = connector_object_id; radeon_connector->hpd = *hpd; - radeon_connector->requires_extended_probe = - radeon_connector_needs_extended_probe(rdev, supported_device, - connector_type); + switch (connector_type) { case DRM_MODE_CONNECTOR_VGA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 045ec59478f9..72ae8266b8e9 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -29,6 +29,8 @@ * Gareth Hughes <gareth@valinux.com> */ +#include <linux/module.h> + #include "drmP.h" #include "drm.h" #include "drm_sarea.h" diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 6adb3e58affd..a22d6e6a49a2 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -33,8 +33,6 @@ #include "drm_crtc_helper.h" #include "drm_edid.h" -static int radeon_ddc_dump(struct drm_connector *connector); - static void avivo_crtc_load_lut(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -669,7 +667,6 @@ static void radeon_print_display_setup(struct drm_device *dev) static bool radeon_setup_enc_conn(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; - struct drm_connector *drm_connector; bool ret = false; if (rdev->bios) { @@ -689,8 +686,6 @@ static bool radeon_setup_enc_conn(struct drm_device *dev) if (ret) { radeon_setup_encoder_clones(dev); radeon_print_display_setup(dev); - list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) - radeon_ddc_dump(drm_connector); } return ret; @@ -708,7 +703,8 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) || - radeon_connector_encoder_is_dp_bridge(&radeon_connector->base)) { + (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != + ENCODER_OBJECT_ID_NONE)) { struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || @@ -743,34 +739,6 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) return 0; } -static int radeon_ddc_dump(struct drm_connector *connector) -{ - struct edid *edid; - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - int ret = 0; - - /* on hw with routers, select right port */ - if (radeon_connector->router.ddc_valid) - radeon_router_select_ddc_port(radeon_connector); - - if (!radeon_connector->ddc_bus) - return -1; - edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); - /* Log EDID retrieval status here. In particular with regard to - * connectors with requires_extended_probe flag set, that will prevent - * function radeon_dvi_detect() to fetch EDID on this connector, - * as long as there is no valid EDID header found */ - if (edid) { - DRM_INFO("Radeon display connector %s: Found valid EDID", - drm_get_connector_name(connector)); - kfree(edid); - } else { - DRM_INFO("Radeon display connector %s: No monitor connected or invalid EDID", - drm_get_connector_name(connector)); - } - return ret; -} - /* avivo */ static void avivo_get_fb_div(struct radeon_pll *pll, u32 target_clock, diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index e71d2ed7fa11..a0b35e909489 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -36,6 +36,7 @@ #include "drm_pciids.h" #include <linux/console.h> +#include <linux/module.h> /* @@ -118,6 +119,7 @@ int radeon_audio = 0; int radeon_disp_priority = 0; int radeon_hw_i2c = 0; int radeon_pcie_gen2 = 0; +int radeon_msi = -1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -164,6 +166,9 @@ module_param_named(hw_i2c, radeon_hw_i2c, int, 0444); MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (1 = enable)"); module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444); +MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(msi, radeon_msi, int, 0444); + static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index eb3f6dc6df83..06e413e6a920 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -29,12 +29,6 @@ #include "radeon.h" #include "atom.h" -extern int atom_debug; - -/* evil but including atombios.h is much worse */ -bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, - struct drm_display_mode *mode); - static uint32_t radeon_encoder_clones(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; @@ -156,27 +150,6 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8 return ret; } -static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - return true; - default: - return false; - } -} - void radeon_link_encoder_connector(struct drm_device *dev) { @@ -229,23 +202,7 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder) return NULL; } -static struct drm_connector * -radeon_get_connector_for_encoder_init(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_connector *connector; - struct radeon_connector *radeon_connector; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - radeon_connector = to_radeon_connector(connector); - if (radeon_encoder->devices & radeon_connector->devices) - return connector; - } - return NULL; -} - -struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder) +struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -266,9 +223,9 @@ struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder return NULL; } -bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder) +u16 radeon_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder) { - struct drm_encoder *other_encoder = radeon_atom_get_external_encoder(encoder); + struct drm_encoder *other_encoder = radeon_get_external_encoder(encoder); if (other_encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(other_encoder); @@ -332,2105 +289,3 @@ void radeon_panel_mode_fixup(struct drm_encoder *encoder, } -static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - - /* set the active encoder to connector routing */ - radeon_encoder_set_active_device(encoder); - drm_mode_set_crtcinfo(adjusted_mode, 0); - - /* hw bug */ - if ((mode->flags & DRM_MODE_FLAG_INTERLACE) - && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) - adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; - - /* get the native mode for LVDS */ - if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) - radeon_panel_mode_fixup(encoder, adjusted_mode); - - /* get the native mode for TV */ - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { - struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; - if (tv_dac) { - if (tv_dac->tv_std == TV_STD_NTSC || - tv_dac->tv_std == TV_STD_NTSC_J || - tv_dac->tv_std == TV_STD_PAL_M) - radeon_atom_get_tv_timings(rdev, 0, adjusted_mode); - else - radeon_atom_get_tv_timings(rdev, 1, adjusted_mode); - } - } - - if (ASIC_IS_DCE3(rdev) && - ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || - radeon_encoder_is_dp_bridge(encoder))) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - radeon_dp_set_link_config(connector, mode); - } - - return true; -} - -static void -atombios_dac_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - DAC_ENCODER_CONTROL_PS_ALLOCATION args; - int index = 0; - struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; - - memset(&args, 0, sizeof(args)); - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); - break; - } - - args.ucAction = action; - - if (radeon_encoder->active_device & (ATOM_DEVICE_CRT_SUPPORT)) - args.ucDacStandard = ATOM_DAC1_PS2; - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.ucDacStandard = ATOM_DAC1_CV; - else { - switch (dac_info->tv_std) { - case TV_STD_PAL: - case TV_STD_PAL_M: - case TV_STD_SCART_PAL: - case TV_STD_SECAM: - case TV_STD_PAL_CN: - args.ucDacStandard = ATOM_DAC1_PAL; - break; - case TV_STD_NTSC: - case TV_STD_NTSC_J: - case TV_STD_PAL_60: - default: - args.ucDacStandard = ATOM_DAC1_NTSC; - break; - } - } - args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -} - -static void -atombios_tv_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - TV_ENCODER_CONTROL_PS_ALLOCATION args; - int index = 0; - struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; - - memset(&args, 0, sizeof(args)); - - index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); - - args.sTVEncoder.ucAction = action; - - if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.sTVEncoder.ucTvStandard = ATOM_TV_CV; - else { - switch (dac_info->tv_std) { - case TV_STD_NTSC: - args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; - break; - case TV_STD_PAL: - args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; - break; - case TV_STD_PAL_M: - args.sTVEncoder.ucTvStandard = ATOM_TV_PALM; - break; - case TV_STD_PAL_60: - args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; - break; - case TV_STD_NTSC_J: - args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; - break; - case TV_STD_SCART_PAL: - args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ - break; - case TV_STD_SECAM: - args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; - break; - case TV_STD_PAL_CN: - args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; - break; - default: - args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; - break; - } - } - - args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -} - -union dvo_encoder_control { - ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; - DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; - DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; -}; - -void -atombios_dvo_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - union dvo_encoder_control args; - int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); - - memset(&args, 0, sizeof(args)); - - if (ASIC_IS_DCE3(rdev)) { - /* DCE3+ */ - args.dvo_v3.ucAction = action; - args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - args.dvo_v3.ucDVOConfig = 0; /* XXX */ - } else if (ASIC_IS_DCE2(rdev)) { - /* DCE2 (pre-DCE3 R6xx, RS600/690/740 */ - args.dvo.sDVOEncoder.ucAction = action; - args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - /* DFP1, CRT1, TV1 depending on the type of port */ - args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX; - - if (radeon_encoder->pixel_clock > 165000) - args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL; - } else { - /* R4xx, R5xx */ - args.ext_tmds.sXTmdsEncoder.ucEnable = action; - - if (radeon_encoder->pixel_clock > 165000) - args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL; - - /*if (pScrn->rgbBits == 8)*/ - args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB; - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); -} - -union lvds_encoder_control { - LVDS_ENCODER_CONTROL_PS_ALLOCATION v1; - LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2; -}; - -void -atombios_digital_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - union lvds_encoder_control args; - int index = 0; - int hdmi_detected = 0; - uint8_t frev, crev; - - if (!dig) - return; - - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) - hdmi_detected = 1; - - memset(&args, 0, sizeof(args)); - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); - else - index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); - break; - } - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return; - - switch (frev) { - case 1: - case 2: - switch (crev) { - case 1: - args.v1.ucMisc = 0; - args.v1.ucAction = action; - if (hdmi_detected) - args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; - args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) - args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; - if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) - args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; - } else { - if (dig->linkb) - args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; - if (radeon_encoder->pixel_clock > 165000) - args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; - /*if (pScrn->rgbBits == 8) */ - args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; - } - break; - case 2: - case 3: - args.v2.ucMisc = 0; - args.v2.ucAction = action; - if (crev == 3) { - if (dig->coherent_mode) - args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; - } - if (hdmi_detected) - args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; - args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - args.v2.ucTruncate = 0; - args.v2.ucSpatial = 0; - args.v2.ucTemporal = 0; - args.v2.ucFRC = 0; - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) - args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; - if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) { - args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; - if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) - args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; - } - if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) { - args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; - if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) - args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; - if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2) - args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; - } - } else { - if (dig->linkb) - args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; - if (radeon_encoder->pixel_clock > 165000) - args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; - } - break; - default: - DRM_ERROR("Unknown table version %d, %d\n", frev, crev); - break; - } - break; - default: - DRM_ERROR("Unknown table version %d, %d\n", frev, crev); - break; - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); -} - -int -atombios_get_encoder_mode(struct drm_encoder *encoder) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector; - struct radeon_connector_atom_dig *dig_connector; - - /* dp bridges are always DP */ - if (radeon_encoder_is_dp_bridge(encoder)) - return ATOM_ENCODER_MODE_DP; - - /* DVO is always DVO */ - if (radeon_encoder->encoder_id == ATOM_ENCODER_MODE_DVO) - return ATOM_ENCODER_MODE_DVO; - - connector = radeon_get_connector_for_encoder(encoder); - /* if we don't have an active device yet, just use one of - * the connectors tied to the encoder. - */ - if (!connector) - connector = radeon_get_connector_for_encoder_init(encoder); - radeon_connector = to_radeon_connector(connector); - - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_DVII: - case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ - if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { - /* fix me */ - if (ASIC_IS_DCE4(rdev)) - return ATOM_ENCODER_MODE_DVI; - else - return ATOM_ENCODER_MODE_HDMI; - } else if (radeon_connector->use_digital) - return ATOM_ENCODER_MODE_DVI; - else - return ATOM_ENCODER_MODE_CRT; - break; - case DRM_MODE_CONNECTOR_DVID: - case DRM_MODE_CONNECTOR_HDMIA: - default: - if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { - /* fix me */ - if (ASIC_IS_DCE4(rdev)) - return ATOM_ENCODER_MODE_DVI; - else - return ATOM_ENCODER_MODE_HDMI; - } else - return ATOM_ENCODER_MODE_DVI; - break; - case DRM_MODE_CONNECTOR_LVDS: - return ATOM_ENCODER_MODE_LVDS; - break; - case DRM_MODE_CONNECTOR_DisplayPort: - dig_connector = radeon_connector->con_priv; - if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || - (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) - return ATOM_ENCODER_MODE_DP; - else if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { - /* fix me */ - if (ASIC_IS_DCE4(rdev)) - return ATOM_ENCODER_MODE_DVI; - else - return ATOM_ENCODER_MODE_HDMI; - } else - return ATOM_ENCODER_MODE_DVI; - break; - case DRM_MODE_CONNECTOR_eDP: - return ATOM_ENCODER_MODE_DP; - case DRM_MODE_CONNECTOR_DVIA: - case DRM_MODE_CONNECTOR_VGA: - return ATOM_ENCODER_MODE_CRT; - break; - case DRM_MODE_CONNECTOR_Composite: - case DRM_MODE_CONNECTOR_SVIDEO: - case DRM_MODE_CONNECTOR_9PinDIN: - /* fix me */ - return ATOM_ENCODER_MODE_TV; - /*return ATOM_ENCODER_MODE_CV;*/ - break; - } -} - -/* - * DIG Encoder/Transmitter Setup - * - * DCE 3.0/3.1 - * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. - * Supports up to 3 digital outputs - * - 2 DIG encoder blocks. - * DIG1 can drive UNIPHY link A or link B - * DIG2 can drive UNIPHY link B or LVTMA - * - * DCE 3.2 - * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). - * Supports up to 5 digital outputs - * - 2 DIG encoder blocks. - * DIG1/2 can drive UNIPHY0/1/2 link A or link B - * - * DCE 4.0/5.0 - * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). - * Supports up to 6 digital outputs - * - 6 DIG encoder blocks. - * - DIG to PHY mapping is hardcoded - * DIG1 drives UNIPHY0 link A, A+B - * DIG2 drives UNIPHY0 link B - * DIG3 drives UNIPHY1 link A, A+B - * DIG4 drives UNIPHY1 link B - * DIG5 drives UNIPHY2 link A, A+B - * DIG6 drives UNIPHY2 link B - * - * DCE 4.1 - * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). - * Supports up to 6 digital outputs - * - 2 DIG encoder blocks. - * DIG1/2 can drive UNIPHY0/1/2 link A or link B - * - * Routing - * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) - * Examples: - * crtc0 -> dig2 -> LVTMA links A+B -> TMDS/HDMI - * crtc1 -> dig1 -> UNIPHY0 link B -> DP - * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS - * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI - */ - -union dig_encoder_control { - DIG_ENCODER_CONTROL_PS_ALLOCATION v1; - DIG_ENCODER_CONTROL_PARAMETERS_V2 v2; - DIG_ENCODER_CONTROL_PARAMETERS_V3 v3; - DIG_ENCODER_CONTROL_PARAMETERS_V4 v4; -}; - -void -atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - union dig_encoder_control args; - int index = 0; - uint8_t frev, crev; - int dp_clock = 0; - int dp_lane_count = 0; - int hpd_id = RADEON_HPD_NONE; - int bpc = 8; - - if (connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *dig_connector = - radeon_connector->con_priv; - - dp_clock = dig_connector->dp_clock; - dp_lane_count = dig_connector->dp_lane_count; - hpd_id = radeon_connector->hpd.hpd; - bpc = connector->display_info.bpc; - } - - /* no dig encoder assigned */ - if (dig->dig_encoder == -1) - return; - - memset(&args, 0, sizeof(args)); - - if (ASIC_IS_DCE4(rdev)) - index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl); - else { - if (dig->dig_encoder) - index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); - else - index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); - } - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return; - - args.v1.ucAction = action; - args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) - args.v3.ucPanelMode = panel_mode; - else - args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder); - - if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) || - (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST)) - args.v1.ucLaneNum = dp_lane_count; - else if (radeon_encoder->pixel_clock > 165000) - args.v1.ucLaneNum = 8; - else - args.v1.ucLaneNum = 4; - - if (ASIC_IS_DCE5(rdev)) { - if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) || - (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST)) { - if (dp_clock == 270000) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ; - else if (dp_clock == 540000) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; - } - args.v4.acConfig.ucDigSel = dig->dig_encoder; - switch (bpc) { - case 0: - args.v4.ucBitPerColor = PANEL_BPC_UNDEFINE; - break; - case 6: - args.v4.ucBitPerColor = PANEL_6BIT_PER_COLOR; - break; - case 8: - default: - args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR; - break; - case 10: - args.v4.ucBitPerColor = PANEL_10BIT_PER_COLOR; - break; - case 12: - args.v4.ucBitPerColor = PANEL_12BIT_PER_COLOR; - break; - case 16: - args.v4.ucBitPerColor = PANEL_16BIT_PER_COLOR; - break; - } - if (hpd_id == RADEON_HPD_NONE) - args.v4.ucHPD_ID = 0; - else - args.v4.ucHPD_ID = hpd_id + 1; - } else if (ASIC_IS_DCE4(rdev)) { - if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000)) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; - args.v3.acConfig.ucDigSel = dig->dig_encoder; - switch (bpc) { - case 0: - args.v3.ucBitPerColor = PANEL_BPC_UNDEFINE; - break; - case 6: - args.v3.ucBitPerColor = PANEL_6BIT_PER_COLOR; - break; - case 8: - default: - args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR; - break; - case 10: - args.v3.ucBitPerColor = PANEL_10BIT_PER_COLOR; - break; - case 12: - args.v3.ucBitPerColor = PANEL_12BIT_PER_COLOR; - break; - case 16: - args.v3.ucBitPerColor = PANEL_16BIT_PER_COLOR; - break; - } - } else { - if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000)) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; - break; - } - if (dig->linkb) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; - else - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -} - -union dig_transmitter_control { - DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; - DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; - DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; - DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4; -}; - -void -atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct drm_connector *connector; - union dig_transmitter_control args; - int index = 0; - uint8_t frev, crev; - bool is_dp = false; - int pll_id = 0; - int dp_clock = 0; - int dp_lane_count = 0; - int connector_object_id = 0; - int igp_lane_info = 0; - int dig_encoder = dig->dig_encoder; - - if (action == ATOM_TRANSMITTER_ACTION_INIT) { - connector = radeon_get_connector_for_encoder_init(encoder); - /* just needed to avoid bailing in the encoder check. the encoder - * isn't used for init - */ - dig_encoder = 0; - } else - connector = radeon_get_connector_for_encoder(encoder); - - if (connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *dig_connector = - radeon_connector->con_priv; - - dp_clock = dig_connector->dp_clock; - dp_lane_count = dig_connector->dp_lane_count; - connector_object_id = - (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - igp_lane_info = dig_connector->igp_lane_info; - } - - /* no dig encoder assigned */ - if (dig_encoder == -1) - return; - - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) - is_dp = true; - - memset(&args, 0, sizeof(args)); - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); - break; - } - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return; - - args.v1.ucAction = action; - if (action == ATOM_TRANSMITTER_ACTION_INIT) { - args.v1.usInitInfo = cpu_to_le16(connector_object_id); - } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { - args.v1.asMode.ucLaneSel = lane_num; - args.v1.asMode.ucLaneSet = lane_set; - } else { - if (is_dp) - args.v1.usPixelClock = - cpu_to_le16(dp_clock / 10); - else if (radeon_encoder->pixel_clock > 165000) - args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); - else - args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - } - if (ASIC_IS_DCE4(rdev)) { - if (is_dp) - args.v3.ucLaneNum = dp_lane_count; - else if (radeon_encoder->pixel_clock > 165000) - args.v3.ucLaneNum = 8; - else - args.v3.ucLaneNum = 4; - - if (dig->linkb) - args.v3.acConfig.ucLinkSel = 1; - if (dig_encoder & 1) - args.v3.acConfig.ucEncoderSel = 1; - - /* Select the PLL for the PHY - * DP PHY should be clocked from external src if there is - * one. - */ - if (encoder->crtc) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - pll_id = radeon_crtc->pll_id; - } - - if (ASIC_IS_DCE5(rdev)) { - /* On DCE5 DCPLL usually generates the DP ref clock */ - if (is_dp) { - if (rdev->clock.dp_extclk) - args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK; - else - args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL; - } else - args.v4.acConfig.ucRefClkSource = pll_id; - } else { - /* On DCE4, if there is an external clock, it generates the DP ref clock */ - if (is_dp && rdev->clock.dp_extclk) - args.v3.acConfig.ucRefClkSource = 2; /* external src */ - else - args.v3.acConfig.ucRefClkSource = pll_id; - } - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - args.v3.acConfig.ucTransmitterSel = 0; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - args.v3.acConfig.ucTransmitterSel = 1; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - args.v3.acConfig.ucTransmitterSel = 2; - break; - } - - if (is_dp) - args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */ - else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { - if (dig->coherent_mode) - args.v3.acConfig.fCoherentMode = 1; - if (radeon_encoder->pixel_clock > 165000) - args.v3.acConfig.fDualLinkConnector = 1; - } - } else if (ASIC_IS_DCE32(rdev)) { - args.v2.acConfig.ucEncoderSel = dig_encoder; - if (dig->linkb) - args.v2.acConfig.ucLinkSel = 1; - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - args.v2.acConfig.ucTransmitterSel = 0; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - args.v2.acConfig.ucTransmitterSel = 1; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - args.v2.acConfig.ucTransmitterSel = 2; - break; - } - - if (is_dp) { - args.v2.acConfig.fCoherentMode = 1; - args.v2.acConfig.fDPConnector = 1; - } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { - if (dig->coherent_mode) - args.v2.acConfig.fCoherentMode = 1; - if (radeon_encoder->pixel_clock > 165000) - args.v2.acConfig.fDualLinkConnector = 1; - } - } else { - args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; - - if (dig_encoder) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; - else - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; - - if ((rdev->flags & RADEON_IS_IGP) && - (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) { - if (is_dp || (radeon_encoder->pixel_clock <= 165000)) { - if (igp_lane_info & 0x1) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; - else if (igp_lane_info & 0x2) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; - else if (igp_lane_info & 0x4) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; - else if (igp_lane_info & 0x8) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; - } else { - if (igp_lane_info & 0x3) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; - else if (igp_lane_info & 0xc) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; - } - } - - if (dig->linkb) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; - else - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; - - if (is_dp) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; - else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { - if (dig->coherent_mode) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; - if (radeon_encoder->pixel_clock > 165000) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; - } - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); -} - -bool -atombios_set_edp_panel_power(struct drm_connector *connector, int action) -{ - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct drm_device *dev = radeon_connector->base.dev; - struct radeon_device *rdev = dev->dev_private; - union dig_transmitter_control args; - int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); - uint8_t frev, crev; - - if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) - goto done; - - if (!ASIC_IS_DCE4(rdev)) - goto done; - - if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) && - (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) - goto done; - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - goto done; - - memset(&args, 0, sizeof(args)); - - args.v1.ucAction = action; - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - - /* wait for the panel to power up */ - if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) { - int i; - - for (i = 0; i < 300; i++) { - if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) - return true; - mdelay(1); - } - return false; - } -done: - return true; -} - -union external_encoder_control { - EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; - EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3; -}; - -static void -atombios_external_encoder_setup(struct drm_encoder *encoder, - struct drm_encoder *ext_encoder, - int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); - union external_encoder_control args; - struct drm_connector *connector; - int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); - u8 frev, crev; - int dp_clock = 0; - int dp_lane_count = 0; - int connector_object_id = 0; - u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; - int bpc = 8; - - if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) - connector = radeon_get_connector_for_encoder_init(encoder); - else - connector = radeon_get_connector_for_encoder(encoder); - - if (connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *dig_connector = - radeon_connector->con_priv; - - dp_clock = dig_connector->dp_clock; - dp_lane_count = dig_connector->dp_lane_count; - connector_object_id = - (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - bpc = connector->display_info.bpc; - } - - memset(&args, 0, sizeof(args)); - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return; - - switch (frev) { - case 1: - /* no params on frev 1 */ - break; - case 2: - switch (crev) { - case 1: - case 2: - args.v1.sDigEncoder.ucAction = action; - args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); - - if (args.v1.sDigEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) { - if (dp_clock == 270000) - args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; - args.v1.sDigEncoder.ucLaneNum = dp_lane_count; - } else if (radeon_encoder->pixel_clock > 165000) - args.v1.sDigEncoder.ucLaneNum = 8; - else - args.v1.sDigEncoder.ucLaneNum = 4; - break; - case 3: - args.v3.sExtEncoder.ucAction = action; - if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) - args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id); - else - args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); - - if (args.v3.sExtEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) { - if (dp_clock == 270000) - args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; - else if (dp_clock == 540000) - args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ; - args.v3.sExtEncoder.ucLaneNum = dp_lane_count; - } else if (radeon_encoder->pixel_clock > 165000) - args.v3.sExtEncoder.ucLaneNum = 8; - else - args.v3.sExtEncoder.ucLaneNum = 4; - switch (ext_enum) { - case GRAPH_OBJECT_ENUM_ID1: - args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1; - break; - case GRAPH_OBJECT_ENUM_ID2: - args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2; - break; - case GRAPH_OBJECT_ENUM_ID3: - args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3; - break; - } - switch (bpc) { - case 0: - args.v3.sExtEncoder.ucBitPerColor = PANEL_BPC_UNDEFINE; - break; - case 6: - args.v3.sExtEncoder.ucBitPerColor = PANEL_6BIT_PER_COLOR; - break; - case 8: - default: - args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR; - break; - case 10: - args.v3.sExtEncoder.ucBitPerColor = PANEL_10BIT_PER_COLOR; - break; - case 12: - args.v3.sExtEncoder.ucBitPerColor = PANEL_12BIT_PER_COLOR; - break; - case 16: - args.v3.sExtEncoder.ucBitPerColor = PANEL_16BIT_PER_COLOR; - break; - } - break; - default: - DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); - return; - } - break; - default: - DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); - return; - } - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); -} - -static void -atombios_yuv_setup(struct drm_encoder *encoder, bool enable) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - ENABLE_YUV_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, EnableYUV); - uint32_t temp, reg; - - memset(&args, 0, sizeof(args)); - - if (rdev->family >= CHIP_R600) - reg = R600_BIOS_3_SCRATCH; - else - reg = RADEON_BIOS_3_SCRATCH; - - /* XXX: fix up scratch reg handling */ - temp = RREG32(reg); - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - WREG32(reg, (ATOM_S3_TV1_ACTIVE | - (radeon_crtc->crtc_id << 18))); - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24))); - else - WREG32(reg, 0); - - if (enable) - args.ucEnable = ATOM_ENABLE; - args.ucCRTC = radeon_crtc->crtc_id; - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - - WREG32(reg, temp); -} - -static void -radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; - int index = 0; - bool is_dig = false; - bool is_dce5_dac = false; - bool is_dce5_dvo = false; - - memset(&args, 0, sizeof(args)); - - DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", - radeon_encoder->encoder_id, mode, radeon_encoder->devices, - radeon_encoder->active_device); - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - is_dig = true; - break; - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_DDI: - index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - if (ASIC_IS_DCE5(rdev)) - is_dce5_dvo = true; - else if (ASIC_IS_DCE3(rdev)) - is_dig = true; - else - index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); - else - index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - if (ASIC_IS_DCE5(rdev)) - is_dce5_dac = true; - else { - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); - else - index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); - } - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); - else - index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); - break; - } - - if (is_dig) { - switch (mode) { - case DRM_MODE_DPMS_ON: - /* some early dce3.2 boards have a bug in their transmitter control table */ - if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - else - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - - if (connector && - (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *radeon_dig_connector = - radeon_connector->con_priv; - atombios_set_edp_panel_power(connector, - ATOM_TRANSMITTER_ACTION_POWER_ON); - radeon_dig_connector->edp_on = true; - } - if (ASIC_IS_DCE4(rdev)) - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); - radeon_dp_link_train(encoder, connector); - if (ASIC_IS_DCE4(rdev)) - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); - } - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - - if (ASIC_IS_DCE4(rdev)) - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); - if (connector && - (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *radeon_dig_connector = - radeon_connector->con_priv; - atombios_set_edp_panel_power(connector, - ATOM_TRANSMITTER_ACTION_POWER_OFF); - radeon_dig_connector->edp_on = false; - } - } - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); - break; - } - } else if (is_dce5_dac) { - switch (mode) { - case DRM_MODE_DPMS_ON: - atombios_dac_setup(encoder, ATOM_ENABLE); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - atombios_dac_setup(encoder, ATOM_DISABLE); - break; - } - } else if (is_dce5_dvo) { - switch (mode) { - case DRM_MODE_DPMS_ON: - atombios_dvo_setup(encoder, ATOM_ENABLE); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - atombios_dvo_setup(encoder, ATOM_DISABLE); - break; - } - } else { - switch (mode) { - case DRM_MODE_DPMS_ON: - args.ucAction = ATOM_ENABLE; - /* workaround for DVOOutputControl on some RS690 systems */ - if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) { - u32 reg = RREG32(RADEON_BIOS_3_SCRATCH); - WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - WREG32(RADEON_BIOS_3_SCRATCH, reg); - } else - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - args.ucAction = ATOM_LCD_BLON; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - } - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - args.ucAction = ATOM_DISABLE; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - args.ucAction = ATOM_LCD_BLOFF; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - } - break; - } - } - - if (ext_encoder) { - switch (mode) { - case DRM_MODE_DPMS_ON: - default: - if (ASIC_IS_DCE41(rdev)) { - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT); - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF); - } else - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - if (ASIC_IS_DCE41(rdev)) { - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING); - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT); - } else - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); - break; - } - } - - radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); - -} - -union crtc_source_param { - SELECT_CRTC_SOURCE_PS_ALLOCATION v1; - SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; -}; - -static void -atombios_set_encoder_crtc_source(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - union crtc_source_param args; - int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); - uint8_t frev, crev; - struct radeon_encoder_atom_dig *dig; - - memset(&args, 0, sizeof(args)); - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return; - - switch (frev) { - case 1: - switch (crev) { - case 1: - default: - if (ASIC_IS_AVIVO(rdev)) - args.v1.ucCRTC = radeon_crtc->crtc_id; - else { - if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) { - args.v1.ucCRTC = radeon_crtc->crtc_id; - } else { - args.v1.ucCRTC = radeon_crtc->crtc_id << 2; - } - } - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; - break; - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) - args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; - else - args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; - break; - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; - else - args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; - else - args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; - break; - } - break; - case 2: - args.v2.ucCRTC = radeon_crtc->crtc_id; - if (radeon_encoder_is_dp_bridge(encoder)) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - - if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) - args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; - else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA) - args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT; - else - args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); - } else - args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - dig = radeon_encoder->enc_priv; - switch (dig->dig_encoder) { - case 0: - args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; - break; - case 1: - args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; - break; - case 2: - args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; - break; - case 3: - args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; - break; - case 4: - args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; - break; - case 5: - args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; - break; - } - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; - else - args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; - else - args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; - break; - } - break; - } - break; - default: - DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); - return; - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - - /* update scratch regs with new routing */ - radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); -} - -static void -atombios_apply_encoder_quirks(struct drm_encoder *encoder, - struct drm_display_mode *mode) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - - /* Funky macbooks */ - if ((dev->pdev->device == 0x71C5) && - (dev->pdev->subsystem_vendor == 0x106b) && - (dev->pdev->subsystem_device == 0x0080)) { - if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { - uint32_t lvtma_bit_depth_control = RREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL); - - lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; - lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; - - WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); - } - } - - /* set scaler clears this on some chips */ - if (ASIC_IS_AVIVO(rdev) && - (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) { - if (ASIC_IS_DCE4(rdev)) { - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, - EVERGREEN_INTERLEAVE_EN); - else - WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); - } else { - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, - AVIVO_D1MODE_INTERLEAVE_EN); - else - WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); - } - } -} - -static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *test_encoder; - struct radeon_encoder_atom_dig *dig; - uint32_t dig_enc_in_use = 0; - - /* DCE4/5 */ - if (ASIC_IS_DCE4(rdev)) { - dig = radeon_encoder->enc_priv; - if (ASIC_IS_DCE41(rdev)) { - /* ontario follows DCE4 */ - if (rdev->family == CHIP_PALM) { - if (dig->linkb) - return 1; - else - return 0; - } else - /* llano follows DCE3.2 */ - return radeon_crtc->crtc_id; - } else { - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - if (dig->linkb) - return 1; - else - return 0; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - if (dig->linkb) - return 3; - else - return 2; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - if (dig->linkb) - return 5; - else - return 4; - break; - } - } - } - - /* on DCE32 and encoder can driver any block so just crtc id */ - if (ASIC_IS_DCE32(rdev)) { - return radeon_crtc->crtc_id; - } - - /* on DCE3 - LVTMA can only be driven by DIGB */ - list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { - struct radeon_encoder *radeon_test_encoder; - - if (encoder == test_encoder) - continue; - - if (!radeon_encoder_is_digital(test_encoder)) - continue; - - radeon_test_encoder = to_radeon_encoder(test_encoder); - dig = radeon_test_encoder->enc_priv; - - if (dig->dig_encoder >= 0) - dig_enc_in_use |= (1 << dig->dig_encoder); - } - - if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { - if (dig_enc_in_use & 0x2) - DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); - return 1; - } - if (!(dig_enc_in_use & 1)) - return 0; - return 1; -} - -/* This only needs to be called once at startup */ -void -radeon_atom_encoder_init(struct radeon_device *rdev) -{ - struct drm_device *dev = rdev->ddev; - struct drm_encoder *encoder; - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); - break; - default: - break; - } - - if (ext_encoder && ASIC_IS_DCE41(rdev)) - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); - } -} - -static void -radeon_atom_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - - radeon_encoder->pixel_clock = adjusted_mode->clock; - - if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) { - if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) - atombios_yuv_setup(encoder, true); - else - atombios_yuv_setup(encoder, false); - } - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - if (ASIC_IS_DCE4(rdev)) { - /* disable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - /* setup and enable the encoder */ - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); - - /* enable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - } else { - /* disable the encoder and transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); - - /* setup and enable the encoder and transmitter */ - atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - } - break; - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - atombios_dvo_setup(encoder, ATOM_ENABLE); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - atombios_dac_setup(encoder, ATOM_ENABLE); - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) { - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) - atombios_tv_setup(encoder, ATOM_ENABLE); - else - atombios_tv_setup(encoder, ATOM_DISABLE); - } - break; - } - - if (ext_encoder) { - if (ASIC_IS_DCE41(rdev)) - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); - else - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); - } - - atombios_apply_encoder_quirks(encoder, adjusted_mode); - - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { - r600_hdmi_enable(encoder); - r600_hdmi_setmode(encoder, adjusted_mode); - } -} - -static bool -atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | - ATOM_DEVICE_CV_SUPPORT | - ATOM_DEVICE_CRT_SUPPORT)) { - DAC_LOAD_DETECTION_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); - uint8_t frev, crev; - - memset(&args, 0, sizeof(args)); - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return false; - - args.sDacload.ucMisc = 0; - - if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || - (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) - args.sDacload.ucDacType = ATOM_DAC_A; - else - args.sDacload.ucDacType = ATOM_DAC_B; - - if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); - else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); - else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); - if (crev >= 3) - args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; - } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); - if (crev >= 3) - args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - - return true; - } else - return false; -} - -static enum drm_connector_status -radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - uint32_t bios_0_scratch; - - if (!atombios_dac_load_detect(encoder, connector)) { - DRM_DEBUG_KMS("detect returned false \n"); - return connector_status_unknown; - } - - if (rdev->family >= CHIP_R600) - bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); - else - bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); - - DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); - if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { - if (bios_0_scratch & ATOM_S0_CRT1_MASK) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { - if (bios_0_scratch & ATOM_S0_CRT2_MASK) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { - if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { - if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) - return connector_status_connected; /* CTV */ - else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) - return connector_status_connected; /* STV */ - } - return connector_status_disconnected; -} - -static enum drm_connector_status -radeon_atom_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - u32 bios_0_scratch; - - if (!ASIC_IS_DCE4(rdev)) - return connector_status_unknown; - - if (!ext_encoder) - return connector_status_unknown; - - if ((radeon_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0) - return connector_status_unknown; - - /* load detect on the dp bridge */ - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION); - - bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); - - DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); - if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { - if (bios_0_scratch & ATOM_S0_CRT1_MASK) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { - if (bios_0_scratch & ATOM_S0_CRT2_MASK) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { - if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { - if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) - return connector_status_connected; /* CTV */ - else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) - return connector_status_connected; /* STV */ - } - return connector_status_disconnected; -} - -void -radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder) -{ - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - - if (ext_encoder) - /* ddc_setup on the dp bridge */ - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); - -} - -static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - - if ((radeon_encoder->active_device & - (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || - radeon_encoder_is_dp_bridge(encoder)) { - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - if (dig) - dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); - } - - radeon_atom_output_lock(encoder, true); - radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); - - if (connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - - /* select the clock/data port if it uses a router */ - if (radeon_connector->router.cd_valid) - radeon_router_select_cd_port(radeon_connector); - - /* turn eDP panel on for mode set */ - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) - atombios_set_edp_panel_power(connector, - ATOM_TRANSMITTER_ACTION_POWER_ON); - } - - /* this is needed for the pll/ss setup to work correctly in some cases */ - atombios_set_encoder_crtc_source(encoder); -} - -static void radeon_atom_encoder_commit(struct drm_encoder *encoder) -{ - radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); - radeon_atom_output_lock(encoder, false); -} - -static void radeon_atom_encoder_disable(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig; - - /* check for pre-DCE3 cards with shared encoders; - * can't really use the links individually, so don't disable - * the encoder if it's in use by another connector - */ - if (!ASIC_IS_DCE3(rdev)) { - struct drm_encoder *other_encoder; - struct radeon_encoder *other_radeon_encoder; - - list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { - other_radeon_encoder = to_radeon_encoder(other_encoder); - if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) && - drm_helper_encoder_in_use(other_encoder)) - goto disable_done; - } - } - - radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_DISABLE); - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - if (ASIC_IS_DCE4(rdev)) - /* disable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - else { - /* disable the encoder and transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); - } - break; - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - atombios_dvo_setup(encoder, ATOM_DISABLE); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - atombios_dac_setup(encoder, ATOM_DISABLE); - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) - atombios_tv_setup(encoder, ATOM_DISABLE); - break; - } - -disable_done: - if (radeon_encoder_is_digital(encoder)) { - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) - r600_hdmi_disable(encoder); - dig = radeon_encoder->enc_priv; - dig->dig_encoder = -1; - } - radeon_encoder->active_device = 0; -} - -/* these are handled by the primary encoders */ -static void radeon_atom_ext_prepare(struct drm_encoder *encoder) -{ - -} - -static void radeon_atom_ext_commit(struct drm_encoder *encoder) -{ - -} - -static void -radeon_atom_ext_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - -} - -static void radeon_atom_ext_disable(struct drm_encoder *encoder) -{ - -} - -static void -radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) -{ - -} - -static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - -static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { - .dpms = radeon_atom_ext_dpms, - .mode_fixup = radeon_atom_ext_mode_fixup, - .prepare = radeon_atom_ext_prepare, - .mode_set = radeon_atom_ext_mode_set, - .commit = radeon_atom_ext_commit, - .disable = radeon_atom_ext_disable, - /* no detect for TMDS/LVDS yet */ -}; - -static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { - .dpms = radeon_atom_encoder_dpms, - .mode_fixup = radeon_atom_mode_fixup, - .prepare = radeon_atom_encoder_prepare, - .mode_set = radeon_atom_encoder_mode_set, - .commit = radeon_atom_encoder_commit, - .disable = radeon_atom_encoder_disable, - .detect = radeon_atom_dig_detect, -}; - -static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { - .dpms = radeon_atom_encoder_dpms, - .mode_fixup = radeon_atom_mode_fixup, - .prepare = radeon_atom_encoder_prepare, - .mode_set = radeon_atom_encoder_mode_set, - .commit = radeon_atom_encoder_commit, - .detect = radeon_atom_dac_detect, -}; - -void radeon_enc_destroy(struct drm_encoder *encoder) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - kfree(radeon_encoder->enc_priv); - drm_encoder_cleanup(encoder); - kfree(radeon_encoder); -} - -static const struct drm_encoder_funcs radeon_atom_enc_funcs = { - .destroy = radeon_enc_destroy, -}; - -struct radeon_encoder_atom_dac * -radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) -{ - struct drm_device *dev = radeon_encoder->base.dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL); - - if (!dac) - return NULL; - - dac->tv_std = radeon_atombios_get_tv_info(rdev); - return dac; -} - -struct radeon_encoder_atom_dig * -radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) -{ - int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; - struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); - - if (!dig) - return NULL; - - /* coherent mode by default */ - dig->coherent_mode = true; - dig->dig_encoder = -1; - - if (encoder_enum == 2) - dig->linkb = true; - else - dig->linkb = false; - - return dig; -} - -void -radeon_add_atom_encoder(struct drm_device *dev, - uint32_t encoder_enum, - uint32_t supported_device, - u16 caps) -{ - struct radeon_device *rdev = dev->dev_private; - struct drm_encoder *encoder; - struct radeon_encoder *radeon_encoder; - - /* see if we already added it */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->encoder_enum == encoder_enum) { - radeon_encoder->devices |= supported_device; - return; - } - - } - - /* add a new one */ - radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); - if (!radeon_encoder) - return; - - encoder = &radeon_encoder->base; - switch (rdev->num_crtc) { - case 1: - encoder->possible_crtcs = 0x1; - break; - case 2: - default: - encoder->possible_crtcs = 0x3; - break; - case 4: - encoder->possible_crtcs = 0xf; - break; - case 6: - encoder->possible_crtcs = 0x3f; - break; - } - - radeon_encoder->enc_priv = NULL; - - radeon_encoder->encoder_enum = encoder_enum; - radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - radeon_encoder->devices = supported_device; - radeon_encoder->rmx_type = RMX_OFF; - radeon_encoder->underscan_type = UNDERSCAN_OFF; - radeon_encoder->is_ext_encoder = false; - radeon_encoder->caps = caps; - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - radeon_encoder->rmx_type = RMX_FULL; - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); - radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); - } else { - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); - radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); - } - drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); - radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); - drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC); - radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); - drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); - break; - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - radeon_encoder->rmx_type = RMX_FULL; - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); - radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); - } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); - radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); - } else { - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); - radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); - } - drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); - break; - case ENCODER_OBJECT_ID_SI170B: - case ENCODER_OBJECT_ID_CH7303: - case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: - case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: - case ENCODER_OBJECT_ID_TITFP513: - case ENCODER_OBJECT_ID_VT1623: - case ENCODER_OBJECT_ID_HDMI_SI1930: - case ENCODER_OBJECT_ID_TRAVIS: - case ENCODER_OBJECT_ID_NUTMEG: - /* these are handled by the primary encoders */ - radeon_encoder->is_ext_encoder = true; - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); - else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); - else - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); - drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); - break; - } -} diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index fdc3a9a54bf8..ba7ab79e12c1 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -49,27 +49,27 @@ int radeon_gart_table_ram_alloc(struct radeon_device *rdev) rdev->gart.table_size >> PAGE_SHIFT); } #endif - rdev->gart.table.ram.ptr = ptr; - memset((void *)rdev->gart.table.ram.ptr, 0, rdev->gart.table_size); + rdev->gart.ptr = ptr; + memset((void *)rdev->gart.ptr, 0, rdev->gart.table_size); return 0; } void radeon_gart_table_ram_free(struct radeon_device *rdev) { - if (rdev->gart.table.ram.ptr == NULL) { + if (rdev->gart.ptr == NULL) { return; } #ifdef CONFIG_X86 if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { - set_memory_wb((unsigned long)rdev->gart.table.ram.ptr, + set_memory_wb((unsigned long)rdev->gart.ptr, rdev->gart.table_size >> PAGE_SHIFT); } #endif pci_free_consistent(rdev->pdev, rdev->gart.table_size, - (void *)rdev->gart.table.ram.ptr, + (void *)rdev->gart.ptr, rdev->gart.table_addr); - rdev->gart.table.ram.ptr = NULL; + rdev->gart.ptr = NULL; rdev->gart.table_addr = 0; } @@ -77,10 +77,10 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { r = radeon_bo_create(rdev, rdev->gart.table_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, - &rdev->gart.table.vram.robj); + &rdev->gart.robj); if (r) { return r; } @@ -93,38 +93,46 @@ int radeon_gart_table_vram_pin(struct radeon_device *rdev) uint64_t gpu_addr; int r; - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); + r = radeon_bo_reserve(rdev->gart.robj, false); if (unlikely(r != 0)) return r; - r = radeon_bo_pin(rdev->gart.table.vram.robj, + r = radeon_bo_pin(rdev->gart.robj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr); if (r) { - radeon_bo_unreserve(rdev->gart.table.vram.robj); + radeon_bo_unreserve(rdev->gart.robj); return r; } - r = radeon_bo_kmap(rdev->gart.table.vram.robj, - (void **)&rdev->gart.table.vram.ptr); + r = radeon_bo_kmap(rdev->gart.robj, &rdev->gart.ptr); if (r) - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); + radeon_bo_unpin(rdev->gart.robj); + radeon_bo_unreserve(rdev->gart.robj); rdev->gart.table_addr = gpu_addr; return r; } -void radeon_gart_table_vram_free(struct radeon_device *rdev) +void radeon_gart_table_vram_unpin(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { return; } - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); + r = radeon_bo_reserve(rdev->gart.robj, false); if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); + radeon_bo_kunmap(rdev->gart.robj); + radeon_bo_unpin(rdev->gart.robj); + radeon_bo_unreserve(rdev->gart.robj); + rdev->gart.ptr = NULL; } - radeon_bo_unref(&rdev->gart.table.vram.robj); +} + +void radeon_gart_table_vram_free(struct radeon_device *rdev) +{ + if (rdev->gart.robj == NULL) { + return; + } + radeon_gart_table_vram_unpin(rdev); + radeon_bo_unref(&rdev->gart.robj); } @@ -151,12 +159,14 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, if (rdev->gart.pages[p]) { if (!rdev->gart.ttm_alloced[p]) pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p], - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); rdev->gart.pages[p] = NULL; rdev->gart.pages_addr[p] = rdev->dummy_page.addr; page_base = rdev->gart.pages_addr[p]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base); + if (rdev->gart.ptr) { + radeon_gart_set_page(rdev, t, page_base); + } page_base += RADEON_GPU_PAGE_SIZE; } } @@ -199,10 +209,12 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, } } rdev->gart.pages[p] = pagelist[i]; - page_base = rdev->gart.pages_addr[p]; - for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base); - page_base += RADEON_GPU_PAGE_SIZE; + if (rdev->gart.ptr) { + page_base = rdev->gart.pages_addr[p]; + for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { + radeon_gart_set_page(rdev, t, page_base); + page_base += RADEON_GPU_PAGE_SIZE; + } } } mb(); @@ -215,6 +227,9 @@ void radeon_gart_restore(struct radeon_device *rdev) int i, j, t; u64 page_base; + if (!rdev->gart.ptr) { + return; + } for (i = 0, t = 0; i < rdev->gart.num_cpu_pages; i++) { page_base = rdev->gart.pages_addr[i]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 02cb7da4124d..7bb1b079f480 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -23,6 +23,8 @@ * Authors: Dave Airlie * Alex Deucher */ +#include <linux/export.h> + #include "drmP.h" #include "radeon_drm.h" #include "radeon.h" @@ -32,7 +34,7 @@ * radeon_ddc_probe * */ -bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_extended_probe) +bool radeon_ddc_probe(struct radeon_connector *radeon_connector) { u8 out = 0x0; u8 buf[8]; @@ -47,15 +49,11 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_e { .addr = 0x50, .flags = I2C_M_RD, - .len = 1, + .len = 8, .buf = buf, } }; - /* Read 8 bytes from i2c for extended probe of EDID header */ - if (requires_extended_probe) - msgs[1].len = 8; - /* on hw with routers, select right port */ if (radeon_connector->router.ddc_valid) radeon_router_select_ddc_port(radeon_connector); @@ -64,17 +62,15 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_e if (ret != 2) /* Couldn't find an accessible DDC on this connector */ return false; - if (requires_extended_probe) { - /* Probe also for valid EDID header - * EDID header starts with: - * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00. - * Only the first 6 bytes must be valid as - * drm_edid_block_valid() can fix the last 2 bytes */ - if (drm_edid_header_is_valid(buf) < 6) { - /* Couldn't find an accessible EDID on this - * connector */ - return false; - } + /* Probe also for valid EDID header + * EDID header starts with: + * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00. + * Only the first 6 bytes must be valid as + * drm_edid_block_valid() can fix the last 2 bytes */ + if (drm_edid_header_is_valid(buf) < 6) { + /* Couldn't find an accessible EDID on this + * connector */ + return false; } return true; } diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 9ec830c77af0..8f86aeb26693 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -67,10 +67,10 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ rdev->irq.sw_int = false; rdev->irq.gui_idle = false; - for (i = 0; i < rdev->num_crtc; i++) - rdev->irq.crtc_vblank_int[i] = false; - for (i = 0; i < 6; i++) { + for (i = 0; i < RADEON_MAX_HPD_PINS; i++) rdev->irq.hpd[i] = false; + for (i = 0; i < RADEON_MAX_CRTCS; i++) { + rdev->irq.crtc_vblank_int[i] = false; rdev->irq.pflip[i] = false; } radeon_irq_set(rdev); @@ -99,15 +99,55 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ rdev->irq.sw_int = false; rdev->irq.gui_idle = false; - for (i = 0; i < rdev->num_crtc; i++) - rdev->irq.crtc_vblank_int[i] = false; - for (i = 0; i < 6; i++) { + for (i = 0; i < RADEON_MAX_HPD_PINS; i++) rdev->irq.hpd[i] = false; + for (i = 0; i < RADEON_MAX_CRTCS; i++) { + rdev->irq.crtc_vblank_int[i] = false; rdev->irq.pflip[i] = false; } radeon_irq_set(rdev); } +static bool radeon_msi_ok(struct radeon_device *rdev) +{ + /* RV370/RV380 was first asic with MSI support */ + if (rdev->family < CHIP_RV380) + return false; + + /* MSIs don't work on AGP */ + if (rdev->flags & RADEON_IS_AGP) + return false; + + /* force MSI on */ + if (radeon_msi == 1) + return true; + else if (radeon_msi == 0) + return false; + + /* Quirks */ + /* HP RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x103c) && + (rdev->pdev->subsystem_device == 0x30c2)) + return true; + + /* Dell RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x1028) && + (rdev->pdev->subsystem_device == 0x01fd)) + return true; + + if (rdev->flags & RADEON_IS_IGP) { + /* APUs work fine with MSIs */ + if (rdev->family >= CHIP_PALM) + return true; + /* lots of IGPs have problems with MSIs */ + return false; + } + + return true; +} + int radeon_irq_kms_init(struct radeon_device *rdev) { int i; @@ -124,12 +164,8 @@ int radeon_irq_kms_init(struct radeon_device *rdev) } /* enable msi */ rdev->msi_enabled = 0; - /* MSIs don't seem to work reliably on all IGP - * chips. Disable MSI on them for now. - */ - if ((rdev->family >= CHIP_RV380) && - ((!(rdev->flags & RADEON_IS_IGP)) || (rdev->family >= CHIP_PALM)) && - (!(rdev->flags & RADEON_IS_AGP))) { + + if (radeon_msi_ok(rdev)) { int ret = pci_enable_msi(rdev->pdev); if (!ret) { rdev->msi_enabled = 1; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index ed0178f03235..2c2e75ef8a37 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -438,9 +438,6 @@ struct radeon_connector { struct radeon_i2c_chan *ddc_bus; /* some systems have an hdmi and vga port with a shared ddc line */ bool shared_ddc; - /* for some Radeon chip families we apply an additional EDID header - check as part of the DDC probe */ - bool requires_extended_probe; bool use_digital; /* we need to mind the EDID between detect and get modes due to analog/digital/tvencoder */ @@ -459,6 +456,8 @@ struct radeon_framebuffer { struct drm_gem_object *obj; }; +#define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \ + ((em) == ATOM_ENCODER_MODE_DP_MST)) extern enum radeon_tv_std radeon_combios_get_tv_info(struct radeon_device *rdev); @@ -468,8 +467,8 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev); extern struct drm_connector * radeon_get_connector_for_encoder(struct drm_encoder *encoder); -extern bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder); -extern bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector); +extern u16 radeon_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder); +extern u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector); extern bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector); extern bool radeon_connector_is_dp12_capable(struct drm_connector *connector); @@ -489,7 +488,7 @@ extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set); extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder); -extern struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder); +extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder); extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, u8 write_byte, u8 *read_byte); @@ -519,8 +518,7 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c, u8 val); extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector); extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); -extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, - bool requires_extended_probe); +extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 89a6e1ecea8d..06b90c87f8f3 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -77,7 +77,7 @@ int rs400_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.ram.ptr) { + if (rdev->gart.ptr) { WARN(1, "RS400 GART already initialized\n"); return 0; } @@ -212,6 +212,7 @@ void rs400_gart_fini(struct radeon_device *rdev) int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { uint32_t entry; + u32 *gtt = rdev->gart.ptr; if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; @@ -221,7 +222,7 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) ((upper_32_bits(addr) & 0xff) << 4) | RS400_PTE_WRITEABLE | RS400_PTE_READABLE; entry = cpu_to_le32(entry); - rdev->gart.table.ram.ptr[i] = entry; + gtt[i] = entry; return 0; } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 9320dd6404f6..481b99e89f65 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -287,6 +287,7 @@ void rs600_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) rs600_irq_set(rdev); @@ -413,7 +414,7 @@ int rs600_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj) { + if (rdev->gart.robj) { WARN(1, "RS600 GART already initialized\n"); return 0; } @@ -431,7 +432,7 @@ static int rs600_gart_enable(struct radeon_device *rdev) u32 tmp; int r, i; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -494,20 +495,12 @@ static int rs600_gart_enable(struct radeon_device *rdev) void rs600_gart_disable(struct radeon_device *rdev) { u32 tmp; - int r; /* FIXME: disable out of gart access */ WREG32_MC(R_000100_MC_PT0_CNTL, 0); tmp = RREG32_MC(R_000009_MC_CNTL1); WREG32_MC(R_000009_MC_CNTL1, tmp & C_000009_ENABLE_PAGE_TABLES); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (r == 0) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void rs600_gart_fini(struct radeon_device *rdev) @@ -525,7 +518,7 @@ void rs600_gart_fini(struct radeon_device *rdev) int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + void __iomem *ptr = (void *)rdev->gart.ptr; if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 87cc1feee3ac..a983f410ab89 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -124,7 +124,7 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) u32 tmp; int r, i; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -171,7 +171,7 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) void rv770_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int i, r; + int i; /* Disable all tables */ for (i = 0; i < 7; i++) @@ -191,14 +191,7 @@ void rv770_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void rv770_pcie_gart_fini(struct radeon_device *rdev) @@ -282,7 +275,7 @@ static void rv770_mc_program(struct radeon_device *rdev) WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, rdev->mc.vram_end >> 12); } - WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); + WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, rdev->vram_scratch.gpu_addr >> 12); tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); WREG32(MC_VM_FB_LOCATION, tmp); @@ -959,54 +952,6 @@ static void rv770_gpu_init(struct radeon_device *rdev) } -static int rv770_vram_scratch_init(struct radeon_device *rdev) -{ - int r; - u64 gpu_addr; - - if (rdev->vram_scratch.robj == NULL) { - r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, - PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, - &rdev->vram_scratch.robj); - if (r) { - return r; - } - } - - r = radeon_bo_reserve(rdev->vram_scratch.robj, false); - if (unlikely(r != 0)) - return r; - r = radeon_bo_pin(rdev->vram_scratch.robj, - RADEON_GEM_DOMAIN_VRAM, &gpu_addr); - if (r) { - radeon_bo_unreserve(rdev->vram_scratch.robj); - return r; - } - r = radeon_bo_kmap(rdev->vram_scratch.robj, - (void **)&rdev->vram_scratch.ptr); - if (r) - radeon_bo_unpin(rdev->vram_scratch.robj); - radeon_bo_unreserve(rdev->vram_scratch.robj); - - return r; -} - -static void rv770_vram_scratch_fini(struct radeon_device *rdev) -{ - int r; - - if (rdev->vram_scratch.robj == NULL) { - return; - } - r = radeon_bo_reserve(rdev->vram_scratch.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->vram_scratch.robj); - radeon_bo_unpin(rdev->vram_scratch.robj); - radeon_bo_unreserve(rdev->vram_scratch.robj); - } - radeon_bo_unref(&rdev->vram_scratch.robj); -} - void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) { u64 size_bf, size_af; @@ -1106,6 +1051,10 @@ static int rv770_startup(struct radeon_device *rdev) } } + r = r600_vram_scratch_init(rdev); + if (r) + return r; + rv770_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { rv770_agp_enable(rdev); @@ -1114,9 +1063,7 @@ static int rv770_startup(struct radeon_device *rdev) if (r) return r; } - r = rv770_vram_scratch_init(rdev); - if (r) - return r; + rv770_gpu_init(rdev); r = r600_blit_init(rdev); if (r) { @@ -1316,7 +1263,7 @@ void rv770_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); rv770_pcie_gart_fini(rdev); - rv770_vram_scratch_fini(rdev); + r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_agp_fini(rdev); diff --git a/drivers/gpu/drm/savage/savage_drv.c b/drivers/gpu/drm/savage/savage_drv.c index 6464490b240b..5468d1cd3296 100644 --- a/drivers/gpu/drm/savage/savage_drv.c +++ b/drivers/gpu/drm/savage/savage_drv.c @@ -23,6 +23,8 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include <linux/module.h> + #include "drmP.h" #include "savage_drm.h" #include "savage_drv.h" diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c index 46d5be6e97e5..a9c5716bea4e 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c @@ -25,6 +25,8 @@ * */ +#include <linux/module.h> + #include "drmP.h" #include "sis_drm.h" #include "sis_drv.h" diff --git a/drivers/gpu/drm/tdfx/tdfx_drv.c b/drivers/gpu/drm/tdfx/tdfx_drv.c index 8bf98810a8d6..cda29911e332 100644 --- a/drivers/gpu/drm/tdfx/tdfx_drv.c +++ b/drivers/gpu/drm/tdfx/tdfx_drv.c @@ -30,6 +30,8 @@ * Gareth Hughes <gareth@valinux.com> */ +#include <linux/module.h> + #include "drmP.h" #include "tdfx_drv.h" diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 58c271ebc0f7..f9cc548d6d98 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -35,6 +35,7 @@ #include <linux/file.h> #include <linux/swap.h> #include <linux/slab.h> +#include <linux/export.h> #include "drm_cache.h" #include "drm_mem_util.h" #include "ttm/ttm_module.h" diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c index 920a55214bcf..a83e86d3956c 100644 --- a/drivers/gpu/drm/via/via_drv.c +++ b/drivers/gpu/drm/via/via_drv.c @@ -22,6 +22,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include <linux/module.h> + #include "drmP.h" #include "via_drm.h" #include "via_drv.h" diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 13afddc1f034..dff8fc767152 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -24,6 +24,7 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ +#include <linux/module.h> #include "drmP.h" #include "vmwgfx_drv.h" @@ -103,6 +104,9 @@ #define DRM_IOCTL_VMW_PRESENT_READBACK \ DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT_READBACK, \ struct drm_vmw_present_readback_arg) +#define DRM_IOCTL_VMW_UPDATE_LAYOUT \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT, \ + struct drm_vmw_update_layout_arg) /** * The core DRM version of this macro doesn't account for @@ -165,6 +169,9 @@ static struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_PRESENT_READBACK, vmw_present_readback_ioctl, DRM_MASTER | DRM_AUTH | DRM_UNLOCKED), + VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, + vmw_kms_update_layout_ioctl, + DRM_MASTER | DRM_UNLOCKED), }; static struct pci_device_id vmw_pci_id_list[] = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 30589d0aecd9..8cca91a93bde 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -40,9 +40,9 @@ #include "ttm/ttm_module.h" #include "vmwgfx_fence.h" -#define VMWGFX_DRIVER_DATE "20111008" +#define VMWGFX_DRIVER_DATE "20111025" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 2 +#define VMWGFX_DRIVER_MINOR 3 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) @@ -633,6 +633,8 @@ int vmw_kms_readback(struct vmw_private *dev_priv, struct drm_vmw_fence_rep __user *user_fence_rep, struct drm_vmw_rect *clips, uint32_t num_clips); +int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /** * Overlay control - vmwgfx_overlay.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 070797b7b03a..34e51a1695b8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -26,6 +26,8 @@ * **************************************************************************/ +#include <linux/export.h> + #include "drmP.h" #include "vmwgfx_drv.h" diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 8b14dfd513a1..03daefa73397 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -111,6 +111,7 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, if (!ret) { if (!surface->snooper.image) { DRM_ERROR("surface not suitable for cursor\n"); + vmw_surface_unreference(&surface); return -EINVAL; } } else { @@ -176,7 +177,9 @@ err_unreserve: return 0; } - vmw_cursor_update_position(dev_priv, true, du->cursor_x, du->cursor_y); + vmw_cursor_update_position(dev_priv, true, + du->cursor_x + du->hotspot_x, + du->cursor_y + du->hotspot_y); return 0; } @@ -191,7 +194,8 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) du->cursor_y = y + crtc->y; vmw_cursor_update_position(dev_priv, shown, - du->cursor_x, du->cursor_y); + du->cursor_x + du->hotspot_x, + du->cursor_y + du->hotspot_y); return 0; } @@ -212,7 +216,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, SVGA3dCmdHeader header; SVGA3dCmdSurfaceDMA dma; } *cmd; - int ret; + int i, ret; cmd = container_of(header, struct vmw_dma_cmd, header); @@ -234,16 +238,19 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) / sizeof(SVGA3dCopyBox); - if (cmd->dma.guest.pitch != (64 * 4) || - cmd->dma.guest.ptr.offset % PAGE_SIZE || + if (cmd->dma.guest.ptr.offset % PAGE_SIZE || box->x != 0 || box->y != 0 || box->z != 0 || box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || - box->w != 64 || box->h != 64 || box->d != 1 || - box_count != 1) { + box->d != 1 || box_count != 1) { /* TODO handle none page aligned offsets */ - /* TODO handle partial uploads and pitch != 256 */ - /* TODO handle more then one copy (size != 64) */ - DRM_ERROR("lazy programmer, can't handle weird stuff\n"); + /* TODO handle more dst & src != 0 */ + /* TODO handle more then one copy */ + DRM_ERROR("Cant snoop dma request for cursor!\n"); + DRM_ERROR("(%u, %u, %u) (%u, %u, %u) (%ux%ux%u) %u %u\n", + box->srcx, box->srcy, box->srcz, + box->x, box->y, box->z, + box->w, box->h, box->d, box_count, + cmd->dma.guest.ptr.offset); return; } @@ -262,7 +269,16 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, virtual = ttm_kmap_obj_virtual(&map, &dummy); - memcpy(srf->snooper.image, virtual, 64*64*4); + if (box->w == 64 && cmd->dma.guest.pitch == 64*4) { + memcpy(srf->snooper.image, virtual, 64*64*4); + } else { + /* Image is unsigned pointer. */ + for (i = 0; i < box->h; i++) + memcpy(srf->snooper.image + i * 64, + virtual + i * cmd->dma.guest.pitch, + box->w * 4); + } + srf->snooper.age++; /* we can't call this function from this function since execbuf has @@ -994,7 +1010,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, required_size = mode_cmd->pitch * mode_cmd->height; if (unlikely(required_size > (u64) dev_priv->vram_size)) { DRM_ERROR("VRAM size is too small for requested mode.\n"); - return NULL; + return ERR_PTR(-ENOMEM); } /* @@ -1517,6 +1533,8 @@ int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, du->pref_width = rects[du->unit].w; du->pref_height = rects[du->unit].h; du->pref_active = true; + du->gui_x = rects[du->unit].x; + du->gui_y = rects[du->unit].y; } else { du->pref_width = 800; du->pref_height = 600; @@ -1572,12 +1590,14 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force) uint32_t num_displays; struct drm_device *dev = connector->dev; struct vmw_private *dev_priv = vmw_priv(dev); + struct vmw_display_unit *du = vmw_connector_to_du(connector); mutex_lock(&dev_priv->hw_mutex); num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS); mutex_unlock(&dev_priv->hw_mutex); - return ((vmw_connector_to_du(connector)->unit < num_displays) ? + return ((vmw_connector_to_du(connector)->unit < num_displays && + du->pref_active) ? connector_status_connected : connector_status_disconnected); } @@ -1658,6 +1678,28 @@ static struct drm_display_mode vmw_kms_connector_builtin[] = { { DRM_MODE("", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) }, }; +/** + * vmw_guess_mode_timing - Provide fake timings for a + * 60Hz vrefresh mode. + * + * @mode - Pointer to a struct drm_display_mode with hdisplay and vdisplay + * members filled in. + */ +static void vmw_guess_mode_timing(struct drm_display_mode *mode) +{ + mode->hsync_start = mode->hdisplay + 50; + mode->hsync_end = mode->hsync_start + 50; + mode->htotal = mode->hsync_end + 50; + + mode->vsync_start = mode->vdisplay + 50; + mode->vsync_end = mode->vsync_start + 50; + mode->vtotal = mode->vsync_end + 50; + + mode->clock = (u32)mode->htotal * (u32)mode->vtotal / 100 * 6; + mode->vrefresh = drm_mode_vrefresh(mode); +} + + int vmw_du_connector_fill_modes(struct drm_connector *connector, uint32_t max_width, uint32_t max_height) { @@ -1680,18 +1722,23 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, return 0; mode->hdisplay = du->pref_width; mode->vdisplay = du->pref_height; - mode->vrefresh = drm_mode_vrefresh(mode); + vmw_guess_mode_timing(mode); + if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2, mode->vdisplay)) { drm_mode_probed_add(connector, mode); + } else { + drm_mode_destroy(dev, mode); + mode = NULL; + } - if (du->pref_mode) { - list_del_init(&du->pref_mode->head); - drm_mode_destroy(dev, du->pref_mode); - } - - du->pref_mode = mode; + if (du->pref_mode) { + list_del_init(&du->pref_mode->head); + drm_mode_destroy(dev, du->pref_mode); } + + /* mode might be null here, this is intended */ + du->pref_mode = mode; } for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) { @@ -1712,6 +1759,10 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, drm_mode_probed_add(connector, mode); } + /* Move the prefered mode first, help apps pick the right mode. */ + if (du->pref_mode) + list_move(&du->pref_mode->head, &connector->probed_modes); + drm_mode_connector_list_update(connector); return 1; @@ -1723,3 +1774,63 @@ int vmw_du_connector_set_property(struct drm_connector *connector, { return 0; } + + +int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct drm_vmw_update_layout_arg *arg = + (struct drm_vmw_update_layout_arg *)data; + struct vmw_master *vmaster = vmw_master(file_priv->master); + void __user *user_rects; + struct drm_vmw_rect *rects; + unsigned rects_size; + int ret; + int i; + struct drm_mode_config *mode_config = &dev->mode_config; + + ret = ttm_read_lock(&vmaster->lock, true); + if (unlikely(ret != 0)) + return ret; + + if (!arg->num_outputs) { + struct drm_vmw_rect def_rect = {0, 0, 800, 600}; + vmw_du_update_layout(dev_priv, 1, &def_rect); + goto out_unlock; + } + + rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect); + rects = kzalloc(rects_size, GFP_KERNEL); + if (unlikely(!rects)) { + ret = -ENOMEM; + goto out_unlock; + } + + user_rects = (void __user *)(unsigned long)arg->rects; + ret = copy_from_user(rects, user_rects, rects_size); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed to get rects.\n"); + ret = -EFAULT; + goto out_free; + } + + for (i = 0; i < arg->num_outputs; ++i) { + if (rects->x < 0 || + rects->y < 0 || + rects->x + rects->w > mode_config->max_width || + rects->y + rects->h > mode_config->max_height) { + DRM_ERROR("Invalid GUI layout.\n"); + ret = -EINVAL; + goto out_free; + } + } + + vmw_du_update_layout(dev_priv, arg->num_outputs, rects); + +out_free: + kfree(rects); +out_unlock: + ttm_read_unlock(&vmaster->lock); + return ret; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index db0b901f8c3f..af8e6e5bd964 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -96,6 +96,13 @@ struct vmw_display_unit { unsigned pref_height; bool pref_active; struct drm_display_mode *pref_mode; + + /* + * Gui positioning + */ + int gui_x; + int gui_y; + bool is_implicit; }; #define vmw_crtc_to_du(x) \ @@ -126,8 +133,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, int vmw_du_connector_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val); -int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, - struct drm_vmw_rect *rects); + /* * Legacy display unit functions - vmwgfx_ldu.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 92f56bc594eb..90c5e3928491 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -337,13 +337,14 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) ldu->base.pref_width = 800; ldu->base.pref_height = 600; ldu->base.pref_mode = NULL; + ldu->base.is_implicit = true; drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + DRM_MODE_CONNECTOR_VIRTUAL); connector->status = vmw_du_connector_detect(connector, true); drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, - DRM_MODE_ENCODER_LVDS); + DRM_MODE_ENCODER_VIRTUAL); drm_mode_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 477b2a9eb3c2..4defdcf1c72e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -36,12 +36,9 @@ container_of(x, struct vmw_screen_object_unit, base.connector) struct vmw_screen_object_display { - struct list_head active; + unsigned num_implicit; - unsigned num_active; - unsigned last_num_active; - - struct vmw_framebuffer *fb; + struct vmw_framebuffer *implicit_fb; }; /** @@ -54,13 +51,11 @@ struct vmw_screen_object_unit { struct vmw_dma_buffer *buffer; /**< Backing store buffer */ bool defined; - - struct list_head active; + bool active_implicit; }; static void vmw_sou_destroy(struct vmw_screen_object_unit *sou) { - list_del_init(&sou->active); vmw_display_unit_cleanup(&sou->base); kfree(sou); } @@ -75,58 +70,31 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc) vmw_sou_destroy(vmw_crtc_to_sou(crtc)); } -static int vmw_sou_del_active(struct vmw_private *vmw_priv, +static void vmw_sou_del_active(struct vmw_private *vmw_priv, struct vmw_screen_object_unit *sou) { struct vmw_screen_object_display *ld = vmw_priv->sou_priv; - if (list_empty(&sou->active)) - return 0; - /* Must init otherwise list_empty(&sou->active) will not work. */ - list_del_init(&sou->active); - if (--(ld->num_active) == 0) { - BUG_ON(!ld->fb); - if (ld->fb->unpin) - ld->fb->unpin(ld->fb); - ld->fb = NULL; + if (sou->active_implicit) { + if (--(ld->num_implicit) == 0) + ld->implicit_fb = NULL; + sou->active_implicit = false; } - - return 0; } -static int vmw_sou_add_active(struct vmw_private *vmw_priv, +static void vmw_sou_add_active(struct vmw_private *vmw_priv, struct vmw_screen_object_unit *sou, struct vmw_framebuffer *vfb) { struct vmw_screen_object_display *ld = vmw_priv->sou_priv; - struct vmw_screen_object_unit *entry; - struct list_head *at; - - BUG_ON(!ld->num_active && ld->fb); - if (vfb != ld->fb) { - if (ld->fb && ld->fb->unpin) - ld->fb->unpin(ld->fb); - if (vfb->pin) - vfb->pin(vfb); - ld->fb = vfb; - } - - if (!list_empty(&sou->active)) - return 0; - at = &ld->active; - list_for_each_entry(entry, &ld->active, active) { - if (entry->base.unit > sou->base.unit) - break; + BUG_ON(!ld->num_implicit && ld->implicit_fb); - at = &entry->active; + if (!sou->active_implicit && sou->base.is_implicit) { + ld->implicit_fb = vfb; + sou->active_implicit = true; + ld->num_implicit++; } - - list_add(&sou->active, at); - - ld->num_active++; - - return 0; } /** @@ -164,8 +132,13 @@ static int vmw_sou_fifo_create(struct vmw_private *dev_priv, (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0); cmd->obj.size.width = mode->hdisplay; cmd->obj.size.height = mode->vdisplay; - cmd->obj.root.x = x; - cmd->obj.root.y = y; + if (sou->base.is_implicit) { + cmd->obj.root.x = x; + cmd->obj.root.y = y; + } else { + cmd->obj.root.x = sou->base.gui_x; + cmd->obj.root.y = sou->base.gui_y; + } /* Ok to assume that buffer is pinned in vram */ vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr); @@ -312,10 +285,11 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) } /* sou only supports one fb active at the time */ - if (dev_priv->sou_priv->fb && vfb && - !(dev_priv->sou_priv->num_active == 1 && - !list_empty(&sou->active)) && - dev_priv->sou_priv->fb != vfb) { + if (sou->base.is_implicit && + dev_priv->sou_priv->implicit_fb && vfb && + !(dev_priv->sou_priv->num_implicit == 1 && + sou->active_implicit) && + dev_priv->sou_priv->implicit_fb != vfb) { DRM_ERROR("Multiple framebuffers not supported\n"); return -EINVAL; } @@ -471,19 +445,20 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) encoder = &sou->base.encoder; connector = &sou->base.connector; - INIT_LIST_HEAD(&sou->active); + sou->active_implicit = false; sou->base.pref_active = (unit == 0); sou->base.pref_width = 800; sou->base.pref_height = 600; sou->base.pref_mode = NULL; + sou->base.is_implicit = true; drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + DRM_MODE_CONNECTOR_VIRTUAL); connector->status = vmw_du_connector_detect(connector, true); drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, - DRM_MODE_ENCODER_LVDS); + DRM_MODE_ENCODER_VIRTUAL); drm_mode_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; @@ -520,10 +495,8 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) if (unlikely(!dev_priv->sou_priv)) goto err_no_mem; - INIT_LIST_HEAD(&dev_priv->sou_priv->active); - dev_priv->sou_priv->num_active = 0; - dev_priv->sou_priv->last_num_active = 0; - dev_priv->sou_priv->fb = NULL; + dev_priv->sou_priv->num_implicit = 0; + dev_priv->sou_priv->implicit_fb = NULL; ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); if (unlikely(ret != 0)) @@ -558,9 +531,6 @@ int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv) drm_vblank_cleanup(dev); - if (!list_empty(&dev_priv->sou_priv->active)) - DRM_ERROR("Still have active outputs when unloading driver"); - kfree(dev_priv->sou_priv); return 0; diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 8cdb4b45b30a..299d23871122 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -183,9 +183,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) table = macbookair_fn_keys; - else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI && - hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) - table = macbookair_fn_keys; else if (hid->product < 0x21d || hid->product >= 0x300) table = powerbook_fn_keys; else diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c index 3bdb4500f95e..5be858dd9a15 100644 --- a/drivers/hid/hid-axff.c +++ b/drivers/hid/hid-axff.c @@ -31,6 +31,7 @@ #include <linux/slab.h> #include <linux/usb.h> #include <linux/hid.h> +#include <linux/module.h> #include "hid-ids.h" diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 9a243ca96e6d..ee80d733801d 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -31,6 +31,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/sched.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/poll.h> diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c index 61eece47204d..e832f44ae383 100644 --- a/drivers/hid/hid-dr.c +++ b/drivers/hid/hid-dr.c @@ -31,6 +31,7 @@ #include <linux/slab.h> #include <linux/usb.h> #include <linux/hid.h> +#include <linux/module.h> #include "hid-ids.h" diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c index a5dc13fe367b..9bdde867a02f 100644 --- a/drivers/hid/hid-emsff.c +++ b/drivers/hid/hid-emsff.c @@ -24,6 +24,7 @@ #include <linux/hid.h> #include <linux/input.h> #include <linux/usb.h> +#include <linux/module.h> #include "hid-ids.h" #include "usbhid/usbhid.h" diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c index 279ba530003c..f1e1bcf67427 100644 --- a/drivers/hid/hid-gaff.c +++ b/drivers/hid/hid-gaff.c @@ -31,6 +31,7 @@ #include <linux/slab.h> #include <linux/usb.h> #include <linux/hid.h> +#include <linux/module.h> #include "hid-ids.h" #ifdef CONFIG_GREENASIA_FF diff --git a/drivers/hid/hid-holtekff.c b/drivers/hid/hid-holtekff.c index 91e3a032112b..4e7542151e22 100644 --- a/drivers/hid/hid-holtekff.c +++ b/drivers/hid/hid-holtekff.c @@ -25,6 +25,7 @@ #include <linux/hid.h> #include <linux/input.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/usb.h> diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 1782693819f3..01e7d2cd7c26 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -36,6 +36,7 @@ #include <linux/completion.h> #include <linux/uaccess.h> +#include <linux/module.h> #define PICOLCD_NAME "PicoLCD (graphic)" diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c index 06e5300d43d2..070f93a5c11b 100644 --- a/drivers/hid/hid-pl.c +++ b/drivers/hid/hid-pl.c @@ -40,6 +40,7 @@ #include <linux/input.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/usb.h> #include <linux/hid.h> diff --git a/drivers/hid/hid-roccat-common.c b/drivers/hid/hid-roccat-common.c index edf898dee28b..b07e7f96a358 100644 --- a/drivers/hid/hid-roccat-common.c +++ b/drivers/hid/hid-roccat-common.c @@ -13,6 +13,7 @@ #include <linux/hid.h> #include <linux/slab.h> +#include <linux/module.h> #include "hid-roccat-common.h" static inline uint16_t roccat_common_feature_report(uint8_t report_id) diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c index 56ce12c23b02..b685b04dbf9d 100644 --- a/drivers/hid/hid-roccat.c +++ b/drivers/hid/hid-roccat.c @@ -27,6 +27,7 @@ #include <linux/poll.h> #include <linux/sched.h> #include <linux/hid-roccat.h> +#include <linux/module.h> #define ROCCAT_FIRST_MINOR 0 #define ROCCAT_MAX_DEVICES 8 diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c index 670da9109f86..4b1448613ea6 100644 --- a/drivers/hid/hid-sjoy.c +++ b/drivers/hid/hid-sjoy.c @@ -30,6 +30,7 @@ #include <linux/slab.h> #include <linux/usb.h> #include <linux/hid.h> +#include <linux/module.h> #include "hid-ids.h" #ifdef CONFIG_SMARTJOYPLUS_FF diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index 575862b0688e..83a933b9c2e9 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -31,6 +31,7 @@ #include <linux/input.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/module.h> #include "hid-ids.h" diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c index f31fab012f2f..f6ba81df71bd 100644 --- a/drivers/hid/hid-zpff.c +++ b/drivers/hid/hid-zpff.c @@ -25,6 +25,7 @@ #include <linux/input.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/module.h> #include "hid-ids.h" diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 4ea464151c3b..5028d60a22a1 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -16,6 +16,7 @@ */ #include <linux/hid.h> +#include <linux/export.h> #include <linux/slab.h> #include "../hid-ids.h" diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index ce18c046f728..104b3767516c 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -60,14 +60,13 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); #ifdef CONFIG_SMP #define TO_PHYS_ID(cpu) cpu_data(cpu).phys_proc_id #define TO_CORE_ID(cpu) cpu_data(cpu).cpu_core_id -#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) #define for_each_sibling(i, cpu) for_each_cpu(i, cpu_sibling_mask(cpu)) #else #define TO_PHYS_ID(cpu) (cpu) #define TO_CORE_ID(cpu) (cpu) -#define TO_ATTR_NO(cpu) (cpu) #define for_each_sibling(i, cpu) for (i = 0; false; ) #endif +#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) /* * Per-Core Temperature Data diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index 27a62711e0a6..3cd07bf42dca 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -6,6 +6,7 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/of_device.h> #include <linux/io.h> #include <linux/hwmon.h> diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 483cb268781e..93f5fc7d6059 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1835,12 +1835,15 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data, diode = 0x70; } for (i = 0; i < 3; i++) { - const char *label = data->temp_label[data->temp_src[i]]; + const char *label = NULL; + + if (data->temp_label) + label = data->temp_label[data->temp_src[i]]; /* Digital source overrides analog type */ - if (strncmp(label, "PECI", 4) == 0) + if (label && strncmp(label, "PECI", 4) == 0) data->temp_type[i] = 6; - else if (strncmp(label, "AMD", 3) == 0) + else if (label && strncmp(label, "AMD", 3) == 0) data->temp_type[i] = 5; else if ((tmp & (0x02 << i))) data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3; diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index b73da6cd6f91..632e088760a3 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -3,6 +3,7 @@ * It does not support slave mode, the register slightly moved. This PCI * device provides three bars, every contains a single I2C controller. */ +#include <linux/module.h> #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/i2c/pxa-i2c.h> diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index c418c41eff3d..a67132b2e092 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -17,6 +17,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/module.h> #include <asm/clock.h> #include <asm/i2c-sh7760.h> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index b0505309faa7..46b6500c5478 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/i2c-tegra.h> #include <linux/of_i2c.h> +#include <linux/module.h> #include <asm/unaligned.h> diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index 3ca2e012e789..10274ffb66d7 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/i2c.h> #include <linux/slab.h> +#include <linux/export.h> #include <linux/rwsem.h> #include "i2c-core.h" diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c index ab4f169d0837..b1d38590ac01 100644 --- a/drivers/ide/buddha.c +++ b/drivers/ide/buddha.c @@ -23,6 +23,7 @@ #include <linux/zorro.h> #include <linux/ide.h> #include <linux/init.h> +#include <linux/module.h> #include <asm/amigahw.h> #include <asm/amigaints.h> diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c index cb10201a15ed..a81bd7575792 100644 --- a/drivers/ide/cmd640.c +++ b/drivers/ide/cmd640.c @@ -105,6 +105,7 @@ #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> +#include <linux/module.h> #include <asm/io.h> diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 2af8cb460a3b..f22edc66b030 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -17,6 +17,7 @@ #include <linux/ide.h> #include <linux/pci.h> #include <linux/dmi.h> +#include <linux/module.h> #include <acpi/acpi_bus.h> diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 6f218e014e99..fac3d9da2e07 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -5,6 +5,7 @@ #include <linux/kernel.h> #include <linux/cdrom.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/ide.h> #include <linux/scatterlist.h> #include <linux/gfp.h> diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c index f9bbd904eae7..8b570a17bcd9 100644 --- a/drivers/ide/ide-disk_proc.c +++ b/drivers/ide/ide-disk_proc.c @@ -1,6 +1,7 @@ #include <linux/kernel.h> #include <linux/ide.h> #include <linux/slab.h> +#include <linux/export.h> #include <linux/seq_file.h> #include "ide-disk.h" diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c index e4cdf78cc3e9..289d16c87b8f 100644 --- a/drivers/ide/ide-dma-sff.c +++ b/drivers/ide/ide-dma-sff.c @@ -1,5 +1,6 @@ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/ide.h> #include <linux/scatterlist.h> #include <linux/dma-mapping.h> diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index d4136908f916..17a65ac56491 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -31,6 +31,7 @@ #include <linux/types.h> #include <linux/gfp.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/ide.h> #include <linux/scatterlist.h> #include <linux/dma-mapping.h> diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c index c0aa93fb7a60..32970664c275 100644 --- a/drivers/ide/ide-eh.c +++ b/drivers/ide/ide-eh.c @@ -1,5 +1,6 @@ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/ide.h> #include <linux/delay.h> diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c index d711d9b883de..1600720f3e86 100644 --- a/drivers/ide/ide-floppy_proc.c +++ b/drivers/ide/ide-floppy_proc.c @@ -1,4 +1,5 @@ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/ide.h> #include <linux/seq_file.h> diff --git a/drivers/ide/ide-io-std.c b/drivers/ide/ide-io-std.c index 46721c454518..19763977568c 100644 --- a/drivers/ide/ide-io-std.c +++ b/drivers/ide/ide-io-std.c @@ -1,5 +1,6 @@ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/ide.h> #if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \ diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c index 9965ecd5078c..4d19eb9772a1 100644 --- a/drivers/ide/ide-ioctls.c +++ b/drivers/ide/ide-ioctls.c @@ -2,6 +2,7 @@ * IDE ioctls handling. */ +#include <linux/export.h> #include <linux/hdreg.h> #include <linux/ide.h> #include <linux/slab.h> diff --git a/drivers/ide/ide-legacy.c b/drivers/ide/ide-legacy.c index b9654a7bb7be..30fe3630734f 100644 --- a/drivers/ide/ide-legacy.c +++ b/drivers/ide/ide-legacy.c @@ -1,4 +1,5 @@ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/ide.h> static void ide_legacy_init_one(struct ide_hw **hws, struct ide_hw *hw, diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index e386a32dc9ba..d9c9829c8b20 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -1,6 +1,7 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/ide.h> #include <linux/bitops.h> diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c index 017b1df3b805..e5f3db831373 100644 --- a/drivers/ide/ide-pnp.c +++ b/drivers/ide/ide-pnp.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/pnp.h> #include <linux/ide.h> +#include <linux/module.h> #define DRV_NAME "ide-pnp" diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 600c89a3d137..5bc2839ebcfd 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -11,6 +11,7 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/errno.h> diff --git a/drivers/ide/ide-xfer-mode.c b/drivers/ide/ide-xfer-mode.c index 5fc8d5c17de9..eb421883c16d 100644 --- a/drivers/ide/ide-xfer-mode.c +++ b/drivers/ide/ide-xfer-mode.c @@ -1,6 +1,7 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/ide.h> #include <linux/bitops.h> diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c index 505ec43e5606..adc5fe9daafc 100644 --- a/drivers/ide/macide.c +++ b/drivers/ide/macide.c @@ -17,6 +17,7 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/ide.h> +#include <linux/module.h> #include <asm/macintosh.h> #include <asm/macints.h> diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c index 1db7c4368dbf..e944c7f705f7 100644 --- a/drivers/ide/pmac.c +++ b/drivers/ide/pmac.c @@ -28,6 +28,7 @@ #include <linux/delay.h> #include <linux/ide.h> #include <linux/notifier.h> +#include <linux/module.h> #include <linux/reboot.h> #include <linux/pci.h> #include <linux/adb.h> diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c index 90786083b439..ecd0a69245f6 100644 --- a/drivers/ide/q40ide.c +++ b/drivers/ide/q40ide.c @@ -15,6 +15,7 @@ #include <linux/interrupt.h> #include <linux/blkdev.h> #include <linux/ide.h> +#include <linux/module.h> #include <asm/ide.h> diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index ab3db61d2ba0..34a5e5223d50 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -8,6 +8,7 @@ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/pci.h> #include <linux/init.h> #include <linux/interrupt.h> diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c index e444d24934b3..4799d5c384e7 100644 --- a/drivers/ide/tc86c001.c +++ b/drivers/ide/tc86c001.c @@ -10,6 +10,7 @@ #include <linux/types.h> #include <linux/pci.h> #include <linux/ide.h> +#include <linux/module.h> #define DRV_NAME "tc86c001" diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index a46dddf61078..5d2f8e13cf0e 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -61,6 +61,7 @@ #include <linux/sched.h> #include <linux/notifier.h> #include <linux/cpu.h> +#include <linux/module.h> #include <asm/mwait.h> #include <asm/msr.h> @@ -81,7 +82,8 @@ static unsigned int mwait_substates; static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; -static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); +static int intel_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index); static struct cpuidle_state *cpuidle_state_table; @@ -109,7 +111,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C1 */ .name = "C1-NHM", .desc = "MWAIT 0x00", - .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 3, .target_residency = 6, @@ -117,7 +118,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C2 */ .name = "C3-NHM", .desc = "MWAIT 0x10", - .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 20, .target_residency = 80, @@ -125,7 +125,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C3 */ .name = "C6-NHM", .desc = "MWAIT 0x20", - .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 200, .target_residency = 800, @@ -137,7 +136,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C1 */ .name = "C1-SNB", .desc = "MWAIT 0x00", - .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 1, .target_residency = 1, @@ -145,7 +143,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C2 */ .name = "C3-SNB", .desc = "MWAIT 0x10", - .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 80, .target_residency = 211, @@ -153,7 +150,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C3 */ .name = "C6-SNB", .desc = "MWAIT 0x20", - .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 104, .target_residency = 345, @@ -161,7 +157,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C4 */ .name = "C7-SNB", .desc = "MWAIT 0x30", - .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 109, .target_residency = 345, @@ -173,7 +168,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C1 */ .name = "C1-ATM", .desc = "MWAIT 0x00", - .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 1, .target_residency = 4, @@ -181,7 +175,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C2 */ .name = "C2-ATM", .desc = "MWAIT 0x10", - .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 20, .target_residency = 80, @@ -190,7 +183,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C4 */ .name = "C4-ATM", .desc = "MWAIT 0x30", - .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 100, .target_residency = 400, @@ -199,23 +191,55 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C6 */ .name = "C6-ATM", .desc = "MWAIT 0x52", - .driver_data = (void *) 0x52, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 140, .target_residency = 560, .enter = &intel_idle }, }; +static int get_driver_data(int cstate) +{ + int driver_data; + switch (cstate) { + + case 1: /* MWAIT C1 */ + driver_data = 0x00; + break; + case 2: /* MWAIT C2 */ + driver_data = 0x10; + break; + case 3: /* MWAIT C3 */ + driver_data = 0x20; + break; + case 4: /* MWAIT C4 */ + driver_data = 0x30; + break; + case 5: /* MWAIT C5 */ + driver_data = 0x40; + break; + case 6: /* MWAIT C6 */ + driver_data = 0x52; + break; + default: + driver_data = 0x00; + } + return driver_data; +} + /** * intel_idle * @dev: cpuidle_device - * @state: cpuidle state + * @drv: cpuidle driver + * @index: index of cpuidle state * */ -static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) +static int intel_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { unsigned long ecx = 1; /* break on interrupt flag */ - unsigned long eax = (unsigned long)cpuidle_get_statedata(state); + struct cpuidle_state *state = &drv->states[index]; + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); unsigned int cstate; ktime_t kt_before, kt_after; s64 usec_delta; @@ -256,7 +280,10 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) if (!(lapic_timer_reliable_states & (1 << (cstate)))) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); - return usec_delta; + /* Update cpuidle counters */ + dev->last_residency = (int)usec_delta; + + return index; } static void __setup_broadcast_timer(void *arg) @@ -397,6 +424,60 @@ static void intel_idle_cpuidle_devices_uninit(void) return; } /* + * intel_idle_cpuidle_driver_init() + * allocate, initialize cpuidle_states + */ +static int intel_idle_cpuidle_driver_init(void) +{ + int cstate; + struct cpuidle_driver *drv = &intel_idle_driver; + + drv->state_count = 1; + + for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { + int num_substates; + + if (cstate > max_cstate) { + printk(PREFIX "max_cstate %d reached\n", + max_cstate); + break; + } + + /* does the state exist in CPUID.MWAIT? */ + num_substates = (mwait_substates >> ((cstate) * 4)) + & MWAIT_SUBSTATE_MASK; + if (num_substates == 0) + continue; + /* is the state not enabled? */ + if (cpuidle_state_table[cstate].enter == NULL) { + /* does the driver not know about the state? */ + if (*cpuidle_state_table[cstate].name == '\0') + pr_debug(PREFIX "unaware of model 0x%x" + " MWAIT %d please" + " contact lenb@kernel.org", + boot_cpu_data.x86_model, cstate); + continue; + } + + if ((cstate > 2) && + !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) + mark_tsc_unstable("TSC halts in idle" + " states deeper than C2"); + + drv->states[drv->state_count] = /* structure copy */ + cpuidle_state_table[cstate]; + + drv->state_count += 1; + } + + if (auto_demotion_disable_flags) + smp_call_function(auto_demotion_disable, NULL, 1); + + return 0; +} + + +/* * intel_idle_cpuidle_devices_init() * allocate, initialize, register cpuidle_devices */ @@ -430,22 +511,11 @@ static int intel_idle_cpuidle_devices_init(void) continue; /* is the state not enabled? */ if (cpuidle_state_table[cstate].enter == NULL) { - /* does the driver not know about the state? */ - if (*cpuidle_state_table[cstate].name == '\0') - pr_debug(PREFIX "unaware of model 0x%x" - " MWAIT %d please" - " contact lenb@kernel.org", - boot_cpu_data.x86_model, cstate); continue; } - if ((cstate > 2) && - !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) - mark_tsc_unstable("TSC halts in idle" - " states deeper than C2"); - - dev->states[dev->state_count] = /* structure copy */ - cpuidle_state_table[cstate]; + dev->states_usage[dev->state_count].driver_data = + (void *)get_driver_data(cstate); dev->state_count += 1; } @@ -458,8 +528,6 @@ static int intel_idle_cpuidle_devices_init(void) return -EIO; } } - if (auto_demotion_disable_flags) - smp_call_function(auto_demotion_disable, NULL, 1); return 0; } @@ -477,6 +545,7 @@ static int __init intel_idle_init(void) if (retval) return retval; + intel_idle_cpuidle_driver_init(); retval = cpuidle_register_driver(&intel_idle_driver); if (retval) { printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 236ad9a89c0a..691276bafd78 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -37,6 +37,7 @@ #include <linux/inetdevice.h> #include <linux/slab.h> #include <linux/workqueue.h> +#include <linux/module.h> #include <net/arp.h> #include <net/neighbour.h> #include <net/route.h> diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 4104ea2427c2..8b72f39202fb 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -36,6 +36,7 @@ #include <linux/completion.h> #include <linux/dma-mapping.h> #include <linux/device.h> +#include <linux/module.h> #include <linux/err.h> #include <linux/idr.h> #include <linux/interrupt.h> diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 872b1842598a..75ff821c0af0 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -41,6 +41,7 @@ #include <linux/idr.h> #include <linux/inetdevice.h> #include <linux/slab.h> +#include <linux/module.h> #include <net/tcp.h> #include <net/ipv6.h> diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index 4507043d24c8..176c8f90f2bb 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -33,6 +33,7 @@ #include <linux/errno.h> #include <linux/spinlock.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/jhash.h> #include <linux/kthread.h> diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index a9c042345c6f..1a696f76b616 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -45,6 +45,7 @@ #include <linux/workqueue.h> #include <linux/completion.h> #include <linux/slab.h> +#include <linux/module.h> #include <rdma/iw_cm.h> #include <rdma/ib_addr.h> diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 056389229ea7..2fe428bba54c 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -35,6 +35,7 @@ */ #include <linux/dma-mapping.h> #include <linux/slab.h> +#include <linux/module.h> #include <rdma/ib_cache.h> #include "mad_priv.h" diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 68b4162fd9d2..d2360a8ef0b2 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -34,6 +34,7 @@ #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/interrupt.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/bitops.h> #include <linux/random.h> diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c index 9227f4acd79c..d1c8196d15d7 100644 --- a/drivers/infiniband/core/netlink.c +++ b/drivers/infiniband/core/netlink.c @@ -32,6 +32,7 @@ #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ +#include <linux/export.h> #include <net/netlink.h> #include <net/net_namespace.h> #include <net/sock.h> diff --git a/drivers/infiniband/core/packer.c b/drivers/infiniband/core/packer.c index 019bd4b0863e..1b65986c0be3 100644 --- a/drivers/infiniband/core/packer.c +++ b/drivers/infiniband/core/packer.c @@ -31,6 +31,7 @@ * SOFTWARE. */ +#include <linux/export.h> #include <linux/string.h> #include <rdma/ib_pack.h> diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 2b59b72b57f9..c61bca30fd2d 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -35,6 +35,7 @@ #include "core_priv.h" #include <linux/slab.h> +#include <linux/stat.h> #include <linux/string.h> #include <rdma/ib_mad.h> diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index b69307f4f6d0..b37b0c02a7b9 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -41,6 +41,7 @@ #include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/sysctl.h> +#include <linux/module.h> #include <rdma/rdma_user_cm.h> #include <rdma/ib_marshall.h> diff --git a/drivers/infiniband/core/ud_header.c b/drivers/infiniband/core/ud_header.c index 9b737ff133e2..72feee620ebf 100644 --- a/drivers/infiniband/core/ud_header.c +++ b/drivers/infiniband/core/ud_header.c @@ -33,6 +33,7 @@ #include <linux/errno.h> #include <linux/string.h> +#include <linux/export.h> #include <linux/if_ether.h> #include <rdma/ib_pack.h> diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 9155f91d66bf..71f0c0f7df94 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -35,6 +35,7 @@ #include <linux/mm.h> #include <linux/dma-mapping.h> #include <linux/sched.h> +#include <linux/export.h> #include <linux/hugetlb.h> #include <linux/dma-attrs.h> #include <linux/slab.h> diff --git a/drivers/infiniband/core/uverbs_marshall.c b/drivers/infiniband/core/uverbs_marshall.c index 1b1146f87124..e7bee46868d1 100644 --- a/drivers/infiniband/core/uverbs_marshall.c +++ b/drivers/infiniband/core/uverbs_marshall.c @@ -30,6 +30,7 @@ * SOFTWARE. */ +#include <linux/export.h> #include <rdma/ib_marshall.h> void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst, diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 42517500b223..602b1bd723a9 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -38,6 +38,7 @@ #include <linux/errno.h> #include <linux/err.h> +#include <linux/export.h> #include <linux/string.h> #include <linux/slab.h> diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index d6ccc7e84802..5f940aeaab1e 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -29,6 +29,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +#include <linux/module.h> + #include "iw_cxgb4.h" static int ocqp_support = 1; diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index daef61d5e5bb..714293b78518 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c @@ -45,6 +45,7 @@ #include <linux/pci.h> #include <linux/vmalloc.h> #include <linux/fs.h> +#include <linux/export.h> #include <asm/uaccess.h> #include "ipath_kernel.h" diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index be24ac726114..bfca37b2432f 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -41,6 +41,7 @@ #include <linux/vmalloc.h> #include <linux/bitmap.h> #include <linux/slab.h> +#include <linux/module.h> #include "ipath_kernel.h" #include "ipath_verbs.h" diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 8697eca14356..736d9edbdbe7 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -35,6 +35,7 @@ #include <linux/poll.h> #include <linux/cdev.h> #include <linux/swap.h> +#include <linux/export.h> #include <linux/vmalloc.h> #include <linux/slab.h> #include <linux/highmem.h> diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 824a4d508836..49b09c697c7c 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -33,6 +33,7 @@ #include <linux/pci.h> #include <linux/netdevice.h> +#include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/stat.h> #include <linux/vmalloc.h> diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c index 8991677e9a08..75558f33f1cb 100644 --- a/drivers/infiniband/hw/ipath/ipath_sysfs.c +++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c @@ -32,6 +32,7 @@ */ #include <linux/ctype.h> +#include <linux/stat.h> #include "ipath_kernel.h" #include "ipath_verbs.h" diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index dd7f26d04d46..439c35d4a669 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -35,6 +35,7 @@ #include <rdma/ib_user_verbs.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/utsname.h> #include <linux/rculist.h> diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index e4a08c2819e4..712d2a30fbe5 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c @@ -31,6 +31,7 @@ */ #include <linux/jiffies.h> +#include <linux/module.h> #include <linux/timer.h> #include <linux/workqueue.h> diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 3082b3b3d620..9d3e5c1ac60e 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -36,6 +36,7 @@ #include <linux/pci.h> #include <linux/errno.h> #include <linux/sched.h> +#include <linux/module.h> #include <linux/slab.h> #include <asm/io.h> #include <rdma/ib_mad.h> diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index cb9a0b976804..5b71d43bd89c 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -40,7 +40,9 @@ #include <linux/sched.h> #include <linux/slab.h> +#include <linux/stat.h> #include <linux/mm.h> +#include <linux/export.h> #include "mthca_dev.h" #include "mthca_cmd.h" diff --git a/drivers/infiniband/hw/qib/qib_diag.c b/drivers/infiniband/hw/qib/qib_diag.c index 204c4dd9dce0..9892456a4348 100644 --- a/drivers/infiniband/hw/qib/qib_diag.c +++ b/drivers/infiniband/hw/qib/qib_diag.c @@ -46,6 +46,7 @@ #include <linux/pci.h> #include <linux/poll.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <linux/fs.h> #include <linux/uaccess.h> diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c index 9a9047f385ae..c90a55f4120f 100644 --- a/drivers/infiniband/hw/qib/qib_driver.c +++ b/drivers/infiniband/hw/qib/qib_driver.c @@ -37,6 +37,7 @@ #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> +#include <linux/module.h> #include "qib.h" diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 77633666f81c..574600ef5b42 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -43,6 +43,7 @@ #include <linux/jiffies.h> #include <asm/pgtable.h> #include <linux/delay.h> +#include <linux/export.h> #include "qib.h" #include "qib_common.h" diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 3f1d562ba898..439d3c503cd5 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -39,6 +39,7 @@ #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/io.h> #include <rdma/ib_verbs.h> diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index efd0a110091f..5bd2162b95dc 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -40,6 +40,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/jiffies.h> +#include <linux/module.h> #include <rdma/ib_verbs.h> #include <rdma/ib_smi.h> diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index b093a0b53b2f..58b0f8ad4a29 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -37,6 +37,7 @@ #include <linux/vmalloc.h> #include <linux/delay.h> #include <linux/idr.h> +#include <linux/module.h> #include "qib.h" #include "qib_common.h" diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c index 4426782ad288..97a8bdf68e60 100644 --- a/drivers/infiniband/hw/qib/qib_pcie.c +++ b/drivers/infiniband/hw/qib/qib_pcie.c @@ -35,6 +35,7 @@ #include <linux/delay.h> #include <linux/vmalloc.h> #include <linux/aer.h> +#include <linux/module.h> #include "qib.h" diff --git a/drivers/infiniband/hw/qib/qib_sd7220.c b/drivers/infiniband/hw/qib/qib_sd7220.c index e9f9f8bc3204..de1a4b2f33c0 100644 --- a/drivers/infiniband/hw/qib/qib_sd7220.c +++ b/drivers/infiniband/hw/qib/qib_sd7220.c @@ -38,6 +38,7 @@ #include <linux/pci.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/firmware.h> #include "qib.h" diff --git a/drivers/infiniband/hw/qib/qib_sdma.c b/drivers/infiniband/hw/qib/qib_sdma.c index cad44491320b..12a9604310d7 100644 --- a/drivers/infiniband/hw/qib/qib_sdma.c +++ b/drivers/infiniband/hw/qib/qib_sdma.c @@ -32,6 +32,7 @@ #include <linux/spinlock.h> #include <linux/netdevice.h> +#include <linux/moduleparam.h> #include "qib.h" #include "qib_common.h" diff --git a/drivers/infiniband/hw/qib/qib_tx.c b/drivers/infiniband/hw/qib/qib_tx.c index 7f36454c225e..1bf626c40172 100644 --- a/drivers/infiniband/hw/qib/qib_tx.c +++ b/drivers/infiniband/hw/qib/qib_tx.c @@ -36,6 +36,7 @@ #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> +#include <linux/moduleparam.h> #include "qib.h" diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 9627cb737125..a894762da462 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -35,6 +35,7 @@ #include <rdma/ib_mad.h> #include <rdma/ib_user_verbs.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/utsname.h> #include <linux/rculist.h> #include <linux/mm.h> diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 231c2f2f52f8..014504d8e43c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -37,6 +37,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/vmalloc.h> +#include <linux/moduleparam.h> #include "ipoib.h" diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c index 0e2fe4631ba8..50061854616e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c @@ -37,6 +37,7 @@ struct file_operations; #include <linux/debugfs.h> +#include <linux/export.h> #include "ipoib.h" diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 2b060f45bec3..0ef9af94997d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -34,6 +34,7 @@ */ #include <linux/delay.h> +#include <linux/moduleparam.h> #include <linux/dma-mapping.h> #include <linux/slab.h> diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index ecea4fe1ed00..1b7a97686356 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -34,6 +34,7 @@ #include <linux/skbuff.h> #include <linux/rtnetlink.h> +#include <linux/moduleparam.h> #include <linux/ip.h> #include <linux/in.h> #include <linux/igmp.h> diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index c42b8f390c0b..7e7373a700e6 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -57,6 +57,7 @@ #include <linux/scatterlist.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/module.h> #include <net/sock.h> diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c index 1accb89ae66f..e46a86776a6b 100644 --- a/drivers/input/input-compat.c +++ b/drivers/input/input-compat.c @@ -8,6 +8,7 @@ * the Free Software Foundation. */ +#include <linux/export.h> #include <asm/uaccess.h> #include "input-compat.h" diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index 9150ee78e00a..f658086fbbe0 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -9,6 +9,7 @@ */ #include <linux/input/mt.h> +#include <linux/export.h> #include <linux/slab.h> #define TRKID_SGN ((TRKID_MAX + 1) >> 1) diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index b253973881b8..7dfe1009fae0 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/workqueue.h> +#include <linux/module.h> #include <linux/input-polldev.h> MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index f6732b57ca07..6d6e7418dc21 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -30,6 +30,7 @@ #include <linux/delay.h> #include <linux/input/as5011.h> #include <linux/slab.h> +#include <linux/module.h> #define DRIVER_DESC "Driver for Austria Microsystems AS5011 joystick" #define MODULE_DEVICE_ALIAS "as5011" diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 6e0f23091360..fcdec5e2b297 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -18,6 +18,7 @@ #include <linux/input.h> #include <linux/slab.h> #include <linux/clk.h> +#include <linux/module.h> #include <plat/ske.h> diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c index 1c58681de81f..66e55e5cfdd6 100644 --- a/drivers/input/keyboard/tnetv107x-keypad.c +++ b/drivers/input/keyboard/tnetv107x-keypad.c @@ -24,6 +24,7 @@ #include <linux/io.h> #include <linux/clk.h> #include <linux/input/matrix_keypad.h> +#include <linux/module.h> #define BITS(x) (BIT(x) - 1) diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c index ca42c7d2a3c7..0ac75bbad4d6 100644 --- a/drivers/input/misc/ad714x.c +++ b/drivers/input/misc/ad714x.c @@ -12,6 +12,7 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/input/ad714x.h> +#include <linux/module.h> #include "ad714x.h" #define AD714X_PWR_CTRL 0x0 diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index 144ddbdeb9b3..09244804fb97 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/input/adxl34x.h> +#include <linux/module.h> #include "adxl34x.h" diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index 1de58e8a1b71..8d345e87075e 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -11,6 +11,7 @@ #include <linux/usb/input.h> #include <linux/slab.h> +#include <linux/module.h> #define DRIVER_DESC "ATI/Philips USB RF remote driver" #define DRIVER_VERSION "0.3" diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c index 1633b6342267..80793f1608eb 100644 --- a/drivers/input/misc/cma3000_d0x.c +++ b/drivers/input/misc/cma3000_d0x.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/input.h> #include <linux/input/cma3000.h> +#include <linux/module.h> #include "cma3000_d0x.h" diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index 19af682c24fb..7283dd2a1ad3 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -17,6 +17,7 @@ #include <linux/interrupt.h> #include <linux/i2c/dm355evm_msp.h> +#include <linux/module.h> /* diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index fdb6a3976f94..75fb040a3435 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -15,6 +15,7 @@ #include <linux/input.h> #include <linux/input/sparse-keymap.h> +#include <linux/module.h> #include <linux/slab.h> MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index 714d4e0f9f95..400131df677b 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -45,6 +45,7 @@ #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/spi/ad7877.h> +#include <linux/module.h> #include <asm/irq.h> #define TS_PEN_UP_TIMEOUT msecs_to_jiffies(100) diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index ddf732f3cafc..b1643c8fa7c9 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -9,6 +9,7 @@ #include <linux/input.h> /* BUS_SPI */ #include <linux/pm.h> #include <linux/spi/spi.h> +#include <linux/module.h> #include "ad7879.h" diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 131f9d1c921b..3b2e9ed2aeec 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -33,6 +33,7 @@ #include <linux/gpio.h> #include <linux/spi/ad7879.h> +#include <linux/module.h> #include "ad7879.h" #define AD7879_REG_ZEROS 0 diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index d507b9b67806..de31ec6fe9e4 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -31,6 +31,7 @@ #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> #include <linux/regulator/consumer.h> +#include <linux/module.h> #include <asm/irq.h> /* diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index 1507ce108d5b..902c7214e887 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -13,6 +13,7 @@ #include <linux/input/bu21013.h> #include <linux/slab.h> #include <linux/regulator/consumer.h> +#include <linux/module.h> #define PEN_DOWN_INTR 0 #define MAX_FINGERS 2 diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index bb161d2fa03c..c0c7820d4c46 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -24,6 +24,7 @@ #include <linux/init.h> #include <linux/bitmap.h> #include <linux/debugfs.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/irq.h> #include <linux/interrupt.h> diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c index ea2dff602e49..8d51cd1bf674 100644 --- a/drivers/isdn/capi/kcapi_proc.c +++ b/drivers/isdn/capi/kcapi_proc.c @@ -14,6 +14,7 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/init.h> +#include <linux/export.h> static char *state2str(unsigned short state) { diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index c3b1dc3a13a0..fddae72e3f98 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -16,6 +16,7 @@ #include "gigaset.h" #include <linux/crc-ccitt.h> #include <linux/bitrev.h> +#include <linux/export.h> /* check if byte must be stuffed/escaped * I'm not sure which data should be encoded. diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 658e75f18d05..6d5ceeece9f2 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -17,6 +17,7 @@ #include <linux/isdn/capilli.h> #include <linux/isdn/capicmd.h> #include <linux/isdn/capiutil.h> +#include <linux/export.h> /* missing from kernelcapi.h */ #define CapiNcpiNotSupportedByProtocol 0x0001 diff --git a/drivers/isdn/gigaset/dummyll.c b/drivers/isdn/gigaset/dummyll.c index bd0b1eaa7572..19b1c779d50f 100644 --- a/drivers/isdn/gigaset/dummyll.c +++ b/drivers/isdn/gigaset/dummyll.c @@ -11,6 +11,7 @@ * ===================================================================== */ +#include <linux/export.h> #include "gigaset.h" void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index ba74646cf0e4..6d12623c1db0 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -13,6 +13,7 @@ * ===================================================================== */ +#include <linux/export.h> #include "gigaset.h" /* ========================================================== */ diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 9bec8b969964..04231cb2f031 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -15,6 +15,7 @@ #include "gigaset.h" #include <linux/isdnif.h> +#include <linux/export.h> #define SBUFSIZE 4096 /* sk_buff payload size */ #define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index e35058bcd7b9..ee0a549a933a 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -14,6 +14,7 @@ #include "gigaset.h" #include <linux/gigaset_dev.h> #include <linux/tty_flip.h> +#include <linux/module.h> /*** our ioctls ***/ diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index d13fa5b119f5..7034af28d464 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -29,6 +29,7 @@ #include <linux/delay.h> #include <linux/vmalloc.h> #include <linux/mISDNhw.h> +#include <linux/module.h> #include "isar.h" #define ISAR_REV "2.1" diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index e5546cb3ac69..2c26b64ebbea 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -750,6 +750,7 @@ isdn_tty_modem_hup(modem_info * info, int local) * supplementary service (CAPI 2.0 part III) */ #include <linux/isdn/capicmd.h> +#include <linux/module.h> int isdn_tty_capi_facility(capi_msg *cm) { diff --git a/drivers/isdn/mISDN/clock.c b/drivers/isdn/mISDN/clock.c index 1fa629b3b940..7418f2d811d8 100644 --- a/drivers/isdn/mISDN/clock.c +++ b/drivers/isdn/mISDN/clock.c @@ -38,6 +38,7 @@ #include <linux/stddef.h> #include <linux/spinlock.h> #include <linux/mISDNif.h> +#include <linux/export.h> #include "core.h" static u_int *debug; diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c index 9c7c6451bf3d..b8f18bd09e43 100644 --- a/drivers/isdn/mISDN/dsp_audio.c +++ b/drivers/isdn/mISDN/dsp_audio.c @@ -12,6 +12,7 @@ #include <linux/delay.h> #include <linux/mISDNif.h> #include <linux/mISDNdsp.h> +#include <linux/export.h> #include "core.h" #include "dsp.h" diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index 621f31007095..b6c9a5889346 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -30,6 +30,7 @@ #include <linux/string.h> #include <linux/mISDNif.h> #include <linux/mISDNdsp.h> +#include <linux/export.h> #include "dsp.h" #include "dsp_hwec.h" diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 8e325227b4c0..738ea8dd0adf 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -17,6 +17,7 @@ #include <linux/mISDNif.h> #include <linux/slab.h> +#include <linux/export.h> #include "core.h" static u_int *debug; diff --git a/drivers/leds/dell-led.c b/drivers/leds/dell-led.c index 52590296af33..e5c57389efd6 100644 --- a/drivers/leds/dell-led.c +++ b/drivers/leds/dell-led.c @@ -14,6 +14,7 @@ #include <linux/acpi.h> #include <linux/leds.h> #include <linux/slab.h> +#include <linux/module.h> MODULE_AUTHOR("Louis Davis/Jim Dailey"); MODULE_DESCRIPTION("Dell LED Control Driver"); diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 0d4c16678ace..0810604dc701 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/mfd/88pm860x.h> +#include <linux/module.h> #define LED_PWM_SHIFT (3) #define LED_PWM_MASK (0x1F) diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c index fbd5d88ccd8f..48d9fe61bdfc 100644 --- a/drivers/leds/leds-asic3.c +++ b/drivers/leds/leds-asic3.c @@ -14,6 +14,7 @@ #include <linux/mfd/asic3.h> #include <linux/mfd/core.h> +#include <linux/module.h> /* * The HTC ASIC3 LED GPIOs are inputs, not outputs. diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c index c941d906bba6..109c875ea233 100644 --- a/drivers/leds/leds-atmel-pwm.c +++ b/drivers/leds/leds-atmel-pwm.c @@ -4,6 +4,7 @@ #include <linux/io.h> #include <linux/atmel_pwm.h> #include <linux/slab.h> +#include <linux/module.h> struct pwmled { diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c index 438d48384636..aac1c073fe7b 100644 --- a/drivers/leds/leds-cobalt-raq.c +++ b/drivers/leds/leds-cobalt-raq.c @@ -24,6 +24,7 @@ #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/types.h> +#include <linux/export.h> #define LED_WEB 0x04 #define LED_POWER_OFF 0x08 diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c index d11d05be0dee..49aceffaa5b6 100644 --- a/drivers/leds/leds-fsg.c +++ b/drivers/leds/leds-fsg.c @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/leds.h> +#include <linux/module.h> #include <mach/hardware.h> #include <asm/io.h> diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 504cc26c7e4b..399a86f2013a 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -18,6 +18,7 @@ #include <linux/of_gpio.h> #include <linux/slab.h> #include <linux/workqueue.h> +#include <linux/module.h> #include <asm/gpio.h> diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c index 4dc510fdfa06..0630e4f4b286 100644 --- a/drivers/leds/leds-lm3530.c +++ b/drivers/leds/leds-lm3530.c @@ -18,6 +18,7 @@ #include <linux/led-lm3530.h> #include <linux/types.h> #include <linux/regulator/consumer.h> +#include <linux/module.h> #define LM3530_LED_DEV "lcd-backlight" #define LM3530_NAME "lm3530-led" diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c index 1f7c10f6b7f2..80ba048889d6 100644 --- a/drivers/leds/leds-locomo.c +++ b/drivers/leds/leds-locomo.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/module.h> #include <linux/device.h> #include <linux/leds.h> diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c index 2579678f97a6..53f67b8ce55d 100644 --- a/drivers/leds/leds-lt3593.c +++ b/drivers/leds/leds-lt3593.c @@ -24,6 +24,7 @@ #include <linux/delay.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/module.h> struct lt3593_led_data { struct led_classdev cdev; diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c index 93987a12da49..f117f7326c5b 100644 --- a/drivers/leds/leds-net48xx.c +++ b/drivers/leds/leds-net48xx.c @@ -18,6 +18,7 @@ #include <asm/io.h> #include <linux/nsc_gpio.h> #include <linux/scx200_gpio.h> +#include <linux/module.h> #define DRVNAME "net48xx-led" #define NET48XX_ERROR_LED_GPIO 20 diff --git a/drivers/leds/leds-net5501.c b/drivers/leds/leds-net5501.c index 7e764b8365e6..0555d4709a7c 100644 --- a/drivers/leds/leds-net5501.c +++ b/drivers/leds/leds-net5501.c @@ -16,6 +16,7 @@ #include <linux/leds.h> #include <linux/platform_device.h> #include <linux/gpio.h> +#include <linux/module.h> #include <asm/geode.h> diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index f77d48d0b3e4..37b7d0cfe586 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/leds.h> +#include <linux/module.h> #include <mach/leds-ns2.h> /* diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c index a77771dc2e95..29f8b0f0e2c6 100644 --- a/drivers/leds/leds-s3c24xx.c +++ b/drivers/leds/leds-s3c24xx.c @@ -17,6 +17,7 @@ #include <linux/leds.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/module.h> #include <mach/hardware.h> #include <mach/regs-gpio.h> diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c index ef5c24140a44..b1eb34c3e81f 100644 --- a/drivers/leds/leds-wm831x-status.c +++ b/drivers/leds/leds-wm831x-status.c @@ -18,6 +18,7 @@ #include <linux/mfd/wm831x/core.h> #include <linux/mfd/wm831x/pdata.h> #include <linux/mfd/wm831x/status.h> +#include <linux/module.h> struct wm831x_status { diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c index f14edd82cb00..4a1276578352 100644 --- a/drivers/leds/leds-wm8350.c +++ b/drivers/leds/leds-wm8350.c @@ -17,6 +17,7 @@ #include <linux/mfd/wm8350/pmic.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/module.h> /* Microamps */ static const int isink_cur[] = { diff --git a/drivers/leds/leds-wrap.c b/drivers/leds/leds-wrap.c index 2982c86ac4cf..6e21e654bb02 100644 --- a/drivers/leds/leds-wrap.c +++ b/drivers/leds/leds-wrap.c @@ -17,6 +17,7 @@ #include <linux/err.h> #include <asm/io.h> #include <linux/scx200_gpio.h> +#include <linux/module.h> #define DRVNAME "wrap-led" #define WRAP_POWER_LED_GPIO 2 diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 5289ffa2e500..0dc30ffde5ad 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c @@ -15,6 +15,7 @@ #include <linux/interrupt.h> #include <linux/virtio_ring.h> #include <linux/err.h> +#include <linux/export.h> #include <linux/slab.h> #include <asm/io.h> #include <asm/paravirt.h> diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index f97e625241ad..ff4a0bc9904d 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -13,6 +13,7 @@ #include <linux/eventfd.h> #include <linux/file.h> #include <linux/slab.h> +#include <linux/export.h> #include "lg.h" /*L:056 diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index cb246667dd52..0a6806f80ab5 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -14,6 +14,7 @@ #include <linux/vmalloc.h> #include <linux/version.h> #include <linux/shrinker.h> +#include <linux/module.h> #define DM_MSG_PREFIX "bufio" diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index 0bdb201c2c2a..042e71996569 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c @@ -11,6 +11,7 @@ #include <linux/mm.h> #include <linux/pagemap.h> #include <linux/vmalloc.h> +#include <linux/module.h> #include <linux/slab.h> #define DM_MSG_PREFIX "snapshot exception stores" diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 8db3862dade5..9429159d9ee3 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c @@ -9,6 +9,7 @@ #include <linux/dm-dirty-log.h> #include <linux/device-mapper.h> #include <linux/dm-log-userspace.h> +#include <linux/module.h> #include "dm-log-userspace-transfer.h" diff --git a/drivers/md/dm-path-selector.c b/drivers/md/dm-path-selector.c index 42c04f04a0c4..fa0ccc585cb4 100644 --- a/drivers/md/dm-path-selector.c +++ b/drivers/md/dm-path-selector.c @@ -10,6 +10,7 @@ */ #include <linux/device-mapper.h> +#include <linux/module.h> #include "dm-path-selector.h" diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 11fa96df4b06..c2907d836e4e 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -6,6 +6,7 @@ */ #include <linux/slab.h> +#include <linux/module.h> #include "md.h" #include "raid1.h" diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c index 24752f449bef..27f1d423b76c 100644 --- a/drivers/md/dm-round-robin.c +++ b/drivers/md/dm-round-robin.c @@ -14,6 +14,7 @@ #include "dm-path-selector.h" #include <linux/slab.h> +#include <linux/module.h> #define DM_MSG_PREFIX "multipath round-robin" diff --git a/drivers/md/dm-service-time.c b/drivers/md/dm-service-time.c index 9c6c2e47ad62..59883bd78214 100644 --- a/drivers/md/dm-service-time.c +++ b/drivers/md/dm-service-time.c @@ -12,6 +12,7 @@ #include "dm-path-selector.h" #include <linux/slab.h> +#include <linux/module.h> #define DM_MSG_PREFIX "multipath service-time" #define ST_MIN_IO 1 diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index d1f1d7017103..3ac415675b6c 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -10,6 +10,7 @@ #include <linux/mm.h> #include <linux/pagemap.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/dm-io.h> diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c index a0898a66a2f8..1ce9a2586e41 100644 --- a/drivers/md/dm-snap-transient.c +++ b/drivers/md/dm-snap-transient.c @@ -10,6 +10,7 @@ #include <linux/mm.h> #include <linux/pagemap.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/dm-io.h> diff --git a/drivers/md/dm-uevent.c b/drivers/md/dm-uevent.c index 6b1e3b61b25e..8efe033bab55 100644 --- a/drivers/md/dm-uevent.c +++ b/drivers/md/dm-uevent.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/kobject.h> #include <linux/dm-ioctl.h> +#include <linux/export.h> #include "dm.h" #include "dm-uevent.h" diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 6b6616a41baa..4720f68f817e 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -192,9 +192,6 @@ struct mapped_device { /* forced geometry settings */ struct hd_geometry geometry; - /* For saving the address of __make_request for request based dm */ - make_request_fn *saved_make_request_fn; - /* sysfs handle */ struct kobject kobj; @@ -1403,7 +1400,7 @@ out: * The request function that just remaps the bio built up by * dm_merge_bvec. */ -static int _dm_request(struct request_queue *q, struct bio *bio) +static void _dm_request(struct request_queue *q, struct bio *bio) { int rw = bio_data_dir(bio); struct mapped_device *md = q->queuedata; @@ -1424,19 +1421,12 @@ static int _dm_request(struct request_queue *q, struct bio *bio) queue_io(md, bio); else bio_io_error(bio); - return 0; + return; } __split_and_process_bio(md, bio); up_read(&md->io_lock); - return 0; -} - -static int dm_make_request(struct request_queue *q, struct bio *bio) -{ - struct mapped_device *md = q->queuedata; - - return md->saved_make_request_fn(q, bio); /* call __make_request() */ + return; } static int dm_request_based(struct mapped_device *md) @@ -1444,14 +1434,14 @@ static int dm_request_based(struct mapped_device *md) return blk_queue_stackable(md->queue); } -static int dm_request(struct request_queue *q, struct bio *bio) +static void dm_request(struct request_queue *q, struct bio *bio) { struct mapped_device *md = q->queuedata; if (dm_request_based(md)) - return dm_make_request(q, bio); - - return _dm_request(q, bio); + blk_queue_bio(q, bio); + else + _dm_request(q, bio); } void dm_dispatch_request(struct request *rq) @@ -2191,7 +2181,6 @@ static int dm_init_request_based_queue(struct mapped_device *md) return 0; md->queue = q; - md->saved_make_request_fn = md->queue->make_request_fn; dm_init_md_queue(md); blk_queue_softirq_done(md->queue, dm_softirq_done); blk_queue_prep_rq(md->queue, dm_prep_fn); diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 60816b132c2e..feb2c3c7bb44 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -63,6 +63,7 @@ #define MaxFault 50 #include <linux/blkdev.h> +#include <linux/module.h> #include <linux/raid/md_u.h> #include <linux/slab.h> #include "md.h" @@ -169,7 +170,7 @@ static void add_sector(struct faulty_conf *conf, sector_t start, int mode) conf->nfaults = n+1; } -static int make_request(struct mddev *mddev, struct bio *bio) +static void make_request(struct mddev *mddev, struct bio *bio) { struct faulty_conf *conf = mddev->private; int failit = 0; @@ -181,7 +182,7 @@ static int make_request(struct mddev *mddev, struct bio *bio) * just fail immediately */ bio_endio(bio, -EIO); - return 0; + return; } if (check_sector(conf, bio->bi_sector, bio->bi_sector+(bio->bi_size>>9), @@ -211,15 +212,15 @@ static int make_request(struct mddev *mddev, struct bio *bio) } if (failit) { struct bio *b = bio_clone_mddev(bio, GFP_NOIO, mddev); + b->bi_bdev = conf->rdev->bdev; b->bi_private = bio; b->bi_end_io = faulty_fail; - generic_make_request(b); - return 0; - } else { + bio = b; + } else bio->bi_bdev = conf->rdev->bdev; - return 1; - } + + generic_make_request(bio); } static void status(struct seq_file *seq, struct mddev *mddev) diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 10c5844460cb..c3273efd08cb 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -19,6 +19,7 @@ #include <linux/blkdev.h> #include <linux/raid/md_u.h> #include <linux/seq_file.h> +#include <linux/module.h> #include <linux/slab.h> #include "md.h" #include "linear.h" @@ -264,14 +265,14 @@ static int linear_stop (struct mddev *mddev) return 0; } -static int linear_make_request (struct mddev *mddev, struct bio *bio) +static void linear_make_request(struct mddev *mddev, struct bio *bio) { struct dev_info *tmp_dev; sector_t start_sector; if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); - return 0; + return; } rcu_read_lock(); @@ -293,7 +294,7 @@ static int linear_make_request (struct mddev *mddev, struct bio *bio) (unsigned long long)start_sector); rcu_read_unlock(); bio_io_error(bio); - return 0; + return; } if (unlikely(bio->bi_sector + (bio->bi_size >> 9) > tmp_dev->end_sector)) { @@ -307,20 +308,17 @@ static int linear_make_request (struct mddev *mddev, struct bio *bio) bp = bio_split(bio, end_sector - bio->bi_sector); - if (linear_make_request(mddev, &bp->bio1)) - generic_make_request(&bp->bio1); - if (linear_make_request(mddev, &bp->bio2)) - generic_make_request(&bp->bio2); + linear_make_request(mddev, &bp->bio1); + linear_make_request(mddev, &bp->bio2); bio_pair_release(bp); - return 0; + return; } bio->bi_bdev = tmp_dev->rdev->bdev; bio->bi_sector = bio->bi_sector - start_sector + tmp_dev->rdev->data_offset; rcu_read_unlock(); - - return 1; + generic_make_request(bio); } static void linear_status (struct seq_file *seq, struct mddev *mddev) diff --git a/drivers/md/md.c b/drivers/md/md.c index 266e82ebaf11..84acfe7d10e4 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -44,6 +44,7 @@ #include <linux/hdreg.h> #include <linux/proc_fs.h> #include <linux/random.h> +#include <linux/module.h> #include <linux/reboot.h> #include <linux/file.h> #include <linux/compat.h> @@ -332,18 +333,17 @@ static DEFINE_SPINLOCK(all_mddevs_lock); * call has finished, the bio has been linked into some internal structure * and so is visible to ->quiesce(), so we don't need the refcount any more. */ -static int md_make_request(struct request_queue *q, struct bio *bio) +static void md_make_request(struct request_queue *q, struct bio *bio) { const int rw = bio_data_dir(bio); struct mddev *mddev = q->queuedata; - int rv; int cpu; unsigned int sectors; if (mddev == NULL || mddev->pers == NULL || !mddev->ready) { bio_io_error(bio); - return 0; + return; } smp_rmb(); /* Ensure implications of 'active' are visible */ rcu_read_lock(); @@ -368,7 +368,7 @@ static int md_make_request(struct request_queue *q, struct bio *bio) * go away inside make_request */ sectors = bio_sectors(bio); - rv = mddev->pers->make_request(mddev, bio); + mddev->pers->make_request(mddev, bio); cpu = part_stat_lock(); part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]); @@ -377,8 +377,6 @@ static int md_make_request(struct request_queue *q, struct bio *bio) if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended) wake_up(&mddev->sb_wait); - - return rv; } /* mddev_suspend makes sure no new requests are submitted @@ -477,8 +475,7 @@ static void md_submit_flush_data(struct work_struct *ws) bio_endio(bio, 0); else { bio->bi_rw &= ~REQ_FLUSH; - if (mddev->pers->make_request(mddev, bio)) - generic_make_request(bio); + mddev->pers->make_request(mddev, bio); } mddev->flush_bio = NULL; diff --git a/drivers/md/md.h b/drivers/md/md.h index 51c1d91557e0..cf742d9306ec 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -419,7 +419,7 @@ struct md_personality int level; struct list_head list; struct module *owner; - int (*make_request)(struct mddev *mddev, struct bio *bio); + void (*make_request)(struct mddev *mddev, struct bio *bio); int (*run)(struct mddev *mddev); int (*stop)(struct mddev *mddev); void (*status)(struct seq_file *seq, struct mddev *mddev); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index d32c785e17d4..5899246fa37e 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -20,6 +20,7 @@ */ #include <linux/blkdev.h> +#include <linux/module.h> #include <linux/raid/md_u.h> #include <linux/seq_file.h> #include <linux/slab.h> @@ -106,7 +107,7 @@ static void multipath_end_request(struct bio *bio, int error) rdev_dec_pending(rdev, conf->mddev); } -static int multipath_make_request(struct mddev *mddev, struct bio * bio) +static void multipath_make_request(struct mddev *mddev, struct bio * bio) { struct mpconf *conf = mddev->private; struct multipath_bh * mp_bh; @@ -114,7 +115,7 @@ static int multipath_make_request(struct mddev *mddev, struct bio * bio) if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); - return 0; + return; } mp_bh = mempool_alloc(conf->pool, GFP_NOIO); @@ -126,7 +127,7 @@ static int multipath_make_request(struct mddev *mddev, struct bio * bio) if (mp_bh->path < 0) { bio_endio(bio, -EIO); mempool_free(mp_bh, conf->pool); - return 0; + return; } multipath = conf->multipaths + mp_bh->path; @@ -137,7 +138,7 @@ static int multipath_make_request(struct mddev *mddev, struct bio * bio) mp_bh->bio.bi_end_io = multipath_end_request; mp_bh->bio.bi_private = mp_bh; generic_make_request(&mp_bh->bio); - return 0; + return; } static void multipath_status (struct seq_file *seq, struct mddev *mddev) diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c index 65fd85ec6514..023fbc2d389e 100644 --- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -8,7 +8,7 @@ #include "dm-btree-internal.h" #include "dm-transaction-manager.h" -#include <linux/module.h> +#include <linux/export.h> /* * Removing an entry from a btree diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index e0638be53ea4..bd1e7ffbe26c 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -8,7 +8,7 @@ #include "dm-space-map.h" #include "dm-transaction-manager.h" -#include <linux/module.h> +#include <linux/export.h> #include <linux/device-mapper.h> #define DM_MSG_PREFIX "btree" diff --git a/drivers/md/persistent-data/dm-space-map-checker.c b/drivers/md/persistent-data/dm-space-map-checker.c index bb44a937fe63..50ed53bf4aa2 100644 --- a/drivers/md/persistent-data/dm-space-map-checker.c +++ b/drivers/md/persistent-data/dm-space-map-checker.c @@ -7,6 +7,7 @@ #include "dm-space-map-checker.h" #include <linux/device-mapper.h> +#include <linux/export.h> #ifdef CONFIG_DM_DEBUG_SPACE_MAPS diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c index aeff7852cf79..fc469ba9f627 100644 --- a/drivers/md/persistent-data/dm-space-map-disk.c +++ b/drivers/md/persistent-data/dm-space-map-disk.c @@ -12,7 +12,7 @@ #include <linux/list.h> #include <linux/slab.h> -#include <linux/module.h> +#include <linux/export.h> #include <linux/device-mapper.h> #define DM_MSG_PREFIX "space map disk" diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c index 728e89a3f978..6f8d38747d7f 100644 --- a/drivers/md/persistent-data/dm-transaction-manager.c +++ b/drivers/md/persistent-data/dm-transaction-manager.c @@ -10,7 +10,7 @@ #include "dm-space-map-metadata.h" #include "dm-persistent-data-internal.h" -#include <linux/module.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/device-mapper.h> diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 0eb08a4df759..7294bd115e34 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -20,6 +20,7 @@ #include <linux/blkdev.h> #include <linux/seq_file.h> +#include <linux/module.h> #include <linux/slab.h> #include "md.h" #include "raid0.h" @@ -468,7 +469,7 @@ static inline int is_io_in_chunk_boundary(struct mddev *mddev, } } -static int raid0_make_request(struct mddev *mddev, struct bio *bio) +static void raid0_make_request(struct mddev *mddev, struct bio *bio) { unsigned int chunk_sects; sector_t sector_offset; @@ -477,7 +478,7 @@ static int raid0_make_request(struct mddev *mddev, struct bio *bio) if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); - return 0; + return; } chunk_sects = mddev->chunk_sectors; @@ -497,13 +498,10 @@ static int raid0_make_request(struct mddev *mddev, struct bio *bio) else bp = bio_split(bio, chunk_sects - sector_div(sector, chunk_sects)); - if (raid0_make_request(mddev, &bp->bio1)) - generic_make_request(&bp->bio1); - if (raid0_make_request(mddev, &bp->bio2)) - generic_make_request(&bp->bio2); - + raid0_make_request(mddev, &bp->bio1); + raid0_make_request(mddev, &bp->bio2); bio_pair_release(bp); - return 0; + return; } sector_offset = bio->bi_sector; @@ -513,10 +511,9 @@ static int raid0_make_request(struct mddev *mddev, struct bio *bio) bio->bi_bdev = tmp_dev->bdev; bio->bi_sector = sector_offset + zone->dev_start + tmp_dev->data_offset; - /* - * Let the main block layer submit the IO and resolve recursion: - */ - return 1; + + generic_make_request(bio); + return; bad_map: printk("md/raid0:%s: make_request bug: can't convert block across chunks" @@ -525,7 +522,7 @@ bad_map: (unsigned long long)bio->bi_sector, bio->bi_size >> 10); bio_io_error(bio); - return 0; + return; } static void raid0_status(struct seq_file *seq, struct mddev *mddev) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 4602fc57c961..ede2461e79c5 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -34,6 +34,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/blkdev.h> +#include <linux/module.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> #include "md.h" @@ -807,7 +808,7 @@ do_sync_io: pr_debug("%dB behind alloc failed, doing sync I/O\n", bio->bi_size); } -static int make_request(struct mddev *mddev, struct bio * bio) +static void make_request(struct mddev *mddev, struct bio * bio) { struct r1conf *conf = mddev->private; struct mirror_info *mirror; @@ -892,7 +893,7 @@ read_again: if (rdisk < 0) { /* couldn't find anywhere to read from */ raid_end_bio_io(r1_bio); - return 0; + return; } mirror = conf->mirrors + rdisk; @@ -950,7 +951,7 @@ read_again: goto read_again; } else generic_make_request(read_bio); - return 0; + return; } /* @@ -1151,8 +1152,6 @@ read_again: if (do_sync || !bitmap || !plugged) md_wakeup_thread(mddev->thread); - - return 0; } static void status(struct seq_file *seq, struct mddev *mddev) @@ -2193,7 +2192,6 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp bio->bi_next = NULL; bio->bi_flags &= ~(BIO_POOL_MASK-1); bio->bi_flags |= 1 << BIO_UPTODATE; - bio->bi_comp_cpu = -1; bio->bi_rw = READ; bio->bi_vcnt = 0; bio->bi_idx = 0; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index c025a8276dc1..685ddf325ee4 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -21,6 +21,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/blkdev.h> +#include <linux/module.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> #include "md.h" @@ -842,7 +843,7 @@ static void unfreeze_array(struct r10conf *conf) spin_unlock_irq(&conf->resync_lock); } -static int make_request(struct mddev *mddev, struct bio * bio) +static void make_request(struct mddev *mddev, struct bio * bio) { struct r10conf *conf = mddev->private; struct mirror_info *mirror; @@ -861,7 +862,7 @@ static int make_request(struct mddev *mddev, struct bio * bio) if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); - return 0; + return; } /* If this request crosses a chunk boundary, we need to @@ -893,10 +894,8 @@ static int make_request(struct mddev *mddev, struct bio * bio) conf->nr_waiting++; spin_unlock_irq(&conf->resync_lock); - if (make_request(mddev, &bp->bio1)) - generic_make_request(&bp->bio1); - if (make_request(mddev, &bp->bio2)) - generic_make_request(&bp->bio2); + make_request(mddev, &bp->bio1); + make_request(mddev, &bp->bio2); spin_lock_irq(&conf->resync_lock); conf->nr_waiting--; @@ -904,14 +903,14 @@ static int make_request(struct mddev *mddev, struct bio * bio) spin_unlock_irq(&conf->resync_lock); bio_pair_release(bp); - return 0; + return; bad_map: printk("md/raid10:%s: make_request bug: can't convert block across chunks" " or bigger than %dk %llu %d\n", mdname(mddev), chunk_sects/2, (unsigned long long)bio->bi_sector, bio->bi_size >> 10); bio_io_error(bio); - return 0; + return; } md_write_start(mddev, bio); @@ -954,7 +953,7 @@ read_again: slot = r10_bio->read_slot; if (disk < 0) { raid_end_bio_io(r10_bio); - return 0; + return; } mirror = conf->mirrors + disk; @@ -1002,7 +1001,7 @@ read_again: goto read_again; } else generic_make_request(read_bio); - return 0; + return; } /* @@ -1176,7 +1175,6 @@ retry_write: if (do_sync || !mddev->bitmap || !plugged) md_wakeup_thread(mddev->thread); - return 0; } static void status(struct seq_file *seq, struct mddev *mddev) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f6fe053a5bed..472aedfb07cf 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -47,6 +47,7 @@ #include <linux/kthread.h> #include <linux/raid/pq.h> #include <linux/async_tx.h> +#include <linux/module.h> #include <linux/async.h> #include <linux/seq_file.h> #include <linux/cpu.h> @@ -3688,7 +3689,7 @@ static struct stripe_head *__get_priority_stripe(struct r5conf *conf) return sh; } -static int make_request(struct mddev *mddev, struct bio * bi) +static void make_request(struct mddev *mddev, struct bio * bi) { struct r5conf *conf = mddev->private; int dd_idx; @@ -3701,7 +3702,7 @@ static int make_request(struct mddev *mddev, struct bio * bi) if (unlikely(bi->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bi); - return 0; + return; } md_write_start(mddev, bi); @@ -3709,7 +3710,7 @@ static int make_request(struct mddev *mddev, struct bio * bi) if (rw == READ && mddev->reshape_position == MaxSector && chunk_aligned_read(mddev,bi)) - return 0; + return; logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); last_sector = bi->bi_sector + (bi->bi_size>>9); @@ -3844,8 +3845,6 @@ static int make_request(struct mddev *mddev, struct bio * bi) bio_endio(bi, 0); } - - return 0; } static sector_t raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks); diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index f5d53a202344..d6b1cf66042d 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -21,6 +21,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <media/saa7146.h> +#include <linux/module.h> LIST_HEAD(saa7146_devices); DEFINE_MUTEX(saa7146_devices_lock); diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index a92546144eaa..71f8e018e564 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -1,6 +1,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <media/saa7146_vv.h> +#include <linux/module.h> /****************************************************************************/ /* resource management functions, shamelessly stolen from saa7134 driver */ diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c index 79ad73accb27..bc1f545c95cb 100644 --- a/drivers/media/common/saa7146_hlp.c +++ b/drivers/media/common/saa7146_hlp.c @@ -1,6 +1,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> +#include <linux/export.h> #include <media/saa7146_vv.h> static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format) diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 384b358d3037..ce30533fd972 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -2,6 +2,7 @@ #include <media/saa7146_vv.h> #include <media/v4l2-chip-ident.h> +#include <linux/module.h> static int max_memory = 32; diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index 94a603a60842..e13683bab6b3 100644 --- a/drivers/media/common/tuners/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c @@ -5,6 +5,7 @@ */ #include <linux/i2c.h> +#include <linux/module.h> #include <media/tuner.h> #include <media/tuner-types.h> diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index 774d507b66cc..43be7238311e 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c @@ -1,5 +1,6 @@ #include <linux/i2c.h> #include <linux/mutex.h> +#include <linux/module.h> #include "dibx000_common.h" diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c index af121db88ea0..680c781c8dd6 100644 --- a/drivers/media/dvb/siano/sms-cards.c +++ b/drivers/media/dvb/siano/sms-cards.c @@ -19,6 +19,7 @@ #include "sms-cards.h" #include "smsir.h" +#include <linux/module.h> static int sms_dbg; module_param_named(cards_dbg, sms_dbg, int, 0644); diff --git a/drivers/media/dvb/siano/smsendian.c b/drivers/media/dvb/siano/smsendian.c index 457b6d02ef85..e2657c2f0109 100644 --- a/drivers/media/dvb/siano/smsendian.c +++ b/drivers/media/dvb/siano/smsendian.c @@ -19,6 +19,7 @@ ****************************************************************/ +#include <linux/export.h> #include <asm/byteorder.h> #include "smsendian.h" diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c index e57d38b0197c..91f8c8291e2b 100644 --- a/drivers/media/dvb/siano/smssdio.c +++ b/drivers/media/dvb/siano/smssdio.c @@ -39,6 +39,7 @@ #include <linux/mmc/card.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> +#include <linux/module.h> #include "smscoreapi.h" #include "sms-cards.h" diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index 0c8164a2cc36..51c7121b321a 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <linux/usb.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/module.h> #include "smscoreapi.h" #include "sms-cards.h" diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 16b70b4412f7..6edc9ba81203 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -23,6 +23,7 @@ #include <linux/types.h> #include <linux/ioctl.h> #include <linux/media.h> +#include <linux/export.h> #include <media/media-device.h> #include <media/media-devnode.h> diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index f17b540d68a5..3e9209f84e09 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -23,6 +23,7 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/module.h> #include <media/timb_radio.h> #define DRIVER_NAME "timb-radio" diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 6d1e4e750f63..8aa4968d57bc 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -23,6 +23,7 @@ #include <linux/interrupt.h> #include <linux/mfd/wl1273-core.h> #include <linux/slab.h> +#include <linux/module.h> #include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index c9f4a8e65dc4..27aba936fb2b 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> +#include <linux/module.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-common.h> diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index b93d8cf23b03..4f5c43d2566c 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -28,6 +28,8 @@ * */ +#include <linux/export.h> + #include "fmdrv.h" #include "fmdrv_v4l2.h" #include "fmdrv_common.h" diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index 624449afaa61..035668e27f6b 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -13,6 +13,7 @@ */ #include <linux/bitrev.h> +#include <linux/module.h> #include "rc-core-priv.h" #define JVC_NBITS 16 /* dev(8) + func(8) */ diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index ec2e67fd236b..5faba2a2fdd3 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -14,6 +14,7 @@ #include <linux/sched.h> #include <linux/wait.h> +#include <linux/module.h> #include <media/lirc.h> #include <media/lirc_dev.h> #include <media/rc-core.h> diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 63ee722dbd02..17f8db00435a 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -13,6 +13,7 @@ */ #include <linux/bitrev.h> +#include <linux/module.h> #include "rc-core-priv.h" #define NEC_NBITS 32 diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 27808bb59eba..2e5cd3100b64 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -12,8 +12,10 @@ * GNU General Public License for more details. */ +#include <linux/export.h> #include <linux/kthread.h> #include <linux/mutex.h> +#include <linux/kmod.h> #include <linux/sched.h> #include <linux/freezer.h> #include "rc-core-priv.h" diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index ebdba5539916..9ab663a507a4 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -21,6 +21,7 @@ */ #include "rc-core-priv.h" +#include <linux/module.h> #define RC5_NBITS 14 #define RC5X_NBITS 20 diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c index 90aa8868629a..ec8d4a2e2c5a 100644 --- a/drivers/media/rc/ir-rc5-sz-decoder.c +++ b/drivers/media/rc/ir-rc5-sz-decoder.c @@ -21,6 +21,7 @@ */ #include "rc-core-priv.h" +#include <linux/module.h> #define RC5_SZ_NBITS 15 #define RC5_UNIT 888888 /* ns */ diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 755dafa3871b..140fb67e2f89 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -13,6 +13,7 @@ */ #include "rc-core-priv.h" +#include <linux/module.h> /* * This decoder currently supports: diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index a92de80c48db..d5e2b50aff1f 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -13,6 +13,7 @@ */ #include <linux/bitrev.h> +#include <linux/module.h> #include "rc-core-priv.h" #define SONY_UNIT 600000 /* ns */ diff --git a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c index 9a8752fdcca1..b0e42df7ff82 100644 --- a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c +++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* ADS Tech Instant TV DVB-T PCI Remote */ diff --git a/drivers/media/rc/keymaps/rc-alink-dtu-m.c b/drivers/media/rc/keymaps/rc-alink-dtu-m.c index fe652e928dc0..4e6ade8e616f 100644 --- a/drivers/media/rc/keymaps/rc-alink-dtu-m.c +++ b/drivers/media/rc/keymaps/rc-alink-dtu-m.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* A-Link DTU(m) slim remote, 6 rows, 3 columns. */ static struct rc_map_table alink_dtu_m[] = { diff --git a/drivers/media/rc/keymaps/rc-anysee.c b/drivers/media/rc/keymaps/rc-anysee.c index 884f1b51a8ee..c735fe10a390 100644 --- a/drivers/media/rc/keymaps/rc-anysee.c +++ b/drivers/media/rc/keymaps/rc-anysee.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table anysee[] = { { 0x0800, KEY_0 }, diff --git a/drivers/media/rc/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c index 7af188209ff9..8c92ff95f94d 100644 --- a/drivers/media/rc/keymaps/rc-apac-viewcomp.c +++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Attila Kondoros <attila.kondoros@chello.hu> */ diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c index b2481154491b..2caf2117759b 100644 --- a/drivers/media/rc/keymaps/rc-asus-pc39.c +++ b/drivers/media/rc/keymaps/rc-asus-pc39.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * Marc Fargas <telenieko@telenieko.com> diff --git a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c index f766b24b0158..2031224a2027 100644 --- a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c +++ b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* ATI TV Wonder HD 600 USB Devin Heitmueller <devin.heitmueller@gmail.com> diff --git a/drivers/media/rc/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c index ec9beeebd410..894939ac17f2 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-a16d.c +++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table avermedia_a16d[] = { { 0x20, KEY_LIST}, diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c index 22f54d413a35..d2aaf5b9e39f 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c +++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Oldrich Jedlicka <oldium.pro@seznam.cz> */ diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c index c25809d4c813..dc2baf062398 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c +++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Matt Jesson <dvb@jesson.eclipse.co.uk */ diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c index 3d2cbe4e5e46..04269d31fa19 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m135a.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c @@ -10,6 +10,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * Avermedia M135A with RM-JX and RM-K6 remote controls diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c index 8cd7f28808bd..e83b1a1939bf 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c @@ -9,6 +9,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * Avermedia M733A with IR model RM-K6 diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c index 9d68af217d8b..8344bcc595be 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c +++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Initial keytable is from Jose Alberto Reguero <jareguero@telefonica.net> and Felipe Morales Moreno <felipe.morales.moreno@gmail.com> */ diff --git a/drivers/media/rc/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c index edfa71506d3e..c6063dfcd507 100644 --- a/drivers/media/rc/keymaps/rc-avermedia.c +++ b/drivers/media/rc/keymaps/rc-avermedia.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Alex Hermann <gaaf@gmx.net> */ diff --git a/drivers/media/rc/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c index 32e94988dc94..14f78451e64e 100644 --- a/drivers/media/rc/keymaps/rc-avertv-303.c +++ b/drivers/media/rc/keymaps/rc-avertv-303.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* AVERTV STUDIO 303 Remote */ diff --git a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c index c3f6d62ac892..ea7f2d0f31eb 100644 --- a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c +++ b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table azurewave_ad_tu700[] = { { 0x0000, KEY_TAB }, /* Tab */ diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c index 8bf058f67f0c..086b4b1f19e1 100644 --- a/drivers/media/rc/keymaps/rc-behold-columbus.c +++ b/drivers/media/rc/keymaps/rc-behold-columbus.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Beholder Intl. Ltd. 2008 * Dmitry Belimov d.belimov@google.com diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c index c909a234c776..0877e3480941 100644 --- a/drivers/media/rc/keymaps/rc-behold.c +++ b/drivers/media/rc/keymaps/rc-behold.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * Igor Kuznetsov <igk72@ya.ru> diff --git a/drivers/media/rc/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c index 2f66e4310d20..8311e092c098 100644 --- a/drivers/media/rc/keymaps/rc-budget-ci-old.c +++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * From reading the following remotes: diff --git a/drivers/media/rc/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c index 284534b67e7d..0c87fbaf99ab 100644 --- a/drivers/media/rc/keymaps/rc-cinergy-1400.c +++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Cinergy 1400 DVB-T */ diff --git a/drivers/media/rc/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c index cf3a6bfb190c..309e9e3fb6f3 100644 --- a/drivers/media/rc/keymaps/rc-cinergy.c +++ b/drivers/media/rc/keymaps/rc-cinergy.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table cinergy[] = { { 0x00, KEY_0 }, diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c index 7a5f5300caf9..4d13a7f2e5c3 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-nec.c +++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c @@ -16,6 +16,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table dib0700_nec_table[] = { /* Key codes for the Pixelview SBTVD remote */ diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c index 4af12e45dfba..ba81d9697cfc 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-rc5.c +++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c @@ -16,6 +16,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table dib0700_rc5_table[] = { /* Key codes for the tiny Pinnacle remote*/ diff --git a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c index f68b450f5593..bed78acb9198 100644 --- a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c +++ b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table digitalnow_tinytwin[] = { { 0x0000, KEY_MUTE }, /* [symbol speaker] */ diff --git a/drivers/media/rc/keymaps/rc-digittrade.c b/drivers/media/rc/keymaps/rc-digittrade.c index 21d49871f2a3..a3b97a1fe223 100644 --- a/drivers/media/rc/keymaps/rc-digittrade.c +++ b/drivers/media/rc/keymaps/rc-digittrade.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Digittrade DVB-T USB Stick remote controller. */ /* Imported from af9015.h. diff --git a/drivers/media/rc/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c index d024fbf88bc4..67fc9fb0c007 100644 --- a/drivers/media/rc/keymaps/rc-dm1105-nec.c +++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* DVBWorld remotes Igor M. Liplianin <liplianin@me.by> diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c index 82c0200029af..91ea91de9179 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* DigitalNow DNTV Live DVB-T Remote */ diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c index 015e99de06de..fd680d4d3eb6 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* DigitalNow DNTV Live! DVB-T Pro Remote */ diff --git a/drivers/media/rc/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c index 269d4299da34..d1fcd64c0f90 100644 --- a/drivers/media/rc/keymaps/rc-em-terratec.c +++ b/drivers/media/rc/keymaps/rc-em-terratec.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table em_terratec[] = { { 0x01, KEY_CHANNEL }, diff --git a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c index e388698a0697..2fe45e41fe49 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Encore ENLTV-FM v5.3 Mauro Carvalho Chehab <mchehab@infradead.org> diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c index e56ac6e9670a..223de75a6d1c 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Encore ENLTV-FM - black plastic, white front cover with white glowing buttons Juan Pablo Sormani <sorman@gmail.com> */ diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c index b6264f1bc4c1..669cbff22b7e 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv2.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Encore ENLTV2-FM - silver plastic - "Wand Media" written at the botton Mauro Carvalho Chehab <mchehab@infradead.org> */ diff --git a/drivers/media/rc/keymaps/rc-evga-indtube.c b/drivers/media/rc/keymaps/rc-evga-indtube.c index a2bf24f6dfbb..2c647fc25916 100644 --- a/drivers/media/rc/keymaps/rc-evga-indtube.c +++ b/drivers/media/rc/keymaps/rc-evga-indtube.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* EVGA inDtube Devin Heitmueller <devin.heitmueller@gmail.com> diff --git a/drivers/media/rc/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c index 1e8e5b2d6e36..76921445c1d9 100644 --- a/drivers/media/rc/keymaps/rc-eztv.c +++ b/drivers/media/rc/keymaps/rc-eztv.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Alfons Geser <a.geser@cox.net> * updates from Job D. R. Borges <jobdrb@ig.com.br> */ diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c index a8b0f66edaa9..3a6bba311b08 100644 --- a/drivers/media/rc/keymaps/rc-flydvb.c +++ b/drivers/media/rc/keymaps/rc-flydvb.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table flydvb[] = { { 0x01, KEY_ZOOM }, /* Full Screen */ diff --git a/drivers/media/rc/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c index 5bbe68371756..bf9da584643b 100644 --- a/drivers/media/rc/keymaps/rc-flyvideo.c +++ b/drivers/media/rc/keymaps/rc-flyvideo.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table flyvideo[] = { { 0x0f, KEY_0 }, diff --git a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c index c80b25c65b57..2f0970fe7832 100644 --- a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c +++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* DViCO FUSION HDTV MCE remote */ diff --git a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c index 068c9ead98dd..0e98ec467c34 100644 --- a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c +++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* GADMEI UTV330+ RM008Z remote Shine Liu <shinel@foxmail.com> diff --git a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c index cdbbed467926..a2e2faa1d1b3 100644 --- a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c +++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * Remote control for the Genius TVGO A11MCE diff --git a/drivers/media/rc/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c index a38bdde8c140..864614e19314 100644 --- a/drivers/media/rc/keymaps/rc-gotview7135.c +++ b/drivers/media/rc/keymaps/rc-gotview7135.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Mike Baikov <mike@baikov.com> */ diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c index cd3db7779772..e51c6163378b 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge.c +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -17,6 +17,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * Hauppauge:the newer, gray remotes (seems there are multiple diff --git a/drivers/media/rc/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c index 0ea2aa190d81..124c7228ba8c 100644 --- a/drivers/media/rc/keymaps/rc-imon-mce.c +++ b/drivers/media/rc/keymaps/rc-imon-mce.c @@ -10,6 +10,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* mce-mode imon mce remote key table */ static struct rc_map_table imon_mce[] = { diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c index 75d3843fdc30..999c6295c70e 100644 --- a/drivers/media/rc/keymaps/rc-imon-pad.c +++ b/drivers/media/rc/keymaps/rc-imon-pad.c @@ -10,6 +10,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * standard imon remote key table, which isn't really entirely diff --git a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c index 1f59e163f75d..34540dfc3df5 100644 --- a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c +++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* IO-DATA BCTV7E Remote */ diff --git a/drivers/media/rc/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c index f31dc5c1ad9c..4264a787c150 100644 --- a/drivers/media/rc/keymaps/rc-kaiomy.c +++ b/drivers/media/rc/keymaps/rc-kaiomy.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Kaiomy TVnPC U2 Mauro Carvalho Chehab <mchehab@infradead.org> diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c index 7f33edb47244..e48cd267dda6 100644 --- a/drivers/media/rc/keymaps/rc-kworld-315u.c +++ b/drivers/media/rc/keymaps/rc-kworld-315u.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Kworld 315U */ diff --git a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c index 7fa17a369f2d..32998d6b787d 100644 --- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c +++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Kworld Plus TV Analog Lite PCI IR Mauro Carvalho Chehab <mchehab@infradead.org> diff --git a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c index 8faa54ff16e6..03d762d986ee 100644 --- a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c +++ b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table leadtek_y04g0051[] = { { 0x0300, KEY_POWER2 }, diff --git a/drivers/media/rc/keymaps/rc-lirc.c b/drivers/media/rc/keymaps/rc-lirc.c index e8e23e233c39..fbf08fa6f46e 100644 --- a/drivers/media/rc/keymaps/rc-lirc.c +++ b/drivers/media/rc/keymaps/rc-lirc.c @@ -10,6 +10,7 @@ */ #include <media/rc-core.h> +#include <linux/module.h> static struct rc_map_table lirc[] = { { }, diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index 129d3f9a461d..51f18bb50a37 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -10,6 +10,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table lme2510_rc[] = { diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c index 23b2d04e7a9f..e7038bb71bf6 100644 --- a/drivers/media/rc/keymaps/rc-manli.c +++ b/drivers/media/rc/keymaps/rc-manli.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Michael Tokarev <mjt@tls.msk.ru> keytable is used by MANLI MTV00[0x0c] and BeholdTV 40[13] at diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c index 7b9a01b6e4cf..c64e9e30045d 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table msi_digivox_ii[] = { { 0x0002, KEY_2 }, diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c index ae9d06b39157..303a0b73175b 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* MSI DIGIVOX mini III */ /* Uses NEC extended 0x61d6. */ diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c index 8e9969d1239b..c393d8a50bca 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c index fdd213ff1adf..a7003d3a3c8a 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* MSI TV@nywhere MASTER remote */ diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c index ddae20e9cd96..3f0ddd7afd30 100644 --- a/drivers/media/rc/keymaps/rc-nebula.c +++ b/drivers/media/rc/keymaps/rc-nebula.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table nebula[] = { { 0x00, KEY_0 }, diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c index 26f114c5c0de..f3b86c8db679 100644 --- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Terratec Cinergy Hybrid T USB XS FM Mauro Carvalho Chehab <mchehab@redhat.com> diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c index f9f2fa2819b8..9e65f07157ab 100644 --- a/drivers/media/rc/keymaps/rc-norwood.c +++ b/drivers/media/rc/keymaps/rc-norwood.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Norwood Micro (non-Pro) TV Tuner By Peter Naulls <peter@chocky.org> diff --git a/drivers/media/rc/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c index 4aa588bf6d69..65d0cfc3c33b 100644 --- a/drivers/media/rc/keymaps/rc-npgtech.c +++ b/drivers/media/rc/keymaps/rc-npgtech.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table npgtech[] = { { 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */ diff --git a/drivers/media/rc/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c index 7cdef6e6cc0f..bf2cbdfe2e32 100644 --- a/drivers/media/rc/keymaps/rc-pctv-sedna.c +++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Mapping for the 28 key remote control as seen at http://www.sednacomputer.com/photo/cardbus-tv.jpg diff --git a/drivers/media/rc/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c index 23b8c505c6aa..b46cd8fe6438 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-color.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table pinnacle_color[] = { { 0x59, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c index 6ba8c368d10a..d525df9ad868 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-grey.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table pinnacle_grey[] = { { 0x3a, KEY_0 }, diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c index 31fc64cd17ba..a4603d035374 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Pinnacle PCTV HD 800i mini remote */ diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c index e5ab071f635a..33eb64333c6f 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-002t.c +++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * Keytable for 002-T IR remote provided together with Pixelview diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c index 125fc3949c15..21f4dd25c2ec 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-mk12.c +++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * Keytable for MK-F12 IR remote provided together with Pixelview diff --git a/drivers/media/rc/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c index bd78d6ac1e16..f944ad2cac2b 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-new.c +++ b/drivers/media/rc/keymaps/rc-pixelview-new.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Mauro Carvalho Chehab <mchehab@infradead.org> diff --git a/drivers/media/rc/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c index 06187e7db446..a6020eea7b95 100644 --- a/drivers/media/rc/keymaps/rc-pixelview.c +++ b/drivers/media/rc/keymaps/rc-pixelview.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table pixelview[] = { diff --git a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c index 5f9d546a86c4..e74c571a5e44 100644 --- a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c +++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * Remote control for Powercolor Real Angel 330 diff --git a/drivers/media/rc/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c index 8a3a643879d4..adee8035ce96 100644 --- a/drivers/media/rc/keymaps/rc-proteus-2309.c +++ b/drivers/media/rc/keymaps/rc-proteus-2309.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Michal Majchrowicz <mmajchrowicz@gmail.com> */ diff --git a/drivers/media/rc/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c index ef90296bfd68..722597a20e4a 100644 --- a/drivers/media/rc/keymaps/rc-purpletv.c +++ b/drivers/media/rc/keymaps/rc-purpletv.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table purpletv[] = { { 0x03, KEY_POWER }, diff --git a/drivers/media/rc/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c index 5e8beee94de4..0105d63c07a9 100644 --- a/drivers/media/rc/keymaps/rc-pv951.c +++ b/drivers/media/rc/keymaps/rc-pv951.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Mark Phalan <phalanm@o2.ie> */ diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c index c3907e211d39..753e43ec787b 100644 --- a/drivers/media/rc/keymaps/rc-rc6-mce.c +++ b/drivers/media/rc/keymaps/rc-rc6-mce.c @@ -13,6 +13,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table rc6_mce[] = { diff --git a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c index 6813d1102118..073694d50f49 100644 --- a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c +++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Zogis Real Audio 220 - 32 keys IR */ diff --git a/drivers/media/rc/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c index 92cc10d2f9cd..f9a07578d985 100644 --- a/drivers/media/rc/keymaps/rc-streamzap.c +++ b/drivers/media/rc/keymaps/rc-streamzap.c @@ -10,6 +10,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table streamzap[] = { /* diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c index 7242ee66f6e0..5039be782bc5 100644 --- a/drivers/media/rc/keymaps/rc-tbs-nec.c +++ b/drivers/media/rc/keymaps/rc-tbs-nec.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table tbs_nec[] = { { 0x84, KEY_POWER2}, /* power */ diff --git a/drivers/media/rc/keymaps/rc-technisat-usb2.c b/drivers/media/rc/keymaps/rc-technisat-usb2.c index 4afe5774f192..f9733bb289d6 100644 --- a/drivers/media/rc/keymaps/rc-technisat-usb2.c +++ b/drivers/media/rc/keymaps/rc-technisat-usb2.c @@ -30,6 +30,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table technisat_usb2[] = { {0x0a0c, KEY_POWER}, diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c index bc38e34b9fda..53629fb0151f 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Terratec Cinergy Hybrid T USB XS Devin Heitmueller <dheitmueller@linuxtv.org> diff --git a/drivers/media/rc/keymaps/rc-terratec-slim-2.c b/drivers/media/rc/keymaps/rc-terratec-slim-2.c index 44093918cf03..4c149ef712dc 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim-2.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim-2.c @@ -20,6 +20,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * TerraTec slim remote, 6 rows, 3 columns. diff --git a/drivers/media/rc/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c index 1abafa5fd303..3d8a19cdb5a2 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* TerraTec slim remote, 7 rows, 4 columns. */ /* Uses NEC extended 0x02bd. */ diff --git a/drivers/media/rc/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c index ef5ba3f32735..f2c3b75d8580 100644 --- a/drivers/media/rc/keymaps/rc-tevii-nec.c +++ b/drivers/media/rc/keymaps/rc-tevii-nec.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table tevii_nec[] = { { 0x0a, KEY_POWER2}, diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c index 98ad085531fd..454e06295692 100644 --- a/drivers/media/rc/keymaps/rc-tivo.c +++ b/drivers/media/rc/keymaps/rc-tivo.c @@ -9,6 +9,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* * Initial mapping is for the TiVo remote included in the Nero LiquidTV bundle, diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand.c b/drivers/media/rc/keymaps/rc-total-media-in-hand.c index 20ac4e19fb3f..5b9f9ec13680 100644 --- a/drivers/media/rc/keymaps/rc-total-media-in-hand.c +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Uses NEC extended 0x02bd */ static struct rc_map_table total_media_in_hand[] = { diff --git a/drivers/media/rc/keymaps/rc-trekstor.c b/drivers/media/rc/keymaps/rc-trekstor.c index f8190ead2e32..f9a2e0fabb9f 100644 --- a/drivers/media/rc/keymaps/rc-trekstor.c +++ b/drivers/media/rc/keymaps/rc-trekstor.c @@ -19,6 +19,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* TrekStor DVB-T USB Stick remote controller. */ /* Imported from af9015.h. diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c index 295f3738e301..caeff85603e3 100644 --- a/drivers/media/rc/keymaps/rc-tt-1500.c +++ b/drivers/media/rc/keymaps/rc-tt-1500.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* for the Technotrend 1500 bundled remotes (grey and black): */ diff --git a/drivers/media/rc/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c index 8bf8df64b081..509299b90c90 100644 --- a/drivers/media/rc/keymaps/rc-twinhan1027.c +++ b/drivers/media/rc/keymaps/rc-twinhan1027.c @@ -1,4 +1,5 @@ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table twinhan_vp1027[] = { { 0x16, KEY_POWER2 }, diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c index 4994d405c0a1..3bd1de1f585c 100644 --- a/drivers/media/rc/keymaps/rc-videomate-m1f.c +++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table videomate_m1f[] = { { 0x01, KEY_POWER }, diff --git a/drivers/media/rc/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c index 9e474a6024e5..8bfc3e8d909d 100644 --- a/drivers/media/rc/keymaps/rc-videomate-s350.c +++ b/drivers/media/rc/keymaps/rc-videomate-s350.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table videomate_s350[] = { { 0x00, KEY_TV}, diff --git a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c index 5f2a46e1f8f6..390ce9431b35 100644 --- a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c +++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> static struct rc_map_table videomate_tv_pvr[] = { { 0x14, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c index bd8d021f40aa..2852bf705064 100644 --- a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c +++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Leadtek Winfast TV USB II Deluxe remote Magnus Alm <magnus.alm@gmail.com> diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c index d8a34c14676a..2df1cba23600 100644 --- a/drivers/media/rc/keymaps/rc-winfast.c +++ b/drivers/media/rc/keymaps/rc-winfast.c @@ -11,6 +11,7 @@ */ #include <media/rc-map.h> +#include <linux/module.h> /* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */ diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 666d4bb5b1fb..29f900065d8a 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -18,6 +18,7 @@ #include <linux/input.h> #include <linux/slab.h> #include <linux/device.h> +#include <linux/module.h> #include "rc-core-priv.h" /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c index 5914390211ff..12eedf4d515a 100644 --- a/drivers/media/video/adp1653.c +++ b/drivers/media/video/adp1653.c @@ -31,6 +31,7 @@ */ #include <linux/delay.h> +#include <linux/module.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c index b388654d48cd..53c496c00fb6 100644 --- a/drivers/media/video/ak881x.c +++ b/drivers/media/video/ak881x.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/videodev2.h> +#include <linux/module.h> #include <media/ak881x.h> #include <media/v4l2-chip-ident.h> diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c index dc5b07a20f69..59c797c15277 100644 --- a/drivers/media/video/cpia2/cpia2_usb.c +++ b/drivers/media/video/cpia2/cpia2_usb.c @@ -31,6 +31,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/module.h> #include "cpia2.h" diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c index b718a3a4bed3..13c380ebb562 100644 --- a/drivers/media/video/cx25840/cx25840-ir.c +++ b/drivers/media/video/cx25840/cx25840-ir.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/kfifo.h> +#include <linux/module.h> #include <media/cx25840.h> #include <media/rc-core.h> diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c index c29ac88ffd78..bd443ee76fff 100644 --- a/drivers/media/video/davinci/dm355_ccdc.c +++ b/drivers/media/video/davinci/dm355_ccdc.c @@ -39,6 +39,7 @@ #include <linux/videodev2.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/module.h> #include <media/davinci/dm355_ccdc.h> #include <media/davinci/vpss.h> diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c index c8b32c1c7386..8051c2956478 100644 --- a/drivers/media/video/davinci/dm644x_ccdc.c +++ b/drivers/media/video/davinci/dm644x_ccdc.c @@ -40,6 +40,7 @@ #include <linux/gfp.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/module.h> #include <media/davinci/dm644x_ccdc.h> #include <media/davinci/vpss.h> diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c index 2a1ac287591d..82e819fa91c0 100644 --- a/drivers/media/video/hdpvr/hdpvr-i2c.c +++ b/drivers/media/video/hdpvr/hdpvr-i2c.c @@ -17,6 +17,7 @@ #include <linux/i2c.h> #include <linux/slab.h> +#include <linux/export.h> #include "hdpvr.h" diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c index 9cb039e593db..a62322d5c0d8 100644 --- a/drivers/media/video/hexium_gemini.c +++ b/drivers/media/video/hexium_gemini.c @@ -26,6 +26,7 @@ #define DEBUG_VARIABLE debug #include <media/saa7146_vv.h> +#include <linux/module.h> static int debug; module_param(debug, int, 0); diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c index 74861a4b601a..23debc967d94 100644 --- a/drivers/media/video/hexium_orion.c +++ b/drivers/media/video/hexium_orion.c @@ -26,6 +26,7 @@ #define DEBUG_VARIABLE debug #include <media/saa7146_vv.h> +#include <linux/module.h> static int debug; module_param(debug, int, 0); diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 8775e262bb6e..eec75bb57203 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -15,6 +15,7 @@ #include <linux/v4l2-mediabus.h> #include <linux/slab.h> #include <linux/videodev2.h> +#include <linux/module.h> #include <media/soc_camera.h> #include <media/v4l2-subdev.h> diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index 5d21d056d6a3..05ab3700647e 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c @@ -21,6 +21,7 @@ #include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/videodev2.h> +#include <linux/module.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 63ae5c61c9bf..e2b1029b16cd 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/log2.h> +#include <linux/module.h> #include <media/soc_camera.h> #include <media/soc_mediabus.h> diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index f023cc092c2b..cf2c0fb95f2f 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -14,6 +14,7 @@ #include <linux/gpio.h> #include <linux/delay.h> #include <linux/v4l2-mediabus.h> +#include <linux/module.h> #include <media/soc_camera.h> #include <media/v4l2-common.h> diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 7ee84cc578b9..0e78477452ff 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/v4l2-mediabus.h> #include <linux/videodev2.h> +#include <linux/module.h> #include <media/soc_camera.h> #include <media/v4l2-chip-ident.h> diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index 893a8b8f5141..db74dd27c722 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c @@ -9,6 +9,7 @@ #include <linux/slab.h> #include <linux/videodev2.h> #include <linux/delay.h> +#include <linux/module.h> #include <asm/div64.h> #include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index b6a29f7de82c..690ee0d42eeb 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -13,6 +13,7 @@ #include <linux/i2c.h> #include <linux/delay.h> #include <linux/log2.h> +#include <linux/module.h> #include <media/soc_camera.h> #include <media/soc_mediabus.h> diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c index c64e1dc4cb4e..f080c162123f 100644 --- a/drivers/media/video/mt9v032.c +++ b/drivers/media/video/mt9v032.c @@ -19,6 +19,7 @@ #include <linux/slab.h> #include <linux/videodev2.h> #include <linux/v4l2-mediabus.h> +#include <linux/module.h> #include <media/mt9v032.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index f0c3968ac7eb..2e4131748438 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -29,6 +29,7 @@ #include <media/tuner.h> #include <media/v4l2-common.h> #include <media/saa7115.h> +#include <linux/module.h> #include "mxb.h" #include "tea6415c.h" diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/video/noon010pc30.c index 6cd21cf91b44..50838bf84204 100644 --- a/drivers/media/video/noon010pc30.c +++ b/drivers/media/video/noon010pc30.c @@ -21,6 +21,7 @@ #include <media/noon010pc30.h> #include <media/v4l2-chip-ident.h> #include <linux/videodev2.h> +#include <linux/module.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-mediabus.h> diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c index eb97bff7116f..45522e603185 100644 --- a/drivers/media/video/omap24xxcam.c +++ b/drivers/media/video/omap24xxcam.c @@ -36,6 +36,7 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/sched.h> +#include <linux/module.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index d5b057207a7b..9f2d26b1d4cb 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -29,6 +29,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/v4l2-mediabus.h> +#include <linux/module.h> #include <media/soc_camera.h> #include <media/v4l2-chip-ident.h> diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index e799331389b1..c6da8f77e1a2 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -28,6 +28,7 @@ pvr2_device_desc structures. #include "pvrusb2-devattr.h" #include <linux/usb.h> +#include <linux/module.h> /* This is needed in order to pull in tuner type ids... */ #include <linux/i2c.h> #include <media/tuner.h> diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 5a6f24d1246d..122b45760f0d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -21,6 +21,7 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/firmware.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index e72d5103e778..885ce11f222d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -19,6 +19,7 @@ */ #include <linux/i2c.h> +#include <linux/module.h> #include <media/ir-kbd-i2c.h> #include "pvrusb2-i2c-core.h" #include "pvrusb2-hdw-internal.h" diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index ce7ac4595276..6d666174dbb4 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -29,6 +29,7 @@ #include "pvrusb2-v4l2.h" #include "pvrusb2-ioread.h" #include <linux/videodev2.h> +#include <linux/module.h> #include <media/v4l2-dev.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index 6afc61689549..9937386a3bae 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <linux/v4l2-mediabus.h> #include <linux/videodev2.h> +#include <linux/module.h> #include <media/rj54n1cb0c.h> #include <media/soc_camera.h> diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 37706eb81f25..ea4f0473ed3b 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -15,6 +15,7 @@ #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/videodev2.h> +#include <linux/module.h> #include <media/sh_mobile_ceu.h> #include <media/sh_mobile_csi2.h> diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c index 6a729879d89e..9644bd861abc 100644 --- a/drivers/media/video/sh_vou.c +++ b/drivers/media/video/sh_vou.c @@ -20,6 +20,7 @@ #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/videodev2.h> +#include <linux/module.h> #include <media/sh_vou.h> #include <media/v4l2-common.h> diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/video/sr030pc30.c index 10aff3f943a8..d1b07aceaf94 100644 --- a/drivers/media/video/sr030pc30.c +++ b/drivers/media/video/sr030pc30.c @@ -19,6 +19,7 @@ #include <linux/i2c.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/module.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> #include <media/v4l2-mediabus.h> diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index b6ee1bd342dc..462caa44ae00 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -27,6 +27,7 @@ */ #include <linux/i2c.h> +#include <linux/module.h> #include <media/v4l2-int-device.h> #include "tcm825x.h" diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c index 84cd1b65b765..a0895bf07487 100644 --- a/drivers/media/video/timblogiw.c +++ b/drivers/media/video/timblogiw.c @@ -27,6 +27,7 @@ #include <linux/interrupt.h> #include <linux/list.h> #include <linux/i2c.h> +#include <linux/module.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-device.h> #include <media/videobuf-dma-contig.h> diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index 9b3e828b0775..926f03931156 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -32,6 +32,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/videodev2.h> +#include <linux/module.h> #include <media/v4l2-device.h> #include <media/v4l2-common.h> diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index e927d25e0d35..6abaa16ae136 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -9,6 +9,7 @@ #include <linux/slab.h> #include <linux/videodev2.h> #include <linux/delay.h> +#include <linux/module.h> #include <media/v4l2-device.h> #include <media/tvp5150.h> #include <media/v4l2-chip-ident.h> diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c index 2e6059a52e9f..7875e80cb2ff 100644 --- a/drivers/media/video/tvp7002.c +++ b/drivers/media/video/tvp7002.c @@ -28,6 +28,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/videodev2.h> +#include <linux/module.h> #include <media/tvp7002.h> #include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index 8f5266157f15..3103d0d020e8 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -24,6 +24,7 @@ #include <linux/list.h> +#include <linux/module.h> #include <media/v4l2-dev.h> #include <media/tuner.h> #include "usbvision.h" diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 5552f8137571..f17f92b86a30 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -20,6 +20,7 @@ #include <linux/ctype.h> #include <linux/slab.h> +#include <linux/export.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 9fc0ae8a526a..0edd618b9ddf 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -20,6 +20,7 @@ #include <linux/types.h> #include <linux/ioctl.h> +#include <linux/module.h> #include <linux/i2c.h> #include <linux/slab.h> #if defined(CONFIG_SPI) diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c index 53b190cf225e..46037f225529 100644 --- a/drivers/media/video/v4l2-event.c +++ b/drivers/media/video/v4l2-event.c @@ -29,6 +29,7 @@ #include <linux/sched.h> #include <linux/slab.h> +#include <linux/export.h> static unsigned sev_pos(const struct v4l2_subscribed_event *sev, unsigned idx) { diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c index 122822d2b8b2..9e3fc040ea20 100644 --- a/drivers/media/video/v4l2-fh.c +++ b/drivers/media/video/v4l2-fh.c @@ -24,6 +24,7 @@ #include <linux/bitops.h> #include <linux/slab.h> +#include <linux/export.h> #include <media/v4l2-dev.h> #include <media/v4l2-fh.h> #include <media/v4l2-event.h> diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index a935bae538ef..f4473494af7a 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -26,6 +26,7 @@ #include <linux/list.h> #include <linux/sort.h> #include <linux/string.h> +#include <linux/module.h> #include <media/v4l2-int-device.h> diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 179e20e23fc4..65ade5f03c2e 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -24,6 +24,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/videodev2.h> +#include <linux/export.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index 8c1d85e27be4..56ff19cdc2ad 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -17,6 +17,7 @@ #include <linux/fs.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/module.h> #define DRIVER_NAME "memstick" diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 4a1909a32b60..9729b92fbfdd 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -20,6 +20,7 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/memstick.h> +#include <linux/module.h> #define DRIVER_NAME "mspro_block" diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index d89d925caecf..6ce70e9615d3 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -17,6 +17,7 @@ #include <linux/highmem.h> #include <linux/memstick.h> #include <linux/slab.h> +#include <linux/module.h> #define DRIVER_NAME "jmb38x_ms" diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 03f71a431c82..b7aacf47703a 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -17,6 +17,7 @@ #include <linux/highmem.h> #include <linux/scatterlist.h> #include <linux/log2.h> +#include <linux/module.h> #include <asm/io.h> #define DRIVER_NAME "tifm_ms" diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c index 73e4658af53c..7190d5239b4f 100644 --- a/drivers/message/i2o/pci.c +++ b/drivers/message/i2o/pci.c @@ -31,6 +31,7 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/i2o.h> +#include <linux/module.h> #include "core.h" #define OSM_DESCRIPTION "I2O-subsystem" diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 4f5725508ac0..60107ee166fc 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -12,6 +12,7 @@ #include <linux/notifier.h> #include <linux/slab.h> #include <linux/err.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/device.h> #include <linux/interrupt.h> diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 64bdeeb1c11a..dedb7f65cea6 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -8,6 +8,7 @@ #include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/fs.h> +#include <linux/module.h> #include <linux/debugfs.h> #include <linux/platform_device.h> diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index 392185965b39..f20feefac190 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c @@ -5,6 +5,7 @@ */ #include <linux/err.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c index f12720dbe126..7ce65f49480f 100644 --- a/drivers/mfd/abx500-core.c +++ b/drivers/mfd/abx500-core.c @@ -8,6 +8,7 @@ #include <linux/list.h> #include <linux/slab.h> #include <linux/err.h> +#include <linux/module.h> #include <linux/mfd/abx500.h> static LIST_HEAD(abx500_list); diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 3bd85bddf6e3..b85bbd7f0d19 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -20,6 +20,7 @@ #include <linux/delay.h> #include <linux/irq.h> #include <linux/gpio.h> +#include <linux/export.h> #include <linux/io.h> #include <linux/slab.h> #include <linux/spinlock.h> diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 3d4a861976ca..8ad88da647b9 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -13,6 +13,7 @@ #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/module.h> #include <linux/err.h> #include <linux/gpio.h> #include <linux/leds.h> diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index dc58750bb71b..5be53ae9b61c 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -25,6 +25,7 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/pm_runtime.h> +#include <linux/module.h> #include <linux/mutex.h> #include <linux/mfd/core.h> #include <linux/mfd/max8997.h> diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 0902523af62d..0f5922812bff 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -17,6 +17,7 @@ #include <linux/mfd/core.h> #include <linux/pm_runtime.h> #include <linux/slab.h> +#include <linux/module.h> int mfd_cell_enable(struct platform_device *pdev) { diff --git a/drivers/mfd/pcf50633-irq.c b/drivers/mfd/pcf50633-irq.c index 1b0192f1efff..048a3b903b01 100644 --- a/drivers/mfd/pcf50633-irq.c +++ b/drivers/mfd/pcf50633-irq.c @@ -15,6 +15,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/mutex.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/mfd/pcf50633/core.h> diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c index eddc19ae464b..83af78c1b0eb 100644 --- a/drivers/mfd/tmio_core.c +++ b/drivers/mfd/tmio_core.c @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */ +#include <linux/export.h> #include <linux/mfd/tmio.h> int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base) diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index b8eef462737a..bfbd66021afd 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -30,6 +30,7 @@ #include <linux/init.h> #include <linux/mutex.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/err.h> diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index deec3ec858bf..3eee45ffb096 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -32,6 +32,7 @@ */ #include <linux/init.h> +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/kthread.h> diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index d97a86945174..f39b756df561 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -22,6 +22,7 @@ #include <linux/mfd/wl1273-core.h> #include <linux/slab.h> +#include <linux/module.h> #define DRIVER_DESC "WL1273 FM Radio Core" diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index e06ba9440cdb..62b4626f4561 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -12,6 +12,7 @@ * */ +#include <linux/module.h> #include <linux/bug.h> #include <linux/err.h> #include <linux/i2c.h> diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c index 35903154ca2e..2208a9d52622 100644 --- a/drivers/misc/ab8500-pwm.c +++ b/drivers/misc/ab8500-pwm.c @@ -10,6 +10,7 @@ #include <linux/pwm.h> #include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> +#include <linux/module.h> /* * PWM Out generators diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 769a4e8e10dc..5bb187781074 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -16,6 +16,7 @@ #include <linux/spinlock.h> #include <linux/atmel-ssc.h> #include <linux/slab.h> +#include <linux/module.h> /* Serialize access to ssc_list and user count */ static DEFINE_SPINLOCK(user_lock); diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c index a844810b50f6..4bcfc3759734 100644 --- a/drivers/misc/atmel_tclib.c +++ b/drivers/misc/atmel_tclib.c @@ -7,6 +7,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/export.h> /* Number of bytes to reserve for the iomem resource */ #define ATMEL_TC_IOMEM_SIZE 256 diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index 82fe2d067827..bfeea9ba702e 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c @@ -22,6 +22,7 @@ #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/delay.h> +#include <linux/module.h> #define BH1780_REG_CONTROL 0x80 #define BH1780_REG_PARTID 0x8A diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 8cebec5e85ee..3f7ad83ed740 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -102,6 +102,7 @@ #include <linux/nmi.h> #include <linux/delay.h> #include <linux/kthread.h> +#include <linux/module.h> #define v1printk(a...) do { \ if (verbose) \ diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c index 9e9bddaa95ae..913de07e577c 100644 --- a/drivers/misc/sgi-gru/grukservices.c +++ b/drivers/misc/sgi-gru/grukservices.c @@ -31,6 +31,7 @@ #include <linux/interrupt.h> #include <linux/uaccess.h> #include <linux/delay.h> +#include <linux/export.h> #include <asm/io_apic.h> #include "gru.h" #include "grulib.h" diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 3a3580566dfc..43ef8d162f2d 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -35,6 +35,7 @@ #include <linux/skbuff.h> #include <linux/ti_wilink_st.h> +#include <linux/module.h> #define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */ diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index a6ef18259da0..ba2479022670 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -11,6 +11,7 @@ #include <linux/tifm.h> #include <linux/dma-mapping.h> +#include <linux/module.h> #define DRIVER_NAME "tifm_7xx1" #define DRIVER_VERSION "0.8" diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index 44d4475a09dd..0bd5349b0422 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/idr.h> +#include <linux/module.h> #define DRIVER_NAME "tifm_core" #define DRIVER_VERSION "0.8" diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 46b6e84d953e..6be49249895a 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -11,9 +11,11 @@ * MMC card bus driver model */ +#include <linux/export.h> #include <linux/device.h> #include <linux/err.h> #include <linux/slab.h> +#include <linux/stat.h> #include <linux/pm_runtime.h> #include <linux/mmc/card.h> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 6045ea469362..3923880118b6 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ #include <linux/moduleparam.h> +#include <linux/export.h> #include <linux/debugfs.h> #include <linux/fs.h> #include <linux/seq_file.h> diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index ca2e4f50f615..e8a5eb38748b 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/idr.h> #include <linux/pagemap.h> +#include <linux/export.h> #include <linux/leds.h> #include <linux/slab.h> #include <linux/suspend.h> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 36270449dd9d..dbf421a6279c 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -12,6 +12,7 @@ #include <linux/err.h> #include <linux/slab.h> +#include <linux/stat.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 007863eea4fb..4d41fa984c93 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -10,6 +10,7 @@ */ #include <linux/slab.h> +#include <linux/export.h> #include <linux/types.h> #include <linux/scatterlist.h> diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c index 6c3cf98a62eb..06ee1aeaacec 100644 --- a/drivers/mmc/core/quirks.c +++ b/drivers/mmc/core/quirks.c @@ -11,6 +11,7 @@ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/mmc/card.h> #ifndef SDIO_VENDOR_ID_TI diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index a230e7f9d77a..f2a05ea40f2a 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -12,6 +12,7 @@ #include <linux/err.h> #include <linux/slab.h> +#include <linux/stat.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 46a785419fab..274ef00b4463 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/types.h> +#include <linux/export.h> #include <linux/scatterlist.h> #include <linux/mmc/host.h> diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index c643b2f78bf1..40989e6bb53a 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -13,6 +13,7 @@ #include <linux/device.h> #include <linux/err.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/pm_runtime.h> diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 0f687cdeb064..b1f3168f791b 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -9,6 +9,7 @@ * your option) any later version. */ +#include <linux/export.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> #include <linux/mmc/sdio.h> diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index b644dd59c16e..68f81b9ee0fb 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/kthread.h> +#include <linux/export.h> #include <linux/wait.h> #include <linux/delay.h> diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index d2856b6b2a62..720f99334a7f 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -913,9 +913,9 @@ request_done: } static void s3cmci_dma_setup(struct s3cmci_host *host, - enum s3c2410_dmasrc source) + enum dma_data_direction source) { - static enum s3c2410_dmasrc last_source = -1; + static enum dma_data_direction last_source = -1; static int setup_ok; if (last_source == source) @@ -1087,7 +1087,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); - s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW); + s3cmci_dma_setup(host, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 067a4cded9cf..89699e861fc1 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -13,6 +13,7 @@ */ #include <linux/err.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/clk.h> diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 66b616ebe536..318a869286ab 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -12,27 +12,17 @@ menuconfig MTD if MTD -config MTD_DEBUG - bool "Debugging" - help - This turns on low-level debugging for the entire MTD sub-system. - Normally, you should say 'N'. - -config MTD_DEBUG_VERBOSE - int "Debugging verbosity (0 = quiet, 3 = noisy)" - depends on MTD_DEBUG - default "0" - help - Determines the verbosity level of the MTD debugging messages. - config MTD_TESTS - tristate "MTD tests support" + tristate "MTD tests support (DANGEROUS)" depends on m help This option includes various MTD tests into compilation. The tests should normally be compiled as kernel modules. The modules perform various checks and verifications when loaded. + WARNING: some of the tests will ERASE entire MTD device which they + test. Do not use these tests unless you really know what you do. + config MTD_REDBOOT_PARTS tristate "RedBoot partition table parsing" ---help--- @@ -137,7 +127,8 @@ config MTD_AFS_PARTS 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example. config MTD_OF_PARTS - def_bool y + tristate "OpenFirmware partitioning information support" + default Y depends on OF help This provides a partition parsing function which derives diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 39664c4229ff..9aaac3ac89f3 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -5,8 +5,8 @@ # Core functionality. obj-$(CONFIG_MTD) += mtd.o mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o -mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o +obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 302372c08b56..89a02f6f65dc 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -162,8 +162,8 @@ afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr) } static int parse_afs_partitions(struct mtd_info *mtd, - struct mtd_partition **pparts, - unsigned long origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { struct mtd_partition *parts; u_int mask, off, idx, sz; diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c index 6697a1ec72d0..f40ea4547554 100644 --- a/drivers/mtd/ar7part.c +++ b/drivers/mtd/ar7part.c @@ -27,6 +27,7 @@ #include <linux/mtd/partitions.h> #include <linux/bootmem.h> #include <linux/magic.h> +#include <linux/module.h> #define AR7_PARTS 4 #define ROOT_OFFSET 0xe0000 @@ -46,7 +47,7 @@ struct ar7_bin_rec { static int create_mtd_partitions(struct mtd_info *master, struct mtd_partition **pparts, - unsigned long origin) + struct mtd_part_parser_data *data) { struct ar7_bin_rec header; unsigned int offset; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 23175edd5634..8d70895a58d6 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -145,8 +145,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd) if (((major << 8) | minor) < 0x3131) { /* CFI version 1.0 => don't trust bootloc */ - DEBUG(MTD_DEBUG_LEVEL1, - "%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n", + pr_debug("%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n", map->name, cfi->mfr, cfi->id); /* AFAICS all 29LV400 with a bottom boot block have a device ID @@ -166,8 +165,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd) * the 8-bit device ID. */ (cfi->mfr == CFI_MFR_MACRONIX)) { - DEBUG(MTD_DEBUG_LEVEL1, - "%s: Macronix MX29LV400C with bottom boot block" + pr_debug("%s: Macronix MX29LV400C with bottom boot block" " detected\n", map->name); extp->TopBottom = 2; /* bottom boot */ } else @@ -178,8 +176,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd) extp->TopBottom = 2; /* bottom boot */ } - DEBUG(MTD_DEBUG_LEVEL1, - "%s: AMD CFI PRI V%c.%c has no boot block field;" + pr_debug("%s: AMD CFI PRI V%c.%c has no boot block field;" " deduced %s from Device ID\n", map->name, major, minor, extp->TopBottom == 2 ? "bottom" : "top"); } @@ -191,7 +188,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; if (cfi->cfiq->BufWriteTimeoutTyp) { - DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" ); + pr_debug("Using buffer write method\n" ); mtd->write = cfi_amdstd_write_buffers; } } @@ -443,8 +440,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) mtd->writesize = 1; mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; - DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n", - __func__, mtd->writebufsize); + pr_debug("MTD %s(): write buffer size %d\n", __func__, + mtd->writebufsize); mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; @@ -1163,7 +1160,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, return ret; } - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", + pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", __func__, adr, datum.x[0] ); /* @@ -1174,7 +1171,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, */ oldd = map_read(map, adr); if (map_word_equal(map, oldd, datum)) { - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP\n", + pr_debug("MTD %s(): NOP\n", __func__); goto op_done; } @@ -1400,7 +1397,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, datum = map_word_load(map, buf); - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", + pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", __func__, adr, datum.x[0] ); XIP_INVAL_CACHED_RANGE(map, adr, len); @@ -1587,7 +1584,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) return ret; } - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", + pr_debug("MTD %s(): ERASE 0x%.8lx\n", __func__, chip->start ); XIP_INVAL_CACHED_RANGE(map, adr, map->size); @@ -1675,7 +1672,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, return ret; } - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", + pr_debug("MTD %s(): ERASE 0x%.8lx\n", __func__, adr ); XIP_INVAL_CACHED_RANGE(map, adr, len); @@ -1801,8 +1798,7 @@ static int do_atmel_lock(struct map_info *map, struct flchip *chip, goto out_unlock; chip->state = FL_LOCKING; - DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", - __func__, adr, len); + pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -1837,8 +1833,7 @@ static int do_atmel_unlock(struct map_info *map, struct flchip *chip, goto out_unlock; chip->state = FL_UNLOCKING; - DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", - __func__, adr, len); + pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index 5e3cc80128aa..89c6595454a5 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h @@ -34,8 +34,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, /* Refuse the operation if the we cannot look behind the chip */ if (chip->start < 0x400000) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): chip->start: %lx wanted >= 0x400000\n", + pr_debug( "MTD %s(): chip->start: %lx wanted >= 0x400000\n", __func__, chip->start ); return -EIO; } diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index ea832ea0e4aa..c443f527a53a 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1914,11 +1914,10 @@ static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi) * (oh and incidentaly the jedec spec - 3.5.3.3) the reset * sequence is *supposed* to be 0xaa at 0x5555, 0x55 at * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips - * as they will ignore the writes and dont care what address + * as they will ignore the writes and don't care what address * the F0 is written to */ if (cfi->addr_unlock1) { - DEBUG( MTD_DEBUG_LEVEL3, - "reset unlock called %x %x \n", + pr_debug( "reset unlock called %x %x \n", cfi->addr_unlock1,cfi->addr_unlock2); cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); @@ -1941,7 +1940,7 @@ static int cfi_jedec_setup(struct map_info *map, struct cfi_private *cfi, int in uint8_t uaddr; if (!(jedec_table[index].devtypes & cfi->device_type)) { - DEBUG(MTD_DEBUG_LEVEL1, "Rejecting potential %s with incompatible %d-bit device type\n", + pr_debug("Rejecting potential %s with incompatible %d-bit device type\n", jedec_table[index].name, 4 * (1<<cfi->device_type)); return 0; } @@ -2021,7 +2020,7 @@ static inline int jedec_match( uint32_t base, * there aren't. */ if (finfo->dev_id > 0xff) { - DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n", + pr_debug("%s(): ID is not 8bit\n", __func__); goto match_done; } @@ -2045,12 +2044,10 @@ static inline int jedec_match( uint32_t base, } /* the part size must fit in the memory window */ - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", + pr_debug("MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", __func__, base, 1 << finfo->dev_size, base + (1 << finfo->dev_size) ); if ( base + cfi_interleave(cfi) * ( 1 << finfo->dev_size ) > map->size ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", + pr_debug("MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", __func__, finfo->mfr_id, finfo->dev_id, 1 << finfo->dev_size ); goto match_done; @@ -2061,13 +2058,12 @@ static inline int jedec_match( uint32_t base, uaddr = finfo->uaddr; - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", + pr_debug("MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", __func__, cfi->addr_unlock1, cfi->addr_unlock2 ); if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr && ( unlock_addrs[uaddr].addr1 / cfi->device_type != cfi->addr_unlock1 || unlock_addrs[uaddr].addr2 / cfi->device_type != cfi->addr_unlock2 ) ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): 0x%.4x 0x%.4x did not match\n", + pr_debug("MTD %s(): 0x%.4x 0x%.4x did not match\n", __func__, unlock_addrs[uaddr].addr1, unlock_addrs[uaddr].addr2); @@ -2083,15 +2079,13 @@ static inline int jedec_match( uint32_t base, * FIXME - write a driver that takes all of the chip info as * module parameters, doesn't probe but forces a load. */ - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): check ID's disappear when not in ID mode\n", + pr_debug("MTD %s(): check ID's disappear when not in ID mode\n", __func__ ); jedec_reset( base, map, cfi ); mfr = jedec_read_mfr( map, base, cfi ); id = jedec_read_id( map, base, cfi ); if ( mfr == cfi->mfr && id == cfi->id ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n" + pr_debug("MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n" "You might need to manually specify JEDEC parameters.\n", __func__, cfi->mfr, cfi->id ); goto match_done; @@ -2104,7 +2098,7 @@ static inline int jedec_match( uint32_t base, * Put the device back in ID mode - only need to do this if we * were truly frobbing a real device. */ - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ ); + pr_debug("MTD %s(): return to ID mode\n", __func__ ); if (cfi->addr_unlock1) { cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); @@ -2167,13 +2161,11 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, cfi->mfr = jedec_read_mfr(map, base, cfi); cfi->id = jedec_read_id(map, base, cfi); - DEBUG(MTD_DEBUG_LEVEL3, - "Search for id:(%02x %02x) interleave(%d) type(%d)\n", + pr_debug("Search for id:(%02x %02x) interleave(%d) type(%d)\n", cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type); for (i = 0; i < ARRAY_SIZE(jedec_table); i++) { if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n", + pr_debug("MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n", __func__, cfi->mfr, cfi->id, cfi->addr_unlock1, cfi->addr_unlock2 ); if (!cfi_jedec_setup(map, cfi, i)) diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index e790f38893b0..ddf9ec6d9168 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -43,6 +43,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/bootmem.h> +#include <linux/module.h> /* error message prefix */ #define ERRP "mtd: " @@ -188,10 +189,7 @@ static struct mtd_partition * newpart(char *s, extra_mem_size; parts = kzalloc(alloc_size, GFP_KERNEL); if (!parts) - { - printk(KERN_ERR ERRP "out of memory\n"); return NULL; - } extra_mem = (unsigned char *)(parts + *num_parts); } /* enter this partition (offset will be calculated later if it is zero at this point) */ @@ -316,8 +314,8 @@ static int mtdpart_setup_real(char *s) * the first one in the chain if a NULL mtd_id is passed in. */ static int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - unsigned long origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { unsigned long offset; int i; diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 35081ce77fbd..283d887f7825 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -249,6 +249,16 @@ config MTD_DOC2001PLUS under "NAND Flash Device Drivers" (currently that driver does not support all Millennium Plus devices). +config MTD_DOCG3 + tristate "M-Systems Disk-On-Chip G3" + ---help--- + This provides an MTD device driver for the M-Systems DiskOnChip + G3 devices. + + The driver provides access to G3 DiskOnChip, distributed by + M-Systems and now Sandisk. The support is very experimental, + and doesn't give access to any write operations. + config MTD_DOCPROBE tristate select MTD_DOCECC @@ -268,8 +278,7 @@ config MTD_DOCPROBE_ADVANCED config MTD_DOCPROBE_ADDRESS hex "Physical address of DiskOnChip" if MTD_DOCPROBE_ADVANCED depends on MTD_DOCPROBE - default "0x0000" if MTD_DOCPROBE_ADVANCED - default "0" if !MTD_DOCPROBE_ADVANCED + default "0x0" ---help--- By default, the probe for DiskOnChip devices will look for a DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index f3226b1d38fc..56c7cd462f11 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_MTD_DOC2000) += doc2000.o obj-$(CONFIG_MTD_DOC2001) += doc2001.o obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o +obj-$(CONFIG_MTD_DOCG3) += docg3.o obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o obj-$(CONFIG_MTD_DOCECC) += docecc.o obj-$(CONFIG_MTD_SLRAM) += slram.o @@ -17,3 +18,5 @@ obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_M25P80) += m25p80.o obj-$(CONFIG_MTD_SST25L) += sst25l.o + +CFLAGS_docg3.o += -I$(src)
\ No newline at end of file diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index f7fbf6025ef2..e9fad9151219 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -82,8 +82,7 @@ static int _DoC_WaitReady(struct DiskOnChip *doc) void __iomem *docptr = doc->virtadr; unsigned long timeo = jiffies + (HZ * 10); - DEBUG(MTD_DEBUG_LEVEL3, - "_DoC_WaitReady called for out-of-line wait\n"); + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); /* Out-of-line routine to wait for chip response */ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { @@ -92,7 +91,7 @@ static int _DoC_WaitReady(struct DiskOnChip *doc) DoC_Delay(doc, 2); if (time_after(jiffies, timeo)) { - DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); + pr_debug("_DoC_WaitReady timed out.\n"); return -EIO; } udelay(1); @@ -323,8 +322,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) /* Reset the chip */ if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) { - DEBUG(MTD_DEBUG_LEVEL2, - "DoC_Command (reset) for %d,%d returned true\n", + pr_debug("DoC_Command (reset) for %d,%d returned true\n", floor, chip); return 0; } @@ -332,8 +330,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) /* Read the NAND chip ID: 1. Send ReadID command */ if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) { - DEBUG(MTD_DEBUG_LEVEL2, - "DoC_Command (ReadID) for %d,%d returned true\n", + pr_debug("DoC_Command (ReadID) for %d,%d returned true\n", floor, chip); return 0; } @@ -699,7 +696,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, #ifdef ECC_DEBUG printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from); #endif - /* Read the ECC syndrom through the DiskOnChip ECC + /* Read the ECC syndrome through the DiskOnChip ECC logic. These syndrome will be all ZERO when there is no error */ for (i = 0; i < 6; i++) { @@ -930,7 +927,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; @@ -1094,7 +1091,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, struct DiskOnChip *this = mtd->priv; int ret; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); mutex_lock(&this->lock); ret = doc_write_oob_nolock(mtd, ofs + ops->ooboffs, ops->len, diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 241192f05bc8..a3f7a27499be 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -55,15 +55,14 @@ static int _DoC_WaitReady(void __iomem * docptr) { unsigned short c = 0xffff; - DEBUG(MTD_DEBUG_LEVEL3, - "_DoC_WaitReady called for out-of-line wait\n"); + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); /* Out-of-line routine to wait for chip response */ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c) ; if (c == 0) - DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); + pr_debug("_DoC_WaitReady timed out.\n"); return (c == 0); } @@ -464,7 +463,7 @@ static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, #ifdef ECC_DEBUG printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); #endif - /* Read the ECC syndrom through the DiskOnChip ECC logic. + /* Read the ECC syndrome through the DiskOnChip ECC logic. These syndrome will be all ZERO when there is no error */ for (i = 0; i < 6; i++) { syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i); @@ -632,7 +631,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; @@ -690,7 +689,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 09ae0adc3ad0..99351bc3e0ed 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -61,15 +61,14 @@ static int _DoC_WaitReady(void __iomem * docptr) { unsigned int c = 0xffff; - DEBUG(MTD_DEBUG_LEVEL3, - "_DoC_WaitReady called for out-of-line wait\n"); + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); /* Out-of-line routine to wait for chip response */ while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c) ; if (c == 0) - DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); + pr_debug("_DoC_WaitReady timed out.\n"); return (c == 0); } @@ -655,7 +654,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, #ifdef ECC_DEBUG printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); #endif - /* Read the ECC syndrom through the DiskOnChip ECC logic. + /* Read the ECC syndrome through the DiskOnChip ECC logic. These syndrome will be all ZERO when there is no error */ for (i = 0; i < 6; i++) syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); @@ -835,7 +834,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; @@ -920,7 +919,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index 37ef29a73ee4..4a1c39b6f37d 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c @@ -2,7 +2,7 @@ * ECC algorithm for M-systems disk on chip. We use the excellent Reed * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the * GNU GPL License. The rest is simply to convert the disk on chip - * syndrom into a standard syndom. + * syndrome into a standard syndome. * * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c new file mode 100644 index 000000000000..bdcf5df982e8 --- /dev/null +++ b/drivers/mtd/devices/docg3.c @@ -0,0 +1,1114 @@ +/* + * Handles the M-Systems DiskOnChip G3 chip + * + * Copyright (C) 2011 Robert Jarzmik + * + * 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/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> + +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#define CREATE_TRACE_POINTS +#include "docg3.h" + +/* + * This driver handles the DiskOnChip G3 flash memory. + * + * As no specification is available from M-Systems/Sandisk, this drivers lacks + * several functions available on the chip, as : + * - block erase + * - page write + * - IPL write + * - ECC fixing (lack of BCH algorith understanding) + * - powerdown / powerup + * + * The bus data width (8bits versus 16bits) is not handled (if_cfg flag), and + * the driver assumes a 16bits data bus. + * + * DocG3 relies on 2 ECC algorithms, which are handled in hardware : + * - a 1 byte Hamming code stored in the OOB for each page + * - a 7 bytes BCH code stored in the OOB for each page + * The BCH part is only used for check purpose, no correction is available as + * some information is missing. What is known is that : + * - BCH is in GF(2^14) + * - BCH is over data of 520 bytes (512 page + 7 page_info bytes + * + 1 hamming byte) + * - BCH can correct up to 4 bits (t = 4) + * - BCH syndroms are calculated in hardware, and checked in hardware as well + * + */ + +static inline u8 doc_readb(struct docg3 *docg3, u16 reg) +{ + u8 val = readb(docg3->base + reg); + + trace_docg3_io(0, 8, reg, (int)val); + return val; +} + +static inline u16 doc_readw(struct docg3 *docg3, u16 reg) +{ + u16 val = readw(docg3->base + reg); + + trace_docg3_io(0, 16, reg, (int)val); + return val; +} + +static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg) +{ + writeb(val, docg3->base + reg); + trace_docg3_io(1, 16, reg, val); +} + +static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg) +{ + writew(val, docg3->base + reg); + trace_docg3_io(1, 16, reg, val); +} + +static inline void doc_flash_command(struct docg3 *docg3, u8 cmd) +{ + doc_writeb(docg3, cmd, DOC_FLASHCOMMAND); +} + +static inline void doc_flash_sequence(struct docg3 *docg3, u8 seq) +{ + doc_writeb(docg3, seq, DOC_FLASHSEQUENCE); +} + +static inline void doc_flash_address(struct docg3 *docg3, u8 addr) +{ + doc_writeb(docg3, addr, DOC_FLASHADDRESS); +} + +static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL }; + +static int doc_register_readb(struct docg3 *docg3, int reg) +{ + u8 val; + + doc_writew(docg3, reg, DOC_READADDRESS); + val = doc_readb(docg3, reg); + doc_vdbg("Read register %04x : %02x\n", reg, val); + return val; +} + +static int doc_register_readw(struct docg3 *docg3, int reg) +{ + u16 val; + + doc_writew(docg3, reg, DOC_READADDRESS); + val = doc_readw(docg3, reg); + doc_vdbg("Read register %04x : %04x\n", reg, val); + return val; +} + +/** + * doc_delay - delay docg3 operations + * @docg3: the device + * @nbNOPs: the number of NOPs to issue + * + * As no specification is available, the right timings between chip commands are + * unknown. The only available piece of information are the observed nops on a + * working docg3 chip. + * Therefore, doc_delay relies on a busy loop of NOPs, instead of scheduler + * friendlier msleep() functions or blocking mdelay(). + */ +static void doc_delay(struct docg3 *docg3, int nbNOPs) +{ + int i; + + doc_dbg("NOP x %d\n", nbNOPs); + for (i = 0; i < nbNOPs; i++) + doc_writeb(docg3, 0, DOC_NOP); +} + +static int is_prot_seq_error(struct docg3 *docg3) +{ + int ctrl; + + ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + return ctrl & (DOC_CTRL_PROTECTION_ERROR | DOC_CTRL_SEQUENCE_ERROR); +} + +static int doc_is_ready(struct docg3 *docg3) +{ + int ctrl; + + ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + return ctrl & DOC_CTRL_FLASHREADY; +} + +static int doc_wait_ready(struct docg3 *docg3) +{ + int maxWaitCycles = 100; + + do { + doc_delay(docg3, 4); + cpu_relax(); + } while (!doc_is_ready(docg3) && maxWaitCycles--); + doc_delay(docg3, 2); + if (maxWaitCycles > 0) + return 0; + else + return -EIO; +} + +static int doc_reset_seq(struct docg3 *docg3) +{ + int ret; + + doc_writeb(docg3, 0x10, DOC_FLASHCONTROL); + doc_flash_sequence(docg3, DOC_SEQ_RESET); + doc_flash_command(docg3, DOC_CMD_RESET); + doc_delay(docg3, 2); + ret = doc_wait_ready(docg3); + + doc_dbg("doc_reset_seq() -> isReady=%s\n", ret ? "false" : "true"); + return ret; +} + +/** + * doc_read_data_area - Read data from data area + * @docg3: the device + * @buf: the buffer to fill in + * @len: the lenght to read + * @first: first time read, DOC_READADDRESS should be set + * + * Reads bytes from flash data. Handles the single byte / even bytes reads. + */ +static void doc_read_data_area(struct docg3 *docg3, void *buf, int len, + int first) +{ + int i, cdr, len4; + u16 data16, *dst16; + u8 data8, *dst8; + + doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); + cdr = len & 0x3; + len4 = len - cdr; + + if (first) + doc_writew(docg3, DOC_IOSPACE_DATA, DOC_READADDRESS); + dst16 = buf; + for (i = 0; i < len4; i += 2) { + data16 = doc_readw(docg3, DOC_IOSPACE_DATA); + *dst16 = data16; + dst16++; + } + + if (cdr) { + doc_writew(docg3, DOC_IOSPACE_DATA | DOC_READADDR_ONE_BYTE, + DOC_READADDRESS); + doc_delay(docg3, 1); + dst8 = (u8 *)dst16; + for (i = 0; i < cdr; i++) { + data8 = doc_readb(docg3, DOC_IOSPACE_DATA); + *dst8 = data8; + dst8++; + } + } +} + +/** + * doc_set_data_mode - Sets the flash to reliable data mode + * @docg3: the device + * + * The reliable data mode is a bit slower than the fast mode, but less errors + * occur. Entering the reliable mode cannot be done without entering the fast + * mode first. + */ +static void doc_set_reliable_mode(struct docg3 *docg3) +{ + doc_dbg("doc_set_reliable_mode()\n"); + doc_flash_sequence(docg3, DOC_SEQ_SET_MODE); + doc_flash_command(docg3, DOC_CMD_FAST_MODE); + doc_flash_command(docg3, DOC_CMD_RELIABLE_MODE); + doc_delay(docg3, 2); +} + +/** + * doc_set_asic_mode - Set the ASIC mode + * @docg3: the device + * @mode: the mode + * + * The ASIC can work in 3 modes : + * - RESET: all registers are zeroed + * - NORMAL: receives and handles commands + * - POWERDOWN: minimal poweruse, flash parts shut off + */ +static void doc_set_asic_mode(struct docg3 *docg3, u8 mode) +{ + int i; + + for (i = 0; i < 12; i++) + doc_readb(docg3, DOC_IOSPACE_IPL); + + mode |= DOC_ASICMODE_MDWREN; + doc_dbg("doc_set_asic_mode(%02x)\n", mode); + doc_writeb(docg3, mode, DOC_ASICMODE); + doc_writeb(docg3, ~mode, DOC_ASICMODECONFIRM); + doc_delay(docg3, 1); +} + +/** + * doc_set_device_id - Sets the devices id for cascaded G3 chips + * @docg3: the device + * @id: the chip to select (amongst 0, 1, 2, 3) + * + * There can be 4 cascaded G3 chips. This function selects the one which will + * should be the active one. + */ +static void doc_set_device_id(struct docg3 *docg3, int id) +{ + u8 ctrl; + + doc_dbg("doc_set_device_id(%d)\n", id); + doc_writeb(docg3, id, DOC_DEVICESELECT); + ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + + ctrl &= ~DOC_CTRL_VIOLATION; + ctrl |= DOC_CTRL_CE; + doc_writeb(docg3, ctrl, DOC_FLASHCONTROL); +} + +/** + * doc_set_extra_page_mode - Change flash page layout + * @docg3: the device + * + * Normally, the flash page is split into the data (512 bytes) and the out of + * band data (16 bytes). For each, 4 more bytes can be accessed, where the wear + * leveling counters are stored. To access this last area of 4 bytes, a special + * mode must be input to the flash ASIC. + * + * Returns 0 if no error occured, -EIO else. + */ +static int doc_set_extra_page_mode(struct docg3 *docg3) +{ + int fctrl; + + doc_dbg("doc_set_extra_page_mode()\n"); + doc_flash_sequence(docg3, DOC_SEQ_PAGE_SIZE_532); + doc_flash_command(docg3, DOC_CMD_PAGE_SIZE_532); + doc_delay(docg3, 2); + + fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + if (fctrl & (DOC_CTRL_PROTECTION_ERROR | DOC_CTRL_SEQUENCE_ERROR)) + return -EIO; + else + return 0; +} + +/** + * doc_seek - Set both flash planes to the specified block, page for reading + * @docg3: the device + * @block0: the first plane block index + * @block1: the second plane block index + * @page: the page index within the block + * @wear: if true, read will occur on the 4 extra bytes of the wear area + * @ofs: offset in page to read + * + * Programs the flash even and odd planes to the specific block and page. + * Alternatively, programs the flash to the wear area of the specified page. + */ +static int doc_read_seek(struct docg3 *docg3, int block0, int block1, int page, + int wear, int ofs) +{ + int sector, ret = 0; + + doc_dbg("doc_seek(blocks=(%d,%d), page=%d, ofs=%d, wear=%d)\n", + block0, block1, page, ofs, wear); + + if (!wear && (ofs < 2 * DOC_LAYOUT_PAGE_SIZE)) { + doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE1); + doc_flash_command(docg3, DOC_CMD_READ_PLANE1); + doc_delay(docg3, 2); + } else { + doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE2); + doc_flash_command(docg3, DOC_CMD_READ_PLANE2); + doc_delay(docg3, 2); + } + + doc_set_reliable_mode(docg3); + if (wear) + ret = doc_set_extra_page_mode(docg3); + if (ret) + goto out; + + sector = (block0 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK); + doc_flash_sequence(docg3, DOC_SEQ_READ); + doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR); + doc_delay(docg3, 1); + doc_flash_address(docg3, sector & 0xff); + doc_flash_address(docg3, (sector >> 8) & 0xff); + doc_flash_address(docg3, (sector >> 16) & 0xff); + doc_delay(docg3, 1); + + sector = (block1 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK); + doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR); + doc_delay(docg3, 1); + doc_flash_address(docg3, sector & 0xff); + doc_flash_address(docg3, (sector >> 8) & 0xff); + doc_flash_address(docg3, (sector >> 16) & 0xff); + doc_delay(docg3, 2); + +out: + return ret; +} + +/** + * doc_read_page_ecc_init - Initialize hardware ECC engine + * @docg3: the device + * @len: the number of bytes covered by the ECC (BCH covered) + * + * The function does initialize the hardware ECC engine to compute the Hamming + * ECC (on 1 byte) and the BCH Syndroms (on 7 bytes). + * + * Return 0 if succeeded, -EIO on error + */ +static int doc_read_page_ecc_init(struct docg3 *docg3, int len) +{ + doc_writew(docg3, DOC_ECCCONF0_READ_MODE + | DOC_ECCCONF0_BCH_ENABLE | DOC_ECCCONF0_HAMMING_ENABLE + | (len & DOC_ECCCONF0_DATA_BYTES_MASK), + DOC_ECCCONF0); + doc_delay(docg3, 4); + doc_register_readb(docg3, DOC_FLASHCONTROL); + return doc_wait_ready(docg3); +} + +/** + * doc_read_page_prepare - Prepares reading data from a flash page + * @docg3: the device + * @block0: the first plane block index on flash memory + * @block1: the second plane block index on flash memory + * @page: the page index in the block + * @offset: the offset in the page (must be a multiple of 4) + * + * Prepares the page to be read in the flash memory : + * - tell ASIC to map the flash pages + * - tell ASIC to be in read mode + * + * After a call to this method, a call to doc_read_page_finish is mandatory, + * to end the read cycle of the flash. + * + * Read data from a flash page. The length to be read must be between 0 and + * (page_size + oob_size + wear_size), ie. 532, and a multiple of 4 (because + * the extra bytes reading is not implemented). + * + * As pages are grouped by 2 (in 2 planes), reading from a page must be done + * in two steps: + * - one read of 512 bytes at offset 0 + * - one read of 512 bytes at offset 512 + 16 + * + * Returns 0 if successful, -EIO if a read error occured. + */ +static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1, + int page, int offset) +{ + int wear_area = 0, ret = 0; + + doc_dbg("doc_read_page_prepare(blocks=(%d,%d), page=%d, ofsInPage=%d)\n", + block0, block1, page, offset); + if (offset >= DOC_LAYOUT_WEAR_OFFSET) + wear_area = 1; + if (!wear_area && offset > (DOC_LAYOUT_PAGE_OOB_SIZE * 2)) + return -EINVAL; + + doc_set_device_id(docg3, docg3->device_id); + ret = doc_reset_seq(docg3); + if (ret) + goto err; + + /* Program the flash address block and page */ + ret = doc_read_seek(docg3, block0, block1, page, wear_area, offset); + if (ret) + goto err; + + doc_flash_command(docg3, DOC_CMD_READ_ALL_PLANES); + doc_delay(docg3, 2); + doc_wait_ready(docg3); + + doc_flash_command(docg3, DOC_CMD_SET_ADDR_READ); + doc_delay(docg3, 1); + if (offset >= DOC_LAYOUT_PAGE_SIZE * 2) + offset -= 2 * DOC_LAYOUT_PAGE_SIZE; + doc_flash_address(docg3, offset >> 2); + doc_delay(docg3, 1); + doc_wait_ready(docg3); + + doc_flash_command(docg3, DOC_CMD_READ_FLASH); + + return 0; +err: + doc_writeb(docg3, 0, DOC_DATAEND); + doc_delay(docg3, 2); + return -EIO; +} + +/** + * doc_read_page_getbytes - Reads bytes from a prepared page + * @docg3: the device + * @len: the number of bytes to be read (must be a multiple of 4) + * @buf: the buffer to be filled in + * @first: 1 if first time read, DOC_READADDRESS should be set + * + */ +static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, + int first) +{ + doc_read_data_area(docg3, buf, len, first); + doc_delay(docg3, 2); + return len; +} + +/** + * doc_get_hw_bch_syndroms - Get hardware calculated BCH syndroms + * @docg3: the device + * @syns: the array of 7 integers where the syndroms will be stored + */ +static void doc_get_hw_bch_syndroms(struct docg3 *docg3, int *syns) +{ + int i; + + for (i = 0; i < DOC_ECC_BCH_SIZE; i++) + syns[i] = doc_register_readb(docg3, DOC_BCH_SYNDROM(i)); +} + +/** + * doc_read_page_finish - Ends reading of a flash page + * @docg3: the device + * + * As a side effect, resets the chip selector to 0. This ensures that after each + * read operation, the floor 0 is selected. Therefore, if the systems halts, the + * reboot will boot on floor 0, where the IPL is. + */ +static void doc_read_page_finish(struct docg3 *docg3) +{ + doc_writeb(docg3, 0, DOC_DATAEND); + doc_delay(docg3, 2); + doc_set_device_id(docg3, 0); +} + +/** + * calc_block_sector - Calculate blocks, pages and ofs. + + * @from: offset in flash + * @block0: first plane block index calculated + * @block1: second plane block index calculated + * @page: page calculated + * @ofs: offset in page + */ +static void calc_block_sector(loff_t from, int *block0, int *block1, int *page, + int *ofs) +{ + uint sector; + + sector = from / DOC_LAYOUT_PAGE_SIZE; + *block0 = sector / (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES) + * DOC_LAYOUT_NBPLANES; + *block1 = *block0 + 1; + *page = sector % (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES); + *page /= DOC_LAYOUT_NBPLANES; + if (sector % 2) + *ofs = DOC_LAYOUT_PAGE_OOB_SIZE; + else + *ofs = 0; +} + +/** + * doc_read - Read bytes from flash + * @mtd: the device + * @from: the offset from first block and first page, in bytes, aligned on page + * size + * @len: the number of bytes to read (must be a multiple of 4) + * @retlen: the number of bytes actually read + * @buf: the filled in buffer + * + * Reads flash memory pages. This function does not read the OOB chunk, but only + * the page data. + * + * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured + */ +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct docg3 *docg3 = mtd->priv; + int block0, block1, page, readlen, ret, ofs = 0; + int syn[DOC_ECC_BCH_SIZE], eccconf1; + u8 oob[DOC_LAYOUT_OOB_SIZE]; + + ret = -EINVAL; + doc_dbg("doc_read(from=%lld, len=%zu, buf=%p)\n", from, len, buf); + if (from % DOC_LAYOUT_PAGE_SIZE) + goto err; + if (len % 4) + goto err; + calc_block_sector(from, &block0, &block1, &page, &ofs); + if (block1 > docg3->max_block) + goto err; + + *retlen = 0; + ret = 0; + readlen = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); + while (!ret && len > 0) { + readlen = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); + ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); + if (ret < 0) + goto err; + ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_COVERED_BYTES); + if (ret < 0) + goto err_in_read; + ret = doc_read_page_getbytes(docg3, readlen, buf, 1); + if (ret < readlen) + goto err_in_read; + ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE, + oob, 0); + if (ret < DOC_LAYOUT_OOB_SIZE) + goto err_in_read; + + *retlen += readlen; + buf += readlen; + len -= readlen; + + ofs ^= DOC_LAYOUT_PAGE_OOB_SIZE; + if (ofs == 0) + page += 2; + if (page > DOC_ADDR_PAGE_MASK) { + page = 0; + block0 += 2; + block1 += 2; + } + + /* + * There should be a BCH bitstream fixing algorithm here ... + * By now, a page read failure is triggered by BCH error + */ + doc_get_hw_bch_syndroms(docg3, syn); + eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); + + doc_dbg("OOB - INFO: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + oob[0], oob[1], oob[2], oob[3], oob[4], + oob[5], oob[6]); + doc_dbg("OOB - HAMMING: %02x\n", oob[7]); + doc_dbg("OOB - BCH_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + oob[8], oob[9], oob[10], oob[11], oob[12], + oob[13], oob[14]); + doc_dbg("OOB - UNUSED: %02x\n", oob[15]); + doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1); + doc_dbg("ECC BCH syndrom: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + syn[0], syn[1], syn[2], syn[3], syn[4], syn[5], syn[6]); + + ret = -EBADMSG; + if (block0 >= DOC_LAYOUT_BLOCK_FIRST_DATA) { + if (eccconf1 & DOC_ECCCONF1_BCH_SYNDROM_ERR) + goto err_in_read; + if (is_prot_seq_error(docg3)) + goto err_in_read; + } + doc_read_page_finish(docg3); + } + + return 0; +err_in_read: + doc_read_page_finish(docg3); +err: + return ret; +} + +/** + * doc_read_oob - Read out of band bytes from flash + * @mtd: the device + * @from: the offset from first block and first page, in bytes, aligned on page + * size + * @ops: the mtd oob structure + * + * Reads flash memory OOB area of pages. + * + * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured + */ +static int doc_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct docg3 *docg3 = mtd->priv; + int block0, block1, page, ofs, ret; + u8 *buf = ops->oobbuf; + size_t len = ops->ooblen; + + doc_dbg("doc_read_oob(from=%lld, buf=%p, len=%zu)\n", from, buf, len); + if (len != DOC_LAYOUT_OOB_SIZE) + return -EINVAL; + + switch (ops->mode) { + case MTD_OPS_PLACE_OOB: + buf += ops->ooboffs; + break; + default: + break; + } + + calc_block_sector(from, &block0, &block1, &page, &ofs); + if (block1 > docg3->max_block) + return -EINVAL; + + ret = doc_read_page_prepare(docg3, block0, block1, page, + ofs + DOC_LAYOUT_PAGE_SIZE); + if (!ret) + ret = doc_read_page_ecc_init(docg3, DOC_LAYOUT_OOB_SIZE); + if (!ret) + ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE, + buf, 1); + doc_read_page_finish(docg3); + + if (ret > 0) + ops->oobretlen = ret; + else + ops->oobretlen = 0; + return (ret > 0) ? 0 : ret; +} + +static int doc_reload_bbt(struct docg3 *docg3) +{ + int block = DOC_LAYOUT_BLOCK_BBT; + int ret = 0, nbpages, page; + u_char *buf = docg3->bbt; + + nbpages = DIV_ROUND_UP(docg3->max_block + 1, 8 * DOC_LAYOUT_PAGE_SIZE); + for (page = 0; !ret && (page < nbpages); page++) { + ret = doc_read_page_prepare(docg3, block, block + 1, + page + DOC_LAYOUT_PAGE_BBT, 0); + if (!ret) + ret = doc_read_page_ecc_init(docg3, + DOC_LAYOUT_PAGE_SIZE); + if (!ret) + doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, + buf, 1); + buf += DOC_LAYOUT_PAGE_SIZE; + } + doc_read_page_finish(docg3); + return ret; +} + +/** + * doc_block_isbad - Checks whether a block is good or not + * @mtd: the device + * @from: the offset to find the correct block + * + * Returns 1 if block is bad, 0 if block is good + */ +static int doc_block_isbad(struct mtd_info *mtd, loff_t from) +{ + struct docg3 *docg3 = mtd->priv; + int block0, block1, page, ofs, is_good; + + calc_block_sector(from, &block0, &block1, &page, &ofs); + doc_dbg("doc_block_isbad(from=%lld) => block=(%d,%d), page=%d, ofs=%d\n", + from, block0, block1, page, ofs); + + if (block0 < DOC_LAYOUT_BLOCK_FIRST_DATA) + return 0; + if (block1 > docg3->max_block) + return -EINVAL; + + is_good = docg3->bbt[block0 >> 3] & (1 << (block0 & 0x7)); + return !is_good; +} + +/** + * doc_get_erase_count - Get block erase count + * @docg3: the device + * @from: the offset in which the block is. + * + * Get the number of times a block was erased. The number is the maximum of + * erase times between first and second plane (which should be equal normally). + * + * Returns The number of erases, or -EINVAL or -EIO on error. + */ +static int doc_get_erase_count(struct docg3 *docg3, loff_t from) +{ + u8 buf[DOC_LAYOUT_WEAR_SIZE]; + int ret, plane1_erase_count, plane2_erase_count; + int block0, block1, page, ofs; + + doc_dbg("doc_get_erase_count(from=%lld, buf=%p)\n", from, buf); + if (from % DOC_LAYOUT_PAGE_SIZE) + return -EINVAL; + calc_block_sector(from, &block0, &block1, &page, &ofs); + if (block1 > docg3->max_block) + return -EINVAL; + + ret = doc_reset_seq(docg3); + if (!ret) + ret = doc_read_page_prepare(docg3, block0, block1, page, + ofs + DOC_LAYOUT_WEAR_OFFSET); + if (!ret) + ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, + buf, 1); + doc_read_page_finish(docg3); + + if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) + return -EIO; + plane1_erase_count = (u8)(~buf[1]) | ((u8)(~buf[4]) << 8) + | ((u8)(~buf[5]) << 16); + plane2_erase_count = (u8)(~buf[3]) | ((u8)(~buf[6]) << 8) + | ((u8)(~buf[7]) << 16); + + return max(plane1_erase_count, plane2_erase_count); +} + +/* + * Debug sysfs entries + */ +static int dbg_flashctrl_show(struct seq_file *s, void *p) +{ + struct docg3 *docg3 = (struct docg3 *)s->private; + + int pos = 0; + u8 fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + + pos += seq_printf(s, + "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", + fctrl, + fctrl & DOC_CTRL_VIOLATION ? "protocol violation" : "-", + fctrl & DOC_CTRL_CE ? "active" : "inactive", + fctrl & DOC_CTRL_PROTECTION_ERROR ? "protection error" : "-", + fctrl & DOC_CTRL_SEQUENCE_ERROR ? "sequence error" : "-", + fctrl & DOC_CTRL_FLASHREADY ? "ready" : "not ready"); + return pos; +} +DEBUGFS_RO_ATTR(flashcontrol, dbg_flashctrl_show); + +static int dbg_asicmode_show(struct seq_file *s, void *p) +{ + struct docg3 *docg3 = (struct docg3 *)s->private; + + int pos = 0; + int pctrl = doc_register_readb(docg3, DOC_ASICMODE); + int mode = pctrl & 0x03; + + pos += seq_printf(s, + "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", + pctrl, + pctrl & DOC_ASICMODE_RAM_WE ? 1 : 0, + pctrl & DOC_ASICMODE_RSTIN_RESET ? 1 : 0, + pctrl & DOC_ASICMODE_BDETCT_RESET ? 1 : 0, + pctrl & DOC_ASICMODE_MDWREN ? 1 : 0, + pctrl & DOC_ASICMODE_POWERDOWN ? 1 : 0, + mode >> 1, mode & 0x1); + + switch (mode) { + case DOC_ASICMODE_RESET: + pos += seq_printf(s, "reset"); + break; + case DOC_ASICMODE_NORMAL: + pos += seq_printf(s, "normal"); + break; + case DOC_ASICMODE_POWERDOWN: + pos += seq_printf(s, "powerdown"); + break; + } + pos += seq_printf(s, ")\n"); + return pos; +} +DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show); + +static int dbg_device_id_show(struct seq_file *s, void *p) +{ + struct docg3 *docg3 = (struct docg3 *)s->private; + int pos = 0; + int id = doc_register_readb(docg3, DOC_DEVICESELECT); + + pos += seq_printf(s, "DeviceId = %d\n", id); + return pos; +} +DEBUGFS_RO_ATTR(device_id, dbg_device_id_show); + +static int dbg_protection_show(struct seq_file *s, void *p) +{ + struct docg3 *docg3 = (struct docg3 *)s->private; + int pos = 0; + int protect = doc_register_readb(docg3, DOC_PROTECTION); + int dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); + int dps0_low = doc_register_readb(docg3, DOC_DPS0_ADDRLOW); + int dps0_high = doc_register_readb(docg3, DOC_DPS0_ADDRHIGH); + int dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); + int dps1_low = doc_register_readb(docg3, DOC_DPS1_ADDRLOW); + int dps1_high = doc_register_readb(docg3, DOC_DPS1_ADDRHIGH); + + pos += seq_printf(s, "Protection = 0x%02x (", + protect); + if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK) + pos += seq_printf(s, "FOUNDRY_OTP_LOCK,"); + if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK) + pos += seq_printf(s, "CUSTOMER_OTP_LOCK,"); + if (protect & DOC_PROTECT_LOCK_INPUT) + pos += seq_printf(s, "LOCK_INPUT,"); + if (protect & DOC_PROTECT_STICKY_LOCK) + pos += seq_printf(s, "STICKY_LOCK,"); + if (protect & DOC_PROTECT_PROTECTION_ENABLED) + pos += seq_printf(s, "PROTECTION ON,"); + if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK) + pos += seq_printf(s, "IPL_DOWNLOAD_LOCK,"); + if (protect & DOC_PROTECT_PROTECTION_ERROR) + pos += seq_printf(s, "PROTECT_ERR,"); + else + pos += seq_printf(s, "NO_PROTECT_ERR"); + pos += seq_printf(s, ")\n"); + + pos += seq_printf(s, "DPS0 = 0x%02x : " + "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " + "WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", + dps0, dps0_low, dps0_high, + !!(dps0 & DOC_DPS_OTP_PROTECTED), + !!(dps0 & DOC_DPS_READ_PROTECTED), + !!(dps0 & DOC_DPS_WRITE_PROTECTED), + !!(dps0 & DOC_DPS_HW_LOCK_ENABLED), + !!(dps0 & DOC_DPS_KEY_OK)); + pos += seq_printf(s, "DPS1 = 0x%02x : " + "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " + "WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", + dps1, dps1_low, dps1_high, + !!(dps1 & DOC_DPS_OTP_PROTECTED), + !!(dps1 & DOC_DPS_READ_PROTECTED), + !!(dps1 & DOC_DPS_WRITE_PROTECTED), + !!(dps1 & DOC_DPS_HW_LOCK_ENABLED), + !!(dps1 & DOC_DPS_KEY_OK)); + return pos; +} +DEBUGFS_RO_ATTR(protection, dbg_protection_show); + +static int __init doc_dbg_register(struct docg3 *docg3) +{ + struct dentry *root, *entry; + + root = debugfs_create_dir("docg3", NULL); + if (!root) + return -ENOMEM; + + entry = debugfs_create_file("flashcontrol", S_IRUSR, root, docg3, + &flashcontrol_fops); + if (entry) + entry = debugfs_create_file("asic_mode", S_IRUSR, root, + docg3, &asic_mode_fops); + if (entry) + entry = debugfs_create_file("device_id", S_IRUSR, root, + docg3, &device_id_fops); + if (entry) + entry = debugfs_create_file("protection", S_IRUSR, root, + docg3, &protection_fops); + if (entry) { + docg3->debugfs_root = root; + return 0; + } else { + debugfs_remove_recursive(root); + return -ENOMEM; + } +} + +static void __exit doc_dbg_unregister(struct docg3 *docg3) +{ + debugfs_remove_recursive(docg3->debugfs_root); +} + +/** + * doc_set_driver_info - Fill the mtd_info structure and docg3 structure + * @chip_id: The chip ID of the supported chip + * @mtd: The structure to fill + */ +static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) +{ + struct docg3 *docg3 = mtd->priv; + int cfg; + + cfg = doc_register_readb(docg3, DOC_CONFIGURATION); + docg3->if_cfg = (cfg & DOC_CONF_IF_CFG ? 1 : 0); + + switch (chip_id) { + case DOC_CHIPID_G3: + mtd->name = "DiskOnChip G3"; + docg3->max_block = 2047; + break; + } + mtd->type = MTD_NANDFLASH; + /* + * Once write methods are added, the correct flags will be set. + * mtd->flags = MTD_CAP_NANDFLASH; + */ + mtd->flags = MTD_CAP_ROM; + mtd->size = (docg3->max_block + 1) * DOC_LAYOUT_BLOCK_SIZE; + mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES; + mtd->writesize = DOC_LAYOUT_PAGE_SIZE; + mtd->oobsize = DOC_LAYOUT_OOB_SIZE; + mtd->owner = THIS_MODULE; + mtd->erase = NULL; + mtd->point = NULL; + mtd->unpoint = NULL; + mtd->read = doc_read; + mtd->write = NULL; + mtd->read_oob = doc_read_oob; + mtd->write_oob = NULL; + mtd->sync = NULL; + mtd->block_isbad = doc_block_isbad; +} + +/** + * doc_probe - Probe the IO space for a DiskOnChip G3 chip + * @pdev: platform device + * + * Probes for a G3 chip at the specified IO space in the platform data + * ressources. + * + * Returns 0 on success, -ENOMEM, -ENXIO on error + */ +static int __init docg3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct docg3 *docg3; + struct mtd_info *mtd; + struct resource *ress; + int ret, bbt_nbpages; + u16 chip_id, chip_id_inv; + + ret = -ENOMEM; + docg3 = kzalloc(sizeof(struct docg3), GFP_KERNEL); + if (!docg3) + goto nomem1; + mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); + if (!mtd) + goto nomem2; + mtd->priv = docg3; + + ret = -ENXIO; + ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!ress) { + dev_err(dev, "No I/O memory resource defined\n"); + goto noress; + } + docg3->base = ioremap(ress->start, DOC_IOSPACE_SIZE); + + docg3->dev = &pdev->dev; + docg3->device_id = 0; + doc_set_device_id(docg3, docg3->device_id); + doc_set_asic_mode(docg3, DOC_ASICMODE_RESET); + doc_set_asic_mode(docg3, DOC_ASICMODE_NORMAL); + + chip_id = doc_register_readw(docg3, DOC_CHIPID); + chip_id_inv = doc_register_readw(docg3, DOC_CHIPID_INV); + + ret = -ENODEV; + if (chip_id != (u16)(~chip_id_inv)) { + doc_info("No device found at IO addr %p\n", + (void *)ress->start); + goto nochipfound; + } + + switch (chip_id) { + case DOC_CHIPID_G3: + doc_info("Found a G3 DiskOnChip at addr %p\n", + (void *)ress->start); + break; + default: + doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id); + goto nochipfound; + } + + doc_set_driver_info(chip_id, mtd); + platform_set_drvdata(pdev, mtd); + + ret = -ENOMEM; + bbt_nbpages = DIV_ROUND_UP(docg3->max_block + 1, + 8 * DOC_LAYOUT_PAGE_SIZE); + docg3->bbt = kzalloc(bbt_nbpages * DOC_LAYOUT_PAGE_SIZE, GFP_KERNEL); + if (!docg3->bbt) + goto nochipfound; + doc_reload_bbt(docg3); + + ret = mtd_device_parse_register(mtd, part_probes, + NULL, NULL, 0); + if (ret) + goto register_error; + + doc_dbg_register(docg3); + return 0; + +register_error: + kfree(docg3->bbt); +nochipfound: + iounmap(docg3->base); +noress: + kfree(mtd); +nomem2: + kfree(docg3); +nomem1: + return ret; +} + +/** + * docg3_release - Release the driver + * @pdev: the platform device + * + * Returns 0 + */ +static int __exit docg3_release(struct platform_device *pdev) +{ + struct mtd_info *mtd = platform_get_drvdata(pdev); + struct docg3 *docg3 = mtd->priv; + + doc_dbg_unregister(docg3); + mtd_device_unregister(mtd); + iounmap(docg3->base); + kfree(docg3->bbt); + kfree(docg3); + kfree(mtd); + return 0; +} + +static struct platform_driver g3_driver = { + .driver = { + .name = "docg3", + .owner = THIS_MODULE, + }, + .remove = __exit_p(docg3_release), +}; + +static int __init docg3_init(void) +{ + return platform_driver_probe(&g3_driver, docg3_probe); +} +module_init(docg3_init); + + +static void __exit docg3_exit(void) +{ + platform_driver_unregister(&g3_driver); +} +module_exit(docg3_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>"); +MODULE_DESCRIPTION("MTD driver for DiskOnChip G3"); diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h new file mode 100644 index 000000000000..0d407be24594 --- /dev/null +++ b/drivers/mtd/devices/docg3.h @@ -0,0 +1,297 @@ +/* + * Handles the M-Systems DiskOnChip G3 chip + * + * Copyright (C) 2011 Robert Jarzmik + * + * 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 + * + */ + +#ifndef _MTD_DOCG3_H +#define _MTD_DOCG3_H + +/* + * Flash memory areas : + * - 0x0000 .. 0x07ff : IPL + * - 0x0800 .. 0x0fff : Data area + * - 0x1000 .. 0x17ff : Registers + * - 0x1800 .. 0x1fff : Unknown + */ +#define DOC_IOSPACE_IPL 0x0000 +#define DOC_IOSPACE_DATA 0x0800 +#define DOC_IOSPACE_SIZE 0x2000 + +/* + * DOC G3 layout and adressing scheme + * A page address for the block "b", plane "P" and page "p": + * address = [bbbb bPpp pppp] + */ + +#define DOC_ADDR_PAGE_MASK 0x3f +#define DOC_ADDR_BLOCK_SHIFT 6 +#define DOC_LAYOUT_NBPLANES 2 +#define DOC_LAYOUT_PAGES_PER_BLOCK 64 +#define DOC_LAYOUT_PAGE_SIZE 512 +#define DOC_LAYOUT_OOB_SIZE 16 +#define DOC_LAYOUT_WEAR_SIZE 8 +#define DOC_LAYOUT_PAGE_OOB_SIZE \ + (DOC_LAYOUT_PAGE_SIZE + DOC_LAYOUT_OOB_SIZE) +#define DOC_LAYOUT_WEAR_OFFSET (DOC_LAYOUT_PAGE_OOB_SIZE * 2) +#define DOC_LAYOUT_BLOCK_SIZE \ + (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_PAGE_SIZE) +#define DOC_ECC_BCH_SIZE 7 +#define DOC_ECC_BCH_COVERED_BYTES \ + (DOC_LAYOUT_PAGE_SIZE + DOC_LAYOUT_OOB_PAGEINFO_SZ + \ + DOC_LAYOUT_OOB_HAMMING_SZ + DOC_LAYOUT_OOB_BCH_SZ) + +/* + * Blocks distribution + */ +#define DOC_LAYOUT_BLOCK_BBT 0 +#define DOC_LAYOUT_BLOCK_OTP 0 +#define DOC_LAYOUT_BLOCK_FIRST_DATA 6 + +#define DOC_LAYOUT_PAGE_BBT 4 + +/* + * Extra page OOB (16 bytes wide) layout + */ +#define DOC_LAYOUT_OOB_PAGEINFO_OFS 0 +#define DOC_LAYOUT_OOB_HAMMING_OFS 7 +#define DOC_LAYOUT_OOB_BCH_OFS 8 +#define DOC_LAYOUT_OOB_UNUSED_OFS 15 +#define DOC_LAYOUT_OOB_PAGEINFO_SZ 7 +#define DOC_LAYOUT_OOB_HAMMING_SZ 1 +#define DOC_LAYOUT_OOB_BCH_SZ 7 +#define DOC_LAYOUT_OOB_UNUSED_SZ 1 + + +#define DOC_CHIPID_G3 0x200 +#define DOC_ERASE_MARK 0xaa +/* + * Flash registers + */ +#define DOC_CHIPID 0x1000 +#define DOC_TEST 0x1004 +#define DOC_BUSLOCK 0x1006 +#define DOC_ENDIANCONTROL 0x1008 +#define DOC_DEVICESELECT 0x100a +#define DOC_ASICMODE 0x100c +#define DOC_CONFIGURATION 0x100e +#define DOC_INTERRUPTCONTROL 0x1010 +#define DOC_READADDRESS 0x101a +#define DOC_DATAEND 0x101e +#define DOC_INTERRUPTSTATUS 0x1020 + +#define DOC_FLASHSEQUENCE 0x1032 +#define DOC_FLASHCOMMAND 0x1034 +#define DOC_FLASHADDRESS 0x1036 +#define DOC_FLASHCONTROL 0x1038 +#define DOC_NOP 0x103e + +#define DOC_ECCCONF0 0x1040 +#define DOC_ECCCONF1 0x1042 +#define DOC_ECCPRESET 0x1044 +#define DOC_HAMMINGPARITY 0x1046 +#define DOC_BCH_SYNDROM(idx) (0x1048 + (idx << 1)) + +#define DOC_PROTECTION 0x1056 +#define DOC_DPS0_ADDRLOW 0x1060 +#define DOC_DPS0_ADDRHIGH 0x1062 +#define DOC_DPS1_ADDRLOW 0x1064 +#define DOC_DPS1_ADDRHIGH 0x1066 +#define DOC_DPS0_STATUS 0x106c +#define DOC_DPS1_STATUS 0x106e + +#define DOC_ASICMODECONFIRM 0x1072 +#define DOC_CHIPID_INV 0x1074 + +/* + * Flash sequences + * A sequence is preset before one or more commands are input to the chip. + */ +#define DOC_SEQ_RESET 0x00 +#define DOC_SEQ_PAGE_SIZE_532 0x03 +#define DOC_SEQ_SET_MODE 0x09 +#define DOC_SEQ_READ 0x12 +#define DOC_SEQ_SET_PLANE1 0x0e +#define DOC_SEQ_SET_PLANE2 0x10 +#define DOC_SEQ_PAGE_SETUP 0x1d + +/* + * Flash commands + */ +#define DOC_CMD_READ_PLANE1 0x00 +#define DOC_CMD_SET_ADDR_READ 0x05 +#define DOC_CMD_READ_ALL_PLANES 0x30 +#define DOC_CMD_READ_PLANE2 0x50 +#define DOC_CMD_READ_FLASH 0xe0 +#define DOC_CMD_PAGE_SIZE_532 0x3c + +#define DOC_CMD_PROG_BLOCK_ADDR 0x60 +#define DOC_CMD_PROG_CYCLE1 0x80 +#define DOC_CMD_PROG_CYCLE2 0x10 +#define DOC_CMD_ERASECYCLE2 0xd0 + +#define DOC_CMD_RELIABLE_MODE 0x22 +#define DOC_CMD_FAST_MODE 0xa2 + +#define DOC_CMD_RESET 0xff + +/* + * Flash register : DOC_FLASHCONTROL + */ +#define DOC_CTRL_VIOLATION 0x20 +#define DOC_CTRL_CE 0x10 +#define DOC_CTRL_UNKNOWN_BITS 0x08 +#define DOC_CTRL_PROTECTION_ERROR 0x04 +#define DOC_CTRL_SEQUENCE_ERROR 0x02 +#define DOC_CTRL_FLASHREADY 0x01 + +/* + * Flash register : DOC_ASICMODE + */ +#define DOC_ASICMODE_RESET 0x00 +#define DOC_ASICMODE_NORMAL 0x01 +#define DOC_ASICMODE_POWERDOWN 0x02 +#define DOC_ASICMODE_MDWREN 0x04 +#define DOC_ASICMODE_BDETCT_RESET 0x08 +#define DOC_ASICMODE_RSTIN_RESET 0x10 +#define DOC_ASICMODE_RAM_WE 0x20 + +/* + * Flash register : DOC_ECCCONF0 + */ +#define DOC_ECCCONF0_READ_MODE 0x8000 +#define DOC_ECCCONF0_AUTO_ECC_ENABLE 0x4000 +#define DOC_ECCCONF0_HAMMING_ENABLE 0x1000 +#define DOC_ECCCONF0_BCH_ENABLE 0x0800 +#define DOC_ECCCONF0_DATA_BYTES_MASK 0x07ff + +/* + * Flash register : DOC_ECCCONF1 + */ +#define DOC_ECCCONF1_BCH_SYNDROM_ERR 0x80 +#define DOC_ECCCONF1_UNKOWN1 0x40 +#define DOC_ECCCONF1_UNKOWN2 0x20 +#define DOC_ECCCONF1_UNKOWN3 0x10 +#define DOC_ECCCONF1_HAMMING_BITS_MASK 0x0f + +/* + * Flash register : DOC_PROTECTION + */ +#define DOC_PROTECT_FOUNDRY_OTP_LOCK 0x01 +#define DOC_PROTECT_CUSTOMER_OTP_LOCK 0x02 +#define DOC_PROTECT_LOCK_INPUT 0x04 +#define DOC_PROTECT_STICKY_LOCK 0x08 +#define DOC_PROTECT_PROTECTION_ENABLED 0x10 +#define DOC_PROTECT_IPL_DOWNLOAD_LOCK 0x20 +#define DOC_PROTECT_PROTECTION_ERROR 0x80 + +/* + * Flash register : DOC_DPS0_STATUS and DOC_DPS1_STATUS + */ +#define DOC_DPS_OTP_PROTECTED 0x01 +#define DOC_DPS_READ_PROTECTED 0x02 +#define DOC_DPS_WRITE_PROTECTED 0x04 +#define DOC_DPS_HW_LOCK_ENABLED 0x08 +#define DOC_DPS_KEY_OK 0x80 + +/* + * Flash register : DOC_CONFIGURATION + */ +#define DOC_CONF_IF_CFG 0x80 +#define DOC_CONF_MAX_ID_MASK 0x30 +#define DOC_CONF_VCCQ_3V 0x01 + +/* + * Flash register : DOC_READADDRESS + */ +#define DOC_READADDR_INC 0x8000 +#define DOC_READADDR_ONE_BYTE 0x4000 +#define DOC_READADDR_ADDR_MASK 0x1fff + +/** + * struct docg3 - DiskOnChip driver private data + * @dev: the device currently under control + * @base: mapped IO space + * @device_id: number of the cascaded DoCG3 device (0, 1, 2 or 3) + * @if_cfg: if true, reads are on 16bits, else reads are on 8bits + * @bbt: bad block table cache + * @debugfs_root: debugfs root node + */ +struct docg3 { + struct device *dev; + void __iomem *base; + unsigned int device_id:4; + unsigned int if_cfg:1; + int max_block; + u8 *bbt; + struct dentry *debugfs_root; +}; + +#define doc_err(fmt, arg...) dev_err(docg3->dev, (fmt), ## arg) +#define doc_info(fmt, arg...) dev_info(docg3->dev, (fmt), ## arg) +#define doc_dbg(fmt, arg...) dev_dbg(docg3->dev, (fmt), ## arg) +#define doc_vdbg(fmt, arg...) dev_vdbg(docg3->dev, (fmt), ## arg) + +#define DEBUGFS_RO_ATTR(name, show_fct) \ + static int name##_open(struct inode *inode, struct file *file) \ + { return single_open(file, show_fct, inode->i_private); } \ + static const struct file_operations name##_fops = { \ + .owner = THIS_MODULE, \ + .open = name##_open, \ + .llseek = seq_lseek, \ + .read = seq_read, \ + .release = single_release \ + }; +#endif + +/* + * Trace events part + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM docg3 + +#if !defined(_MTD_DOCG3_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define _MTD_DOCG3_TRACE + +#include <linux/tracepoint.h> + +TRACE_EVENT(docg3_io, + TP_PROTO(int op, int width, u16 reg, int val), + TP_ARGS(op, width, reg, val), + TP_STRUCT__entry( + __field(int, op) + __field(unsigned char, width) + __field(u16, reg) + __field(int, val)), + TP_fast_assign( + __entry->op = op; + __entry->width = width; + __entry->reg = reg; + __entry->val = val;), + TP_printk("docg3: %s%02d reg=%04x, val=%04x", + __entry->op ? "write" : "read", __entry->width, + __entry->reg, __entry->val) + ); +#endif + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE docg3 +#include <trace/define_trace.h> diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index d374603493a7..45116bb30297 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -50,11 +50,6 @@ #include <linux/mtd/nand.h> #include <linux/mtd/doc2000.h> -/* Where to look for the devices? */ -#ifndef CONFIG_MTD_DOCPROBE_ADDRESS -#define CONFIG_MTD_DOCPROBE_ADDRESS 0 -#endif - static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS; module_param(doc_config_location, ulong, 0); diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 772a0ff89e0f..3a11ea628e58 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -34,9 +34,6 @@ /* debugging */ //#define LART_DEBUG -/* partition support */ -#define HAVE_PARTITIONS - #include <linux/kernel.h> #include <linux/module.h> #include <linux/types.h> @@ -44,9 +41,7 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/mtd/mtd.h> -#ifdef HAVE_PARTITIONS #include <linux/mtd/partitions.h> -#endif #ifndef CONFIG_SA1100_LART #error This is for LART architecture only @@ -598,7 +593,6 @@ static struct mtd_erase_region_info erase_regions[] = { } }; -#ifdef HAVE_PARTITIONS static struct mtd_partition lart_partitions[] = { /* blob */ { @@ -619,7 +613,7 @@ static struct mtd_partition lart_partitions[] = { .size = INITRD_LEN, /* MTDPART_SIZ_FULL */ } }; -#endif +#define NUM_PARTITIONS ARRAY_SIZE(lart_partitions) static int __init lart_flash_init (void) { @@ -668,7 +662,6 @@ static int __init lart_flash_init (void) result,mtd.eraseregions[result].erasesize,mtd.eraseregions[result].erasesize / 1024, result,mtd.eraseregions[result].numblocks); -#ifdef HAVE_PARTITIONS printk ("\npartitions = %d\n", ARRAY_SIZE(lart_partitions)); for (result = 0; result < ARRAY_SIZE(lart_partitions); result++) @@ -681,25 +674,16 @@ static int __init lart_flash_init (void) result,lart_partitions[result].offset, result,lart_partitions[result].size,lart_partitions[result].size / 1024); #endif -#endif -#ifndef HAVE_PARTITIONS - result = mtd_device_register(&mtd, NULL, 0); -#else result = mtd_device_register(&mtd, lart_partitions, ARRAY_SIZE(lart_partitions)); -#endif return (result); } static void __exit lart_flash_exit (void) { -#ifndef HAVE_PARTITIONS - mtd_device_unregister(&mtd); -#else mtd_device_unregister(&mtd); -#endif } module_init (lart_flash_init); diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 35180e475c4c..884904d3f9d2 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -30,6 +30,7 @@ #include <linux/mtd/cfi.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/of_platform.h> #include <linux/spi/spi.h> #include <linux/spi/flash.h> @@ -88,7 +89,6 @@ struct m25p { struct spi_device *spi; struct mutex lock; struct mtd_info mtd; - unsigned partitioned:1; u16 page_size; u16 addr_width; u8 erase_opcode; @@ -209,9 +209,8 @@ static int wait_till_ready(struct m25p *flash) */ static int erase_chip(struct m25p *flash) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %lldKiB\n", - dev_name(&flash->spi->dev), __func__, - (long long)(flash->mtd.size >> 10)); + pr_debug("%s: %s %lldKiB\n", dev_name(&flash->spi->dev), __func__, + (long long)(flash->mtd.size >> 10)); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -250,9 +249,8 @@ static int m25p_cmdsz(struct m25p *flash) */ static int erase_sector(struct m25p *flash, u32 offset) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n", - dev_name(&flash->spi->dev), __func__, - flash->mtd.erasesize / 1024, offset); + pr_debug("%s: %s %dKiB at 0x%08x\n", dev_name(&flash->spi->dev), + __func__, flash->mtd.erasesize / 1024, offset); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -286,9 +284,9 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) u32 addr,len; uint32_t rem; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%llx, len %lld\n", - dev_name(&flash->spi->dev), __func__, "at", - (long long)instr->addr, (long long)instr->len); + pr_debug("%s: %s at 0x%llx, len %lld\n", dev_name(&flash->spi->dev), + __func__, (long long)instr->addr, + (long long)instr->len); /* sanity checks */ if (instr->addr + instr->len > flash->mtd.size) @@ -348,9 +346,8 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_transfer t[2]; struct spi_message m; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", - dev_name(&flash->spi->dev), __func__, "from", - (u32)from, len); + pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), + __func__, (u32)from, len); /* sanity checks */ if (!len) @@ -417,9 +414,8 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, struct spi_transfer t[2]; struct spi_message m; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", - dev_name(&flash->spi->dev), __func__, "to", - (u32)to, len); + pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), + __func__, (u32)to, len); *retlen = 0; @@ -510,9 +506,8 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, size_t actual; int cmd_sz, ret; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", - dev_name(&flash->spi->dev), __func__, "to", - (u32)to, len); + pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), + __func__, (u32)to, len); *retlen = 0; @@ -661,6 +656,7 @@ static const struct spi_device_id m25p_ids[] = { { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, + { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, @@ -671,6 +667,7 @@ static const struct spi_device_id m25p_ids[] = { /* EON -- en25xxx */ { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, + { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, /* Intel/Numonyx -- xxxs33b */ @@ -788,8 +785,8 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi) */ tmp = spi_write_then_read(spi, &code, 1, id, 5); if (tmp < 0) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", - dev_name(&spi->dev), tmp); + pr_debug("%s: error %d reading JEDEC ID\n", + dev_name(&spi->dev), tmp); return ERR_PTR(tmp); } jedec = id[0]; @@ -825,8 +822,12 @@ static int __devinit m25p_probe(struct spi_device *spi) struct m25p *flash; struct flash_info *info; unsigned i; - struct mtd_partition *parts = NULL; - int nr_parts = 0; + struct mtd_part_parser_data ppdata; + +#ifdef CONFIG_MTD_OF_PARTS + if (!of_device_is_available(spi->dev.of_node)) + return -ENODEV; +#endif /* Platform data helps sort out which chip type we have, as * well as how this board partitions it. If we don't have @@ -928,6 +929,7 @@ static int __devinit m25p_probe(struct spi_device *spi) if (info->flags & M25P_NO_ERASE) flash->mtd.flags |= MTD_NO_ERASE; + ppdata.of_node = spi->dev.of_node; flash->mtd.dev.parent = &spi->dev; flash->page_size = info->page_size; @@ -945,8 +947,7 @@ static int __devinit m25p_probe(struct spi_device *spi) dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name, (long long)flash->mtd.size >> 10); - DEBUG(MTD_DEBUG_LEVEL2, - "mtd .name = %s, .size = 0x%llx (%lldMiB) " + pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", flash->mtd.name, (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), @@ -955,8 +956,7 @@ static int __devinit m25p_probe(struct spi_device *spi) if (flash->mtd.numeraseregions) for (i = 0; i < flash->mtd.numeraseregions; i++) - DEBUG(MTD_DEBUG_LEVEL2, - "mtd.eraseregions[%d] = { .offset = 0x%llx, " + pr_debug("mtd.eraseregions[%d] = { .offset = 0x%llx, " ".erasesize = 0x%.8x (%uKiB), " ".numblocks = %d }\n", i, (long long)flash->mtd.eraseregions[i].offset, @@ -968,41 +968,9 @@ static int __devinit m25p_probe(struct spi_device *spi) /* partitions should match sector boundaries; and it may be good to * use readonly partitions for writeprotected sectors (BP2..BP0). */ - if (mtd_has_cmdlinepart()) { - static const char *part_probes[] - = { "cmdlinepart", NULL, }; - - nr_parts = parse_mtd_partitions(&flash->mtd, - part_probes, &parts, 0); - } - - if (nr_parts <= 0 && data && data->parts) { - parts = data->parts; - nr_parts = data->nr_parts; - } - -#ifdef CONFIG_MTD_OF_PARTS - if (nr_parts <= 0 && spi->dev.of_node) { - nr_parts = of_mtd_parse_partitions(&spi->dev, - spi->dev.of_node, &parts); - } -#endif - - if (nr_parts > 0) { - for (i = 0; i < nr_parts; i++) { - DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " - "{.name = %s, .offset = 0x%llx, " - ".size = 0x%llx (%lldKiB) }\n", - i, parts[i].name, - (long long)parts[i].offset, - (long long)parts[i].size, - (long long)(parts[i].size >> 10)); - } - flash->partitioned = 1; - } - - return mtd_device_register(&flash->mtd, parts, nr_parts) == 1 ? - -ENODEV : 0; + return mtd_device_parse_register(&flash->mtd, NULL, &ppdata, + data ? data->parts : NULL, + data ? data->nr_parts : 0); } diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 13749d458a31..d75c7af18a63 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -17,6 +17,8 @@ #include <linux/mutex.h> #include <linux/err.h> #include <linux/math64.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/spi/spi.h> #include <linux/spi/flash.h> @@ -24,7 +26,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> - /* * DataFlash is a kind of SPI flash. Most AT45 chips have two buffers in * each chip, which may be used for double buffered I/O; but this driver @@ -98,6 +99,16 @@ struct dataflash { struct mtd_info mtd; }; +#ifdef CONFIG_OF +static const struct of_device_id dataflash_dt_ids[] = { + { .compatible = "atmel,at45", }, + { .compatible = "atmel,dataflash", }, + { /* sentinel */ } +}; +#else +#define dataflash_dt_ids NULL +#endif + /* ......................................................................... */ /* @@ -122,7 +133,7 @@ static int dataflash_waitready(struct spi_device *spi) for (;;) { status = dataflash_status(spi); if (status < 0) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: status %d?\n", + pr_debug("%s: status %d?\n", dev_name(&spi->dev), status); status = 0; } @@ -149,7 +160,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) uint8_t *command; uint32_t rem; - DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%llx len 0x%llx\n", + pr_debug("%s: erase addr=0x%llx len 0x%llx\n", dev_name(&spi->dev), (long long)instr->addr, (long long)instr->len); @@ -187,7 +198,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) command[2] = (uint8_t)(pageaddr >> 8); command[3] = 0; - DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n", + pr_debug("ERASE %s: (%x) %x %x %x [%i]\n", do_block ? "block" : "page", command[0], command[1], command[2], command[3], pageaddr); @@ -238,8 +249,8 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, uint8_t *command; int status; - DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n", - dev_name(&priv->spi->dev), (unsigned)from, (unsigned)(from + len)); + pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev), + (unsigned)from, (unsigned)(from + len)); *retlen = 0; @@ -255,7 +266,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, command = priv->command; - DEBUG(MTD_DEBUG_LEVEL3, "READ: (%x) %x %x %x\n", + pr_debug("READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); spi_message_init(&msg); @@ -287,7 +298,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, *retlen = msg.actual_length - 8; status = 0; } else - DEBUG(MTD_DEBUG_LEVEL1, "%s: read %x..%x --> %d\n", + pr_debug("%s: read %x..%x --> %d\n", dev_name(&priv->spi->dev), (unsigned)from, (unsigned)(from + len), status); @@ -314,7 +325,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, int status = -EINVAL; uint8_t *command; - DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n", + pr_debug("%s: write 0x%x..0x%x\n", dev_name(&spi->dev), (unsigned)to, (unsigned)(to + len)); *retlen = 0; @@ -340,7 +351,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, mutex_lock(&priv->lock); while (remaining > 0) { - DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n", + pr_debug("write @ %i:%i len=%i\n", pageaddr, offset, writelen); /* REVISIT: @@ -368,12 +379,12 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, command[2] = (addr & 0x0000FF00) >> 8; command[3] = 0; - DEBUG(MTD_DEBUG_LEVEL3, "TRANSFER: (%x) %x %x %x\n", + pr_debug("TRANSFER: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); status = spi_sync(spi, &msg); if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: xfer %u -> %d \n", + pr_debug("%s: xfer %u -> %d\n", dev_name(&spi->dev), addr, status); (void) dataflash_waitready(priv->spi); @@ -386,7 +397,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, command[2] = (addr & 0x0000FF00) >> 8; command[3] = (addr & 0x000000FF); - DEBUG(MTD_DEBUG_LEVEL3, "PROGRAM: (%x) %x %x %x\n", + pr_debug("PROGRAM: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); x[1].tx_buf = writebuf; @@ -395,7 +406,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, status = spi_sync(spi, &msg); spi_transfer_del(x + 1); if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: pgm %u/%u -> %d \n", + pr_debug("%s: pgm %u/%u -> %d\n", dev_name(&spi->dev), addr, writelen, status); (void) dataflash_waitready(priv->spi); @@ -410,12 +421,12 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, command[2] = (addr & 0x0000FF00) >> 8; command[3] = 0; - DEBUG(MTD_DEBUG_LEVEL3, "COMPARE: (%x) %x %x %x\n", + pr_debug("COMPARE: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); status = spi_sync(spi, &msg); if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: compare %u -> %d \n", + pr_debug("%s: compare %u -> %d\n", dev_name(&spi->dev), addr, status); status = dataflash_waitready(priv->spi); @@ -634,11 +645,10 @@ add_dataflash_otp(struct spi_device *spi, char *name, { struct dataflash *priv; struct mtd_info *device; + struct mtd_part_parser_data ppdata; struct flash_platform_data *pdata = spi->dev.platform_data; char *otp_tag = ""; int err = 0; - struct mtd_partition *parts; - int nr_parts = 0; priv = kzalloc(sizeof *priv, GFP_KERNEL); if (!priv) @@ -677,28 +687,11 @@ add_dataflash_otp(struct spi_device *spi, char *name, pagesize, otp_tag); dev_set_drvdata(&spi->dev, priv); - if (mtd_has_cmdlinepart()) { - static const char *part_probes[] = { "cmdlinepart", NULL, }; - - nr_parts = parse_mtd_partitions(device, part_probes, &parts, - 0); - } + ppdata.of_node = spi->dev.of_node; + err = mtd_device_parse_register(device, NULL, &ppdata, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); - if (nr_parts <= 0 && pdata && pdata->parts) { - parts = pdata->parts; - nr_parts = pdata->nr_parts; - } - - if (nr_parts > 0) { - priv->partitioned = 1; - err = mtd_device_register(device, parts, nr_parts); - goto out; - } - - if (mtd_device_register(device, NULL, 0) == 1) - err = -ENODEV; - -out: if (!err) return 0; @@ -787,7 +780,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) */ tmp = spi_write_then_read(spi, &code, 1, id, 3); if (tmp < 0) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", + pr_debug("%s: error %d reading JEDEC ID\n", dev_name(&spi->dev), tmp); return ERR_PTR(tmp); } @@ -804,7 +797,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) tmp < ARRAY_SIZE(dataflash_data); tmp++, info++) { if (info->jedec_id == jedec) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: OTP, sector protect%s\n", + pr_debug("%s: OTP, sector protect%s\n", dev_name(&spi->dev), (info->flags & SUP_POW2PS) ? ", binary pagesize" : "" @@ -812,8 +805,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) if (info->flags & SUP_POW2PS) { status = dataflash_status(spi); if (status < 0) { - DEBUG(MTD_DEBUG_LEVEL1, - "%s: status error %d\n", + pr_debug("%s: status error %d\n", dev_name(&spi->dev), status); return ERR_PTR(status); } @@ -878,7 +870,7 @@ static int __devinit dataflash_probe(struct spi_device *spi) */ status = dataflash_status(spi); if (status <= 0 || status == 0xff) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n", + pr_debug("%s: status error %d\n", dev_name(&spi->dev), status); if (status == 0 || status == 0xff) status = -ENODEV; @@ -914,14 +906,14 @@ static int __devinit dataflash_probe(struct spi_device *spi) break; /* obsolete AT45DB1282 not (yet?) supported */ default: - DEBUG(MTD_DEBUG_LEVEL1, "%s: unsupported device (%x)\n", - dev_name(&spi->dev), status & 0x3c); + pr_debug("%s: unsupported device (%x)\n", dev_name(&spi->dev), + status & 0x3c); status = -ENODEV; } if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: add_dataflash --> %d\n", - dev_name(&spi->dev), status); + pr_debug("%s: add_dataflash --> %d\n", dev_name(&spi->dev), + status); return status; } @@ -931,7 +923,7 @@ static int __devexit dataflash_remove(struct spi_device *spi) struct dataflash *flash = dev_get_drvdata(&spi->dev); int status; - DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", dev_name(&spi->dev)); + pr_debug("%s: remove\n", dev_name(&spi->dev)); status = mtd_device_unregister(&flash->mtd); if (status == 0) { @@ -946,6 +938,7 @@ static struct spi_driver dataflash_driver = { .name = "mtd_dataflash", .bus = &spi_bus_type, .owner = THIS_MODULE, + .of_match_table = dataflash_dt_ids, }, .probe = dataflash_probe, diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 83e80c65d6e7..d38ef3bffe8d 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -52,8 +52,6 @@ struct sst25l_flash { struct spi_device *spi; struct mutex lock; struct mtd_info mtd; - - int partitioned; }; struct flash_info { @@ -381,8 +379,6 @@ static int __devinit sst25l_probe(struct spi_device *spi) struct sst25l_flash *flash; struct flash_platform_data *data; int ret, i; - struct mtd_partition *parts = NULL; - int nr_parts = 0; flash_info = sst25l_match_device(spi); if (!flash_info) @@ -414,8 +410,7 @@ static int __devinit sst25l_probe(struct spi_device *spi) dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name, (long long)flash->mtd.size >> 10); - DEBUG(MTD_DEBUG_LEVEL2, - "mtd .name = %s, .size = 0x%llx (%lldMiB) " + pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", flash->mtd.name, (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), @@ -423,37 +418,10 @@ static int __devinit sst25l_probe(struct spi_device *spi) flash->mtd.numeraseregions); - if (mtd_has_cmdlinepart()) { - static const char *part_probes[] = {"cmdlinepart", NULL}; - - nr_parts = parse_mtd_partitions(&flash->mtd, - part_probes, - &parts, 0); - } - - if (nr_parts <= 0 && data && data->parts) { - parts = data->parts; - nr_parts = data->nr_parts; - } - - if (nr_parts > 0) { - for (i = 0; i < nr_parts; i++) { - DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " - "{.name = %s, .offset = 0x%llx, " - ".size = 0x%llx (%lldKiB) }\n", - i, parts[i].name, - (long long)parts[i].offset, - (long long)parts[i].size, - (long long)(parts[i].size >> 10)); - } - - flash->partitioned = 1; - return mtd_device_register(&flash->mtd, parts, - nr_parts); - } - - ret = mtd_device_register(&flash->mtd, NULL, 0); - if (ret == 1) { + ret = mtd_device_parse_register(&flash->mtd, NULL, 0, + data ? data->parts : NULL, + data ? data->nr_parts : 0); + if (ret) { kfree(flash); dev_set_drvdata(&spi->dev, NULL); return -ENODEV; diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 037b399df3f1..c7382bb686c6 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -339,7 +339,7 @@ static int erase_xfer(partition_t *part, struct erase_info *erase; xfer = &part->XferInfo[xfernum]; - DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset); + pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset); xfer->state = XFER_ERASING; /* Is there a free erase slot? Always in MTD. */ @@ -415,7 +415,7 @@ static int prepare_xfer(partition_t *part, int i) xfer = &part->XferInfo[i]; xfer->state = XFER_FAILED; - DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); + pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); /* Write the transfer unit header */ header = part->header; @@ -476,7 +476,7 @@ static int copy_erase_unit(partition_t *part, uint16_t srcunit, eun = &part->EUNInfo[srcunit]; xfer = &part->XferInfo[xferunit]; - DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n", + pr_debug("ftl_cs: copying block 0x%x to 0x%x\n", eun->Offset, xfer->Offset); @@ -598,7 +598,7 @@ static int copy_erase_unit(partition_t *part, uint16_t srcunit, unit with the fewest erases, and usually pick the data unit with the most deleted blocks. But with a small probability, pick the oldest data unit instead. This means that we generally postpone - the next reclaimation as long as possible, but shuffle static + the next reclamation as long as possible, but shuffle static stuff around a bit for wear leveling. ======================================================================*/ @@ -609,8 +609,8 @@ static int reclaim_block(partition_t *part) uint32_t best; int queued, ret; - DEBUG(0, "ftl_cs: reclaiming space...\n"); - DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits); + pr_debug("ftl_cs: reclaiming space...\n"); + pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits); /* Pick the least erased transfer unit */ best = 0xffffffff; xfer = 0xffff; do { @@ -618,22 +618,22 @@ static int reclaim_block(partition_t *part) for (i = 0; i < part->header.NumTransferUnits; i++) { int n=0; if (part->XferInfo[i].state == XFER_UNKNOWN) { - DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i); + pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i); n=1; erase_xfer(part, i); } if (part->XferInfo[i].state == XFER_ERASING) { - DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i); + pr_debug("XferInfo[%d].state == XFER_ERASING\n",i); n=1; queued = 1; } else if (part->XferInfo[i].state == XFER_ERASED) { - DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i); + pr_debug("XferInfo[%d].state == XFER_ERASED\n",i); n=1; prepare_xfer(part, i); } if (part->XferInfo[i].state == XFER_PREPARED) { - DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i); + pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i); n=1; if (part->XferInfo[i].EraseCount <= best) { best = part->XferInfo[i].EraseCount; @@ -641,12 +641,12 @@ static int reclaim_block(partition_t *part) } } if (!n) - DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state); + pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state); } if (xfer == 0xffff) { if (queued) { - DEBUG(1, "ftl_cs: waiting for transfer " + pr_debug("ftl_cs: waiting for transfer " "unit to be prepared...\n"); if (part->mbd.mtd->sync) part->mbd.mtd->sync(part->mbd.mtd); @@ -656,7 +656,7 @@ static int reclaim_block(partition_t *part) printk(KERN_NOTICE "ftl_cs: reclaim failed: no " "suitable transfer units!\n"); else - DEBUG(1, "ftl_cs: reclaim failed: no " + pr_debug("ftl_cs: reclaim failed: no " "suitable transfer units!\n"); return -EIO; @@ -666,7 +666,7 @@ static int reclaim_block(partition_t *part) eun = 0; if ((jiffies % shuffle_freq) == 0) { - DEBUG(1, "ftl_cs: recycling freshest block...\n"); + pr_debug("ftl_cs: recycling freshest block...\n"); best = 0xffffffff; for (i = 0; i < part->DataUnits; i++) if (part->EUNInfo[i].EraseCount <= best) { @@ -686,7 +686,7 @@ static int reclaim_block(partition_t *part) printk(KERN_NOTICE "ftl_cs: reclaim failed: " "no free blocks!\n"); else - DEBUG(1,"ftl_cs: reclaim failed: " + pr_debug("ftl_cs: reclaim failed: " "no free blocks!\n"); return -EIO; @@ -771,7 +771,7 @@ static uint32_t find_free(partition_t *part) printk(KERN_NOTICE "ftl_cs: bad free list!\n"); return 0; } - DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun); + pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun); return blk; } /* find_free */ @@ -791,7 +791,7 @@ static int ftl_read(partition_t *part, caddr_t buffer, int ret; size_t offset, retlen; - DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", + pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", part, sector, nblocks); if (!(part->state & FTL_FORMATTED)) { printk(KERN_NOTICE "ftl_cs: bad partition\n"); @@ -840,7 +840,7 @@ static int set_bam_entry(partition_t *part, uint32_t log_addr, int ret; size_t retlen, offset; - DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n", + pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n", part, log_addr, virt_addr); bsize = 1 << part->header.EraseUnitSize; eun = log_addr / bsize; @@ -905,7 +905,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, int ret; size_t retlen, offset; - DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n", + pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n", part, sector, nblocks); if (!(part->state & FTL_FORMATTED)) { printk(KERN_NOTICE "ftl_cs: bad partition\n"); @@ -1011,7 +1011,7 @@ static int ftl_discardsect(struct mtd_blktrans_dev *dev, partition_t *part = (void *)dev; uint32_t bsize = 1 << part->header.EraseUnitSize; - DEBUG(1, "FTL erase sector %ld for %d sectors\n", + pr_debug("FTL erase sector %ld for %d sectors\n", sector, nr_sects); while (nr_sects) { diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index d7592e67d048..dd034efd1875 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -63,14 +63,12 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; } - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name); + pr_debug("INFTL: add_mtd for %s\n", mtd->name); inftl = kzalloc(sizeof(*inftl), GFP_KERNEL); - if (!inftl) { - printk(KERN_WARNING "INFTL: Out of memory for data structures\n"); + if (!inftl) return; - } inftl->mbd.mtd = mtd; inftl->mbd.devnum = -1; @@ -133,7 +131,7 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev) { struct INFTLrecord *inftl = (void *)dev; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum); + pr_debug("INFTL: remove_dev (i=%d)\n", dev->devnum); del_mtd_blktrans_dev(dev); @@ -154,7 +152,7 @@ int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & (mtd->writesize - 1); ops.ooblen = len; ops.oobbuf = buf; @@ -174,7 +172,7 @@ int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & (mtd->writesize - 1); ops.ooblen = len; ops.oobbuf = buf; @@ -194,7 +192,7 @@ static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs; ops.ooblen = mtd->oobsize; ops.oobbuf = oob; @@ -215,16 +213,16 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate) u16 pot = inftl->LastFreeEUN; int silly = inftl->nb_blocks; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=%p," - "desperate=%d)\n", inftl, desperate); + pr_debug("INFTL: INFTL_findfreeblock(inftl=%p,desperate=%d)\n", + inftl, desperate); /* * Normally, we force a fold to happen before we run out of free * blocks completely. */ if (!desperate && inftl->numfreeEUNs < 2) { - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free " - "EUNs (%d)\n", inftl->numfreeEUNs); + pr_debug("INFTL: there are too few free EUNs (%d)\n", + inftl->numfreeEUNs); return BLOCK_NIL; } @@ -259,8 +257,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned struct inftl_oob oob; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d," - "pending=%d)\n", inftl, thisVUC, pendingblock); + pr_debug("INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,pending=%d)\n", + inftl, thisVUC, pendingblock); memset(BlockMap, 0xff, sizeof(BlockMap)); memset(BlockDeleted, 0, sizeof(BlockDeleted)); @@ -323,8 +321,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned * Chain, and the Erase Unit into which we are supposed to be copying. * Go for it. */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n", - thisVUC, targetEUN); + pr_debug("INFTL: folding chain %d into unit %d\n", thisVUC, targetEUN); for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) { unsigned char movebuf[SECTORSIZE]; @@ -349,14 +346,13 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, &retlen, movebuf); - if (ret < 0 && ret != -EUCLEAN) { + if (ret < 0 && !mtd_is_bitflip(ret)) { ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, &retlen, movebuf); if (ret != -EIO) - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " - "away on retry?\n"); + pr_debug("INFTL: error went away on retry?\n"); } memset(&oob, 0xff, sizeof(struct inftl_oob)); oob.b.Status = oob.b.Status1 = SECTOR_USED; @@ -372,8 +368,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned * is important, by doing oldest first if we crash/reboot then it * it is relatively simple to clean up the mess). */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n", - thisVUC); + pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC); for (;;) { /* Find oldest unit in chain. */ @@ -421,7 +416,7 @@ static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) u16 ChainLength = 0, thislen; u16 chain, EUN; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=%p," + pr_debug("INFTL: INFTL_makefreeblock(inftl=%p," "pending=%d)\n", inftl, pendingblock); for (chain = 0; chain < inftl->nb_blocks; chain++) { @@ -484,8 +479,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) size_t retlen; int silly, silly2 = 3; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=%p," - "block=%d)\n", inftl, block); + pr_debug("INFTL: INFTL_findwriteunit(inftl=%p,block=%d)\n", + inftl, block); do { /* @@ -501,8 +496,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) blockofs, 8, &retlen, (char *)&bci); status = bci.Status | bci.Status1; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " - "EUN %d is %x\n", block , writeEUN, status); + pr_debug("INFTL: status of block %d in EUN %d is %x\n", + block , writeEUN, status); switch(status) { case SECTOR_FREE: @@ -555,9 +550,9 @@ hitused: * Hopefully we free something, lets try again. * This time we are desperate... */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 " - "to find free EUN to accommodate write to " - "VUC %d\n", thisVUC); + pr_debug("INFTL: using desperate==1 to find free EUN " + "to accommodate write to VUC %d\n", + thisVUC); writeEUN = INFTL_findfreeblock(inftl, 1); if (writeEUN == BLOCK_NIL) { /* @@ -647,7 +642,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) struct inftl_bci bci; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=%p," + pr_debug("INFTL: INFTL_trydeletechain(inftl=%p," "thisVUC=%d)\n", inftl, thisVUC); memset(BlockUsed, 0, sizeof(BlockUsed)); @@ -711,7 +706,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) * For each block in the chain free it and make it available * for future use. Erase from the oldest unit first. */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC); + pr_debug("INFTL: deleting empty VUC %d\n", thisVUC); for (;;) { u16 *prevEUN = &inftl->VUtable[thisVUC]; @@ -719,7 +714,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) /* If the chain is all gone already, we're done */ if (thisEUN == BLOCK_NIL) { - DEBUG(MTD_DEBUG_LEVEL2, "INFTL: Empty VUC %d for deletion was already absent\n", thisEUN); + pr_debug("INFTL: Empty VUC %d for deletion was already absent\n", thisEUN); return; } @@ -731,7 +726,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) thisEUN = *prevEUN; } - DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n", + pr_debug("Deleting EUN %d from VUC %d\n", thisEUN, thisVUC); if (INFTL_formatblock(inftl, thisEUN) < 0) { @@ -767,7 +762,7 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block) size_t retlen; struct inftl_bci bci; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=%p," + pr_debug("INFTL: INFTL_deleteblock(inftl=%p," "block=%d)\n", inftl, block); while (thisEUN < inftl->nb_blocks) { @@ -826,7 +821,7 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, struct inftl_oob oob; char *p, *pend; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=%p,block=%ld," + pr_debug("INFTL: inftl_writeblock(inftl=%p,block=%ld," "buffer=%p)\n", inftl, block, buffer); /* Is block all zero? */ @@ -876,7 +871,7 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, struct inftl_bci bci; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld," + pr_debug("INFTL: inftl_readblock(inftl=%p,block=%ld," "buffer=%p)\n", inftl, block, buffer); while (thisEUN < inftl->nb_blocks) { @@ -922,7 +917,7 @@ foundit: int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer); /* Handle corrected bit flips gracefully */ - if (ret < 0 && ret != -EUCLEAN) + if (ret < 0 && !mtd_is_bitflip(ret)) return -EIO; } return 0; diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 104052e774b0..2ff601f816ce 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -53,7 +53,7 @@ static int find_boot_record(struct INFTLrecord *inftl) struct INFTLPartition *ip; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=%p)\n", inftl); + pr_debug("INFTL: find_boot_record(inftl=%p)\n", inftl); /* * Assume logical EraseSize == physical erasesize for starting the @@ -139,24 +139,20 @@ static int find_boot_record(struct INFTLrecord *inftl) mh->FormatFlags = le32_to_cpu(mh->FormatFlags); mh->PercentUsed = le32_to_cpu(mh->PercentUsed); -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { - printk("INFTL: Media Header ->\n" - " bootRecordID = %s\n" - " NoOfBootImageBlocks = %d\n" - " NoOfBinaryPartitions = %d\n" - " NoOfBDTLPartitions = %d\n" - " BlockMultiplerBits = %d\n" - " FormatFlgs = %d\n" - " OsakVersion = 0x%x\n" - " PercentUsed = %d\n", - mh->bootRecordID, mh->NoOfBootImageBlocks, - mh->NoOfBinaryPartitions, - mh->NoOfBDTLPartitions, - mh->BlockMultiplierBits, mh->FormatFlags, - mh->OsakVersion, mh->PercentUsed); - } -#endif + pr_debug("INFTL: Media Header ->\n" + " bootRecordID = %s\n" + " NoOfBootImageBlocks = %d\n" + " NoOfBinaryPartitions = %d\n" + " NoOfBDTLPartitions = %d\n" + " BlockMultiplerBits = %d\n" + " FormatFlgs = %d\n" + " OsakVersion = 0x%x\n" + " PercentUsed = %d\n", + mh->bootRecordID, mh->NoOfBootImageBlocks, + mh->NoOfBinaryPartitions, + mh->NoOfBDTLPartitions, + mh->BlockMultiplierBits, mh->FormatFlags, + mh->OsakVersion, mh->PercentUsed); if (mh->NoOfBDTLPartitions == 0) { printk(KERN_WARNING "INFTL: Media Header sanity check " @@ -200,19 +196,15 @@ static int find_boot_record(struct INFTLrecord *inftl) ip->spareUnits = le32_to_cpu(ip->spareUnits); ip->Reserved0 = le32_to_cpu(ip->Reserved0); -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { - printk(" PARTITION[%d] ->\n" - " virtualUnits = %d\n" - " firstUnit = %d\n" - " lastUnit = %d\n" - " flags = 0x%x\n" - " spareUnits = %d\n", - i, ip->virtualUnits, ip->firstUnit, - ip->lastUnit, ip->flags, - ip->spareUnits); - } -#endif + pr_debug(" PARTITION[%d] ->\n" + " virtualUnits = %d\n" + " firstUnit = %d\n" + " lastUnit = %d\n" + " flags = 0x%x\n" + " spareUnits = %d\n", + i, ip->virtualUnits, ip->firstUnit, + ip->lastUnit, ip->flags, + ip->spareUnits); if (ip->Reserved0 != ip->firstUnit) { struct erase_info *instr = &inftl->instr; @@ -375,7 +367,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, * * Return: 0 when succeed, -1 on error. * - * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * ToDo: 1. Is it necessary to check_free_sector after erasing ?? */ int INFTL_formatblock(struct INFTLrecord *inftl, int block) { @@ -385,8 +377,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block) struct mtd_info *mtd = inftl->mbd.mtd; int physblock; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p," - "block=%d)\n", inftl, block); + pr_debug("INFTL: INFTL_formatblock(inftl=%p,block=%d)\n", inftl, block); memset(instr, 0, sizeof(struct erase_info)); @@ -476,30 +467,30 @@ void INFTL_dumptables(struct INFTLrecord *s) { int i; - printk("-------------------------------------------" + pr_debug("-------------------------------------------" "----------------------------------\n"); - printk("VUtable[%d] ->", s->nb_blocks); + pr_debug("VUtable[%d] ->", s->nb_blocks); for (i = 0; i < s->nb_blocks; i++) { if ((i % 8) == 0) - printk("\n%04x: ", i); - printk("%04x ", s->VUtable[i]); + pr_debug("\n%04x: ", i); + pr_debug("%04x ", s->VUtable[i]); } - printk("\n-------------------------------------------" + pr_debug("\n-------------------------------------------" "----------------------------------\n"); - printk("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); + pr_debug("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); for (i = 0; i <= s->lastEUN; i++) { if ((i % 8) == 0) - printk("\n%04x: ", i); - printk("%04x ", s->PUtable[i]); + pr_debug("\n%04x: ", i); + pr_debug("%04x ", s->PUtable[i]); } - printk("\n-------------------------------------------" + pr_debug("\n-------------------------------------------" "----------------------------------\n"); - printk("INFTL ->\n" + pr_debug("INFTL ->\n" " EraseSize = %d\n" " h/s/c = %d/%d/%d\n" " numvunits = %d\n" @@ -513,7 +504,7 @@ void INFTL_dumptables(struct INFTLrecord *s) s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs, s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks); - printk("\n-------------------------------------------" + pr_debug("\n-------------------------------------------" "----------------------------------\n"); } @@ -521,25 +512,25 @@ void INFTL_dumpVUchains(struct INFTLrecord *s) { int logical, block, i; - printk("-------------------------------------------" + pr_debug("-------------------------------------------" "----------------------------------\n"); - printk("INFTL Virtual Unit Chains:\n"); + pr_debug("INFTL Virtual Unit Chains:\n"); for (logical = 0; logical < s->nb_blocks; logical++) { block = s->VUtable[logical]; if (block > s->nb_blocks) continue; - printk(" LOGICAL %d --> %d ", logical, block); + pr_debug(" LOGICAL %d --> %d ", logical, block); for (i = 0; i < s->nb_blocks; i++) { if (s->PUtable[block] == BLOCK_NIL) break; block = s->PUtable[block]; - printk("%d ", block); + pr_debug("%d ", block); } - printk("\n"); + pr_debug("\n"); } - printk("-------------------------------------------" + pr_debug("-------------------------------------------" "----------------------------------\n"); } @@ -555,7 +546,7 @@ int INFTL_mount(struct INFTLrecord *s) int i; u8 *ANACtable, ANAC; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=%p)\n", s); + pr_debug("INFTL: INFTL_mount(inftl=%p)\n", s); /* Search for INFTL MediaHeader and Spare INFTL Media Header */ if (find_boot_record(s) < 0) { @@ -585,7 +576,7 @@ int INFTL_mount(struct INFTLrecord *s) * NOTEXPLORED state. Then at the end we will try to format it and * mark it as free. */ - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 1, explore each unit\n"); + pr_debug("INFTL: pass 1, explore each unit\n"); for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) { if (s->PUtable[first_block] != BLOCK_NOTEXPLORED) continue; @@ -717,17 +708,14 @@ int INFTL_mount(struct INFTLrecord *s) logical_block = BLOCK_NIL; } -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) - INFTL_dumptables(s); -#endif + INFTL_dumptables(s); /* * Second pass, check for infinite loops in chains. These are * possible because we don't update the previous pointers when * we fold chains. No big deal, just fix them up in PUtable. */ - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 2, validate virtual chains\n"); + pr_debug("INFTL: pass 2, validate virtual chains\n"); for (logical_block = 0; logical_block < s->numvunits; logical_block++) { block = s->VUtable[logical_block]; last_block = BLOCK_NIL; @@ -772,12 +760,8 @@ int INFTL_mount(struct INFTLrecord *s) } } -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) - INFTL_dumptables(s); - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) - INFTL_dumpVUchains(s); -#endif + INFTL_dumptables(s); + INFTL_dumpVUchains(s); /* * Third pass, format unreferenced blocks and init free block count. @@ -785,7 +769,7 @@ int INFTL_mount(struct INFTLrecord *s) s->numfreeEUNs = 0; s->LastFreeEUN = BLOCK_NIL; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 3, format unused blocks\n"); + pr_debug("INFTL: pass 3, format unused blocks\n"); for (block = s->firstEUN; block <= s->lastEUN; block++) { if (s->PUtable[block] == BLOCK_NOTEXPLORED) { printk("INFTL: unreferenced block %d, formatting it\n", diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 65655dd59e1f..1dca31d9a8b3 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -27,6 +27,7 @@ #include <linux/mtd/pfow.h> #include <linux/mtd/qinfo.h> #include <linux/slab.h> +#include <linux/module.h> static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len, size_t *retlen, u_char *buf); diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index c0c328c5b133..8e0c4bf9f7fb 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -41,8 +41,6 @@ config MTD_PHYSMAP_START are mapped on your particular target board. Refer to the memory map which should hopefully be in the documentation for your board. - Ignore this option if you use run-time physmap configuration - (i.e., run-time calling physmap_configure()). config MTD_PHYSMAP_LEN hex "Physical length of flash mapping" @@ -55,8 +53,6 @@ config MTD_PHYSMAP_LEN than the total amount of flash present. Refer to the memory map which should hopefully be in the documentation for your board. - Ignore this option if you use run-time physmap configuration - (i.e., run-time calling physmap_configure()). config MTD_PHYSMAP_BANKWIDTH int "Bank width in octets" @@ -67,8 +63,6 @@ config MTD_PHYSMAP_BANKWIDTH in octets. For example, if you have a data bus width of 32 bits, you would set the bus width octet value to 4. This is used internally by the CFI drivers. - Ignore this option if you use run-time physmap configuration - (i.e., run-time calling physmap_configure()). config MTD_PHYSMAP_OF tristate "Flash device in physical memory map based on OF description" @@ -260,7 +254,6 @@ config MTD_BCM963XX config MTD_LANTIQ tristate "Lantiq SoC NOR support" depends on LANTIQ - select MTD_PARTITIONS help Support for NOR flash attached to the Lantiq SoC's External Bus Unit. @@ -339,10 +332,6 @@ config MTD_SOLUTIONENGINE This enables access to the flash chips on the Hitachi SolutionEngine and similar boards. Say 'Y' if you are building a kernel for such a board. -config MTD_ARM_INTEGRATOR - tristate "CFI Flash device mapped on ARM Integrator/P720T" - depends on ARM && MTD_CFI - config MTD_CDB89712 tristate "Cirrus CDB89712 evaluation board mappings" depends on MTD_CFI && ARCH_CDB89712 @@ -398,13 +387,6 @@ config MTD_AUTCPU12 This enables access to the NV-RAM on autronix autcpu12 board. If you have such a board, say 'Y'. -config MTD_EDB7312 - tristate "CFI Flash device mapped on EDB7312" - depends on ARCH_EDB7312 && MTD_CFI - help - This enables access to the CFI Flash on the Cogent EDB7312 board. - If you have such a board, say 'Y' here. - config MTD_IMPA7 tristate "JEDEC Flash device mapped on impA7" depends on ARM && MTD_JEDECPROBE @@ -412,14 +394,6 @@ config MTD_IMPA7 This enables access to the NOR Flash on the impA7 board of implementa GmbH. If you have such a board, say 'Y' here. -config MTD_CEIVA - tristate "JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame" - depends on MTD_JEDECPROBE && ARCH_CEIVA - help - This enables access to the flash chips on the Ceiva/Polaroid - PhotoMax Digital Picture Frame. - If you have such a device, say 'Y'. - config MTD_H720X tristate "Hynix evaluation board mappings" depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index cb48b11affff..45dcb8b14f22 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o obj-$(CONFIG_MTD_MBX860) += mbx860.o -obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o @@ -40,7 +39,6 @@ obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o -obj-$(CONFIG_MTD_EDB7312) += edb7312.o obj-$(CONFIG_MTD_IMPA7) += impa7.o obj-$(CONFIG_MTD_FORTUNET) += fortunet.o obj-$(CONFIG_MTD_UCLINUX) += uclinux.o diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 67815eed2f00..6d6b2b5674ee 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -41,7 +41,6 @@ struct async_state { uint32_t flash_ambctl0, flash_ambctl1; uint32_t save_ambctl0, save_ambctl1; unsigned long irq_flags; - struct mtd_partition *parts; }; static void switch_to_flash(struct async_state *state) @@ -165,18 +164,8 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev) return -ENXIO; } - ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0); - if (ret > 0) { - pr_devinit(KERN_NOTICE DRIVER_NAME ": Using commandline partition definition\n"); - mtd_device_register(state->mtd, pdata->parts, ret); - state->parts = pdata->parts; - } else if (pdata->nr_parts) { - pr_devinit(KERN_NOTICE DRIVER_NAME ": Using board partition definition\n"); - mtd_device_register(state->mtd, pdata->parts, pdata->nr_parts); - } else { - pr_devinit(KERN_NOTICE DRIVER_NAME ": no partition info available, registering whole flash at once\n"); - mtd_device_register(state->mtd, NULL, 0); - } + mtd_device_parse_register(state->mtd, part_probe_types, 0, + pdata->parts, pdata->nr_parts); platform_set_drvdata(pdev, state); @@ -188,7 +177,6 @@ static int __devexit bfin_flash_remove(struct platform_device *pdev) struct async_state *state = platform_get_drvdata(pdev); gpio_free(state->enet_flash_pin); mtd_device_unregister(state->mtd); - kfree(state->parts); map_destroy(state->mtd); kfree(state); return 0; diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c deleted file mode 100644 index 06f9c9815720..000000000000 --- a/drivers/mtd/maps/ceiva.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Ceiva flash memory driver. - * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net> - * - * Note: this driver supports jedec compatible devices. Modification - * for CFI compatible devices should be straight forward: change - * jedec_probe to cfi_probe. - * - * Based on: sa1100-flash.c, which has the following copyright: - * Flash memory access on SA11x0 based devices - * - * (C) 2000 Nicolas Pitre <nico@fluxnic.net> - * - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/slab.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/concat.h> - -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/io.h> -#include <asm/sizes.h> - -/* - * This isn't complete yet, so... - */ -#define CONFIG_MTD_CEIVA_STATICMAP - -#ifdef CONFIG_MTD_CEIVA_STATICMAP -/* - * See include/linux/mtd/partitions.h for definition of the mtd_partition - * structure. - * - * Please note: - * 1. The flash size given should be the largest flash size that can - * be accommodated. - * - * 2. The bus width must defined in clps_setup_flash. - * - * The MTD layer will detect flash chip aliasing and reduce the size of - * the map accordingly. - * - */ - -#ifdef CONFIG_ARCH_CEIVA -/* Flash / Partition sizing */ -/* For the 28F8003, we use the block mapping to calcuate the sizes */ -#define MAX_SIZE_KiB (16 + 8 + 8 + 96 + (7*128)) -#define BOOT_PARTITION_SIZE_KiB (16) -#define PARAMS_PARTITION_SIZE_KiB (8) -#define KERNEL_PARTITION_SIZE_KiB (4*128) -/* Use both remaining portion of first flash, and all of second flash */ -#define ROOT_PARTITION_SIZE_KiB (3*128) + (8*128) - -static struct mtd_partition ceiva_partitions[] = { - { - .name = "Ceiva BOOT partition", - .size = BOOT_PARTITION_SIZE_KiB*1024, - .offset = 0, - - },{ - .name = "Ceiva parameters partition", - .size = PARAMS_PARTITION_SIZE_KiB*1024, - .offset = (16 + 8) * 1024, - },{ - .name = "Ceiva kernel partition", - .size = (KERNEL_PARTITION_SIZE_KiB)*1024, - .offset = 0x20000, - - },{ - .name = "Ceiva root filesystem partition", - .offset = MTDPART_OFS_APPEND, - .size = (ROOT_PARTITION_SIZE_KiB)*1024, - } -}; -#endif - -static int __init clps_static_partitions(struct mtd_partition **parts) -{ - int nb_parts = 0; - -#ifdef CONFIG_ARCH_CEIVA - if (machine_is_ceiva()) { - *parts = ceiva_partitions; - nb_parts = ARRAY_SIZE(ceiva_partitions); - } -#endif - return nb_parts; -} -#endif - -struct clps_info { - unsigned long base; - unsigned long size; - int width; - void *vbase; - struct map_info *map; - struct mtd_info *mtd; - struct resource *res; -}; - -#define NR_SUBMTD 4 - -static struct clps_info info[NR_SUBMTD]; - -static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd) -{ - struct mtd_info *subdev[nr]; - struct map_info *maps; - int i, found = 0, ret = 0; - - /* - * Allocate the map_info structs in one go. - */ - maps = kzalloc(sizeof(struct map_info) * nr, GFP_KERNEL); - if (!maps) - return -ENOMEM; - /* - * Claim and then map the memory regions. - */ - for (i = 0; i < nr; i++) { - if (clps[i].base == (unsigned long)-1) - break; - - clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash"); - if (!clps[i].res) { - ret = -EBUSY; - break; - } - - clps[i].map = maps + i; - - clps[i].map->name = "clps flash"; - clps[i].map->phys = clps[i].base; - - clps[i].vbase = ioremap(clps[i].base, clps[i].size); - if (!clps[i].vbase) { - ret = -ENOMEM; - break; - } - - clps[i].map->virt = (void __iomem *)clps[i].vbase; - clps[i].map->bankwidth = clps[i].width; - clps[i].map->size = clps[i].size; - - simple_map_init(&clps[i].map); - - clps[i].mtd = do_map_probe("jedec_probe", clps[i].map); - if (clps[i].mtd == NULL) { - ret = -ENXIO; - break; - } - clps[i].mtd->owner = THIS_MODULE; - subdev[i] = clps[i].mtd; - - printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, " - "%d-bit\n", clps[i].base, clps[i].mtd->size >> 20, - clps[i].width * 8); - found += 1; - } - - /* - * ENXIO is special. It means we didn't find a chip when - * we probed. We need to tear down the mapping, free the - * resource and mark it as such. - */ - if (ret == -ENXIO) { - iounmap(clps[i].vbase); - clps[i].vbase = NULL; - release_resource(clps[i].res); - clps[i].res = NULL; - } - - /* - * If we found one device, don't bother with concat support. - * If we found multiple devices, use concat if we have it - * available, otherwise fail. - */ - if (ret == 0 || ret == -ENXIO) { - if (found == 1) { - *rmtd = subdev[0]; - ret = 0; - } else if (found > 1) { - /* - * We detected multiple devices. Concatenate - * them together. - */ - *rmtd = mtd_concat_create(subdev, found, - "clps flash"); - if (*rmtd == NULL) - ret = -ENXIO; - } - } - - /* - * If we failed, clean up. - */ - if (ret) { - do { - if (clps[i].mtd) - map_destroy(clps[i].mtd); - if (clps[i].vbase) - iounmap(clps[i].vbase); - if (clps[i].res) - release_resource(clps[i].res); - } while (i--); - - kfree(maps); - } - - return ret; -} - -static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd) -{ - int i; - - mtd_device_unregister(mtd); - - if (mtd != clps[0].mtd) - mtd_concat_destroy(mtd); - - for (i = NR_SUBMTD; i >= 0; i--) { - if (clps[i].mtd) - map_destroy(clps[i].mtd); - if (clps[i].vbase) - iounmap(clps[i].vbase); - if (clps[i].res) - release_resource(clps[i].res); - } - kfree(clps[0].map); -} - -/* - * We define the memory space, size, and width for the flash memory - * space here. - */ - -static int __init clps_setup_flash(void) -{ - int nr = 0; - -#ifdef CONFIG_ARCH_CEIVA - if (machine_is_ceiva()) { - info[0].base = CS0_PHYS_BASE; - info[0].size = SZ_32M; - info[0].width = CEIVA_FLASH_WIDTH; - info[1].base = CS1_PHYS_BASE; - info[1].size = SZ_32M; - info[1].width = CEIVA_FLASH_WIDTH; - nr = 2; - } -#endif - return nr; -} - -static struct mtd_partition *parsed_parts; -static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; - -static void __init clps_locate_partitions(struct mtd_info *mtd) -{ - const char *part_type = NULL; - int nr_parts = 0; - do { - /* - * Partition selection stuff. - */ - nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0); - if (nr_parts > 0) { - part_type = "command line"; - break; - } -#ifdef CONFIG_MTD_CEIVA_STATICMAP - nr_parts = clps_static_partitions(&parsed_parts); - if (nr_parts > 0) { - part_type = "static"; - break; - } - printk("found: %d partitions\n", nr_parts); -#endif - } while (0); - - if (nr_parts == 0) { - printk(KERN_NOTICE "clps flash: no partition info " - "available, registering whole flash\n"); - mtd_device_register(mtd, NULL, 0); - } else { - printk(KERN_NOTICE "clps flash: using %s partition " - "definition\n", part_type); - mtd_device_register(mtd, parsed_parts, nr_parts); - } - - /* Always succeeds. */ -} - -static void __exit clps_destroy_partitions(void) -{ - kfree(parsed_parts); -} - -static struct mtd_info *mymtd; - -static int __init clps_mtd_init(void) -{ - int ret; - int nr; - - nr = clps_setup_flash(); - if (nr < 0) - return nr; - - ret = clps_setup_mtd(info, nr, &mymtd); - if (ret) - return ret; - - clps_locate_partitions(mymtd); - - return 0; -} - -static void __exit clps_mtd_cleanup(void) -{ - clps_destroy_mtd(info, mymtd); - clps_destroy_partitions(); -} - -module_init(clps_mtd_init); -module_exit(clps_mtd_cleanup); - -MODULE_AUTHOR("Rob Scott"); -MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index 7a9e1989c977..f43b365b848c 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -145,14 +145,10 @@ static struct map_info dc21285_map = { /* Partition stuff */ -static struct mtd_partition *dc21285_parts; static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; static int __init init_dc21285(void) { - - int nrparts; - /* Determine bankwidth */ switch (*CSR_SA110_CNTL & (3<<14)) { case SA110_CNTL_ROMWIDTH_8: @@ -200,8 +196,7 @@ static int __init init_dc21285(void) dc21285_mtd->owner = THIS_MODULE; - nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0); - mtd_device_register(dc21285_mtd, dc21285_parts, nrparts); + mtd_device_parse_register(dc21285_mtd, probes, 0, NULL, 0); if(machine_is_ebsa285()) { /* @@ -224,8 +219,6 @@ static int __init init_dc21285(void) static void __exit cleanup_dc21285(void) { mtd_device_unregister(dc21285_mtd); - if (dc21285_parts) - kfree(dc21285_parts); map_destroy(dc21285_mtd); iounmap(dc21285_map.virt); } diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c deleted file mode 100644 index fe42a212bb3e..000000000000 --- a/drivers/mtd/maps/edb7312.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Handle mapping of the NOR flash on Cogent EDB7312 boards - * - * Copyright 2002 SYSGO Real-Time Solutions GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <asm/io.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#define WINDOW_ADDR 0x00000000 /* physical properties of flash */ -#define WINDOW_SIZE 0x01000000 -#define BUSWIDTH 2 -#define FLASH_BLOCKSIZE_MAIN 0x20000 -#define FLASH_NUMBLOCKS_MAIN 128 -/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */ -#define PROBETYPES { "cfi_probe", NULL } - -#define MSG_PREFIX "EDB7312-NOR:" /* prefix for our printk()'s */ -#define MTDID "edb7312-nor" /* for mtdparts= partitioning */ - -static struct mtd_info *mymtd; - -struct map_info edb7312nor_map = { - .name = "NOR flash on EDB7312", - .size = WINDOW_SIZE, - .bankwidth = BUSWIDTH, - .phys = WINDOW_ADDR, -}; - -/* - * MTD partitioning stuff - */ -static struct mtd_partition static_partitions[3] = -{ - { - .name = "ARMboot", - .size = 0x40000, - .offset = 0 - }, - { - .name = "Kernel", - .size = 0x200000, - .offset = 0x40000 - }, - { - .name = "RootFS", - .size = 0xDC0000, - .offset = 0x240000 - }, -}; - -static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - -static int mtd_parts_nb = 0; -static struct mtd_partition *mtd_parts = 0; - -static int __init init_edb7312nor(void) -{ - static const char *rom_probe_types[] = PROBETYPES; - const char **type; - const char *part_type = 0; - - printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", - WINDOW_SIZE, WINDOW_ADDR); - edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); - - if (!edb7312nor_map.virt) { - printk(MSG_PREFIX "failed to ioremap\n"); - return -EIO; - } - - simple_map_init(&edb7312nor_map); - - mymtd = 0; - type = rom_probe_types; - for(; !mymtd && *type; type++) { - mymtd = do_map_probe(*type, &edb7312nor_map); - } - if (mymtd) { - mymtd->owner = THIS_MODULE; - - mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID); - if (mtd_parts_nb > 0) - part_type = "detected"; - - if (mtd_parts_nb == 0) { - mtd_parts = static_partitions; - mtd_parts_nb = ARRAY_SIZE(static_partitions); - part_type = "static"; - } - - if (mtd_parts_nb == 0) - printk(KERN_NOTICE MSG_PREFIX "no partition info available\n"); - else - printk(KERN_NOTICE MSG_PREFIX - "using %s partition definition\n", part_type); - /* Register the whole device first. */ - mtd_device_register(mymtd, NULL, 0); - mtd_device_register(mymtd, mtd_parts, mtd_parts_nb); - return 0; - } - - iounmap((void *)edb7312nor_map.virt); - return -ENXIO; -} - -static void __exit cleanup_edb7312nor(void) -{ - if (mymtd) { - mtd_device_unregister(mymtd); - map_destroy(mymtd); - } - if (edb7312nor_map.virt) { - iounmap((void *)edb7312nor_map.virt); - edb7312nor_map.virt = 0; - } -} - -module_init(init_edb7312nor); -module_exit(cleanup_edb7312nor); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); -MODULE_DESCRIPTION("Generic configurable MTD map driver"); diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 7568c5f8b8ae..1ec66f031c51 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -187,7 +187,6 @@ static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; */ static int __devinit gpio_flash_probe(struct platform_device *pdev) { - int nr_parts; size_t i, arr_size; struct physmap_flash_data *pdata; struct resource *memory; @@ -252,20 +251,9 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev) return -ENXIO; } - nr_parts = parse_mtd_partitions(state->mtd, part_probe_types, - &pdata->parts, 0); - if (nr_parts > 0) { - pr_devinit(KERN_NOTICE PFX "Using commandline partition definition\n"); - kfree(pdata->parts); - } else if (pdata->nr_parts) { - pr_devinit(KERN_NOTICE PFX "Using board partition definition\n"); - nr_parts = pdata->nr_parts; - } else { - pr_devinit(KERN_NOTICE PFX "no partition info available, registering whole flash at once\n"); - nr_parts = 0; - } - mtd_device_register(state->mtd, pdata->parts, nr_parts); + mtd_device_parse_register(state->mtd, part_probe_types, 0, + pdata->parts, pdata->nr_parts); return 0; } diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index 7f035860a36b..49c14187fc66 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -58,18 +58,11 @@ static struct mtd_partition h720x_partitions[] = { #define NUM_PARTITIONS ARRAY_SIZE(h720x_partitions) -static int nr_mtd_parts; -static struct mtd_partition *mtd_parts; -static const char *probes[] = { "cmdlinepart", NULL }; - /* * Initialize FLASH support */ static int __init h720x_mtd_init(void) { - - char *part_type = NULL; - h720x_map.virt = ioremap(h720x_map.phys, h720x_map.size); if (!h720x_map.virt) { @@ -92,16 +85,8 @@ static int __init h720x_mtd_init(void) if (mymtd) { mymtd->owner = THIS_MODULE; - nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0); - if (nr_mtd_parts > 0) - part_type = "command line"; - if (nr_mtd_parts <= 0) { - mtd_parts = h720x_partitions; - nr_mtd_parts = NUM_PARTITIONS; - part_type = "builtin"; - } - printk(KERN_INFO "Using %s partition table\n", part_type); - mtd_device_register(mymtd, mtd_parts, nr_mtd_parts); + mtd_device_parse_register(mymtd, NULL, 0, + h720x_partitions, NUM_PARTITIONS); return 0; } @@ -120,10 +105,6 @@ static void __exit h720x_mtd_cleanup(void) map_destroy(mymtd); } - /* Free partition info, if commandline partition was used */ - if (mtd_parts && (mtd_parts != h720x_partitions)) - kfree (mtd_parts); - if (h720x_map.virt) { iounmap((void *)h720x_map.virt); h720x_map.virt = 0; diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 404a50cbafa0..f47aedb24366 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -49,7 +49,7 @@ static struct map_info impa7_map[NUM_FLASHBANKS] = { /* * MTD partitioning stuff */ -static struct mtd_partition static_partitions[] = +static struct mtd_partition partitions[] = { { .name = "FileSystem", @@ -58,16 +58,10 @@ static struct mtd_partition static_partitions[] = }, }; -static int mtd_parts_nb[NUM_FLASHBANKS]; -static struct mtd_partition *mtd_parts[NUM_FLASHBANKS]; - -static const char *probes[] = { "cmdlinepart", NULL }; - static int __init init_impa7(void) { static const char *rom_probe_types[] = PROBETYPES; const char **type; - const char *part_type = 0; int i; static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = { { WINDOW_ADDR0, WINDOW_SIZE0 }, @@ -97,23 +91,9 @@ static int __init init_impa7(void) if (impa7_mtd[i]) { impa7_mtd[i]->owner = THIS_MODULE; devicesfound++; - mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], - probes, - &mtd_parts[i], - 0); - if (mtd_parts_nb[i] > 0) { - part_type = "command line"; - } else { - mtd_parts[i] = static_partitions; - mtd_parts_nb[i] = ARRAY_SIZE(static_partitions); - part_type = "static"; - } - - printk(KERN_NOTICE MSG_PREFIX - "using %s partition definition\n", - part_type); - mtd_device_register(impa7_mtd[i], - mtd_parts[i], mtd_parts_nb[i]); + mtd_device_parse_register(impa7_mtd[i], NULL, 0, + partitions, + ARRAY_SIZE(partitions)); } else iounmap((void *)impa7_map[i].virt); diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index d2f47be8754b..08c239604ee4 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -44,7 +44,6 @@ struct vr_nor_mtd { void __iomem *csr_base; struct map_info map; struct mtd_info *info; - int nr_parts; struct pci_dev *dev; }; @@ -71,13 +70,9 @@ static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p) static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p) { - struct mtd_partition *parts; - static const char *part_probes[] = { "cmdlinepart", NULL }; - /* register the flash bank */ /* partition the flash bank */ - p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0); - return mtd_device_register(p->info, parts, p->nr_parts); + return mtd_device_parse_register(p->info, NULL, 0, NULL, 0); } static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index 1594a802631d..437fcd2f352f 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -38,7 +38,6 @@ struct ixp2000_flash_info { struct mtd_info *mtd; struct map_info map; - struct mtd_partition *partitions; struct resource *res; }; @@ -125,8 +124,6 @@ static int ixp2000_flash_remove(struct platform_device *dev) if (info->map.map_priv_1) iounmap((void *) info->map.map_priv_1); - kfree(info->partitions); - if (info->res) { release_resource(info->res); kfree(info->res); @@ -229,13 +226,7 @@ static int ixp2000_flash_probe(struct platform_device *dev) } info->mtd->owner = THIS_MODULE; - err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); - if (err > 0) { - err = mtd_device_register(info->mtd, info->partitions, err); - if(err) - dev_err(&dev->dev, "Could not parse partitions\n"); - } - + err = mtd_device_parse_register(info->mtd, probes, 0, NULL, 0); if (err) goto Error; diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 155b21942f47..30409015a3de 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -145,7 +145,6 @@ static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) struct ixp4xx_flash_info { struct mtd_info *mtd; struct map_info map; - struct mtd_partition *partitions; struct resource *res; }; @@ -168,8 +167,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev) if (info->map.virt) iounmap(info->map.virt); - kfree(info->partitions); - if (info->res) { release_resource(info->res); kfree(info->res); @@ -185,8 +182,6 @@ static int ixp4xx_flash_probe(struct platform_device *dev) { struct flash_platform_data *plat = dev->dev.platform_data; struct ixp4xx_flash_info *info; - const char *part_type = NULL; - int nr_parts = 0; int err = -1; if (!plat) @@ -252,28 +247,12 @@ static int ixp4xx_flash_probe(struct platform_device *dev) /* Use the fast version */ info->map.write = ixp4xx_write16; - nr_parts = parse_mtd_partitions(info->mtd, probes, &info->partitions, - dev->resource->start); - if (nr_parts > 0) { - part_type = "dynamic"; - } else { - info->partitions = plat->parts; - nr_parts = plat->nr_parts; - part_type = "static"; - } - if (nr_parts == 0) - printk(KERN_NOTICE "IXP4xx flash: no partition info " - "available, registering whole flash\n"); - else - printk(KERN_NOTICE "IXP4xx flash: using %s partition " - "definition\n", part_type); - - err = mtd_device_register(info->mtd, info->partitions, nr_parts); - if (err) + err = mtd_device_parse_register(info->mtd, probes, dev->resource->start, + plat->parts, plat->nr_parts); + if (err) { printk(KERN_ERR "Could not parse partitions\n"); - - if (err) goto Error; + } return 0; diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 7e508969239e..4f10e27ada55 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -107,16 +107,12 @@ ltq_copy_to(struct map_info *map, unsigned long to, spin_unlock_irqrestore(&ebu_lock, flags); } -static const char const *part_probe_types[] = { "cmdlinepart", NULL }; - static int __init ltq_mtd_probe(struct platform_device *pdev) { struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); struct ltq_mtd *ltq_mtd; - struct mtd_partition *parts; struct resource *res; - int nr_parts = 0; struct cfi_private *cfi; int err; @@ -172,17 +168,8 @@ ltq_mtd_probe(struct platform_device *pdev) cfi->addr_unlock1 ^= 1; cfi->addr_unlock2 ^= 1; - nr_parts = parse_mtd_partitions(ltq_mtd->mtd, - part_probe_types, &parts, 0); - if (nr_parts > 0) { - dev_info(&pdev->dev, - "using %d partitions from cmdline", nr_parts); - } else { - nr_parts = ltq_mtd_data->nr_parts; - parts = ltq_mtd_data->parts; - } - - err = mtd_device_register(ltq_mtd->mtd, parts, nr_parts); + err = mtd_device_parse_register(ltq_mtd->mtd, NULL, 0, + ltq_mtd_data->parts, ltq_mtd_data->nr_parts); if (err) { dev_err(&pdev->dev, "failed to add partitions\n"); goto err_destroy; diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c index 5936c466e901..119baa7d7477 100644 --- a/drivers/mtd/maps/latch-addr-flash.c +++ b/drivers/mtd/maps/latch-addr-flash.c @@ -33,9 +33,6 @@ struct latch_addr_flash_info { /* cache; could be found out of res */ unsigned long win_mask; - int nr_parts; - struct mtd_partition *parts; - spinlock_t lock; }; @@ -97,8 +94,6 @@ static void lf_copy_from(struct map_info *map, void *to, static char *rom_probe_types[] = { "cfi_probe", NULL }; -static char *part_probe_types[] = { "cmdlinepart", NULL }; - static int latch_addr_flash_remove(struct platform_device *dev) { struct latch_addr_flash_info *info; @@ -112,8 +107,6 @@ static int latch_addr_flash_remove(struct platform_device *dev) latch_addr_data = dev->dev.platform_data; if (info->mtd != NULL) { - if (info->nr_parts) - kfree(info->parts); mtd_device_unregister(info->mtd); map_destroy(info->mtd); } @@ -206,21 +199,8 @@ static int __devinit latch_addr_flash_probe(struct platform_device *dev) } info->mtd->owner = THIS_MODULE; - err = parse_mtd_partitions(info->mtd, (const char **)part_probe_types, - &info->parts, 0); - if (err > 0) { - mtd_device_register(info->mtd, info->parts, err); - return 0; - } - if (latch_addr_data->nr_parts) { - pr_notice("Using latch-addr-flash partition information\n"); - mtd_device_register(info->mtd, - latch_addr_data->parts, - latch_addr_data->nr_parts); - return 0; - } - - mtd_device_register(info->mtd, NULL, 0); + mtd_device_parse_register(info->mtd, NULL, 0, + latch_addr_data->parts, latch_addr_data->nr_parts); return 0; iounmap: diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index bbe168b65c26..e8e9fec23553 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -22,22 +22,6 @@ #include <linux/mtd/map.h> #include <linux/mtd/mtd.h> -#ifdef CONFIG_MTD_DEBUG -static int debug = CONFIG_MTD_DEBUG_VERBOSE; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy"); -#undef DEBUG -#define DEBUG(n, format, arg...) \ - if (n <= debug) { \ - printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \ - } - -#else -#undef DEBUG -#define DEBUG(n, arg...) -static const int debug = 0; -#endif - #define info(format, arg...) printk(KERN_INFO "pcmciamtd: " format "\n" , ## arg) #define DRIVER_DESC "PCMCIA Flash memory card driver" @@ -105,13 +89,13 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) int ret; if (!pcmcia_dev_present(dev->p_dev)) { - DEBUG(1, "device removed"); + pr_debug("device removed\n"); return 0; } offset = to & ~(dev->win_size-1); if (offset != dev->offset) { - DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x", + pr_debug("Remapping window from 0x%8.8x to 0x%8.8x\n", dev->offset, offset); ret = pcmcia_map_mem_page(dev->p_dev, win, offset); if (ret != 0) @@ -132,7 +116,7 @@ static map_word pcmcia_read8_remap(struct map_info *map, unsigned long ofs) return d; d.x[0] = readb(addr); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02lx", ofs, addr, d.x[0]); + pr_debug("ofs = 0x%08lx (%p) data = 0x%02lx\n", ofs, addr, d.x[0]); return d; } @@ -147,7 +131,7 @@ static map_word pcmcia_read16_remap(struct map_info *map, unsigned long ofs) return d; d.x[0] = readw(addr); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04lx", ofs, addr, d.x[0]); + pr_debug("ofs = 0x%08lx (%p) data = 0x%04lx\n", ofs, addr, d.x[0]); return d; } @@ -157,7 +141,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; unsigned long win_size = dev->win_size; - DEBUG(3, "to = %p from = %lu len = %zd", to, from, len); + pr_debug("to = %p from = %lu len = %zd\n", to, from, len); while(len) { int toread = win_size - (from & (win_size-1)); caddr_t addr; @@ -169,7 +153,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long if(!addr) return; - DEBUG(4, "memcpy from %p to %p len = %d", addr, to, toread); + pr_debug("memcpy from %p to %p len = %d\n", addr, to, toread); memcpy_fromio(to, addr, toread); len -= toread; to += toread; @@ -185,7 +169,7 @@ static void pcmcia_write8_remap(struct map_info *map, map_word d, unsigned long if(!addr) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02lx", adr, addr, d.x[0]); + pr_debug("adr = 0x%08lx (%p) data = 0x%02lx\n", adr, addr, d.x[0]); writeb(d.x[0], addr); } @@ -196,7 +180,7 @@ static void pcmcia_write16_remap(struct map_info *map, map_word d, unsigned long if(!addr) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04lx", adr, addr, d.x[0]); + pr_debug("adr = 0x%08lx (%p) data = 0x%04lx\n", adr, addr, d.x[0]); writew(d.x[0], addr); } @@ -206,7 +190,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; unsigned long win_size = dev->win_size; - DEBUG(3, "to = %lu from = %p len = %zd", to, from, len); + pr_debug("to = %lu from = %p len = %zd\n", to, from, len); while(len) { int towrite = win_size - (to & (win_size-1)); caddr_t addr; @@ -218,7 +202,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v if(!addr) return; - DEBUG(4, "memcpy from %p to %p len = %d", from, addr, towrite); + pr_debug("memcpy from %p to %p len = %d\n", from, addr, towrite); memcpy_toio(addr, from, towrite); len -= towrite; to += towrite; @@ -240,7 +224,7 @@ static map_word pcmcia_read8(struct map_info *map, unsigned long ofs) return d; d.x[0] = readb(win_base + ofs); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02lx", + pr_debug("ofs = 0x%08lx (%p) data = 0x%02lx\n", ofs, win_base + ofs, d.x[0]); return d; } @@ -255,7 +239,7 @@ static map_word pcmcia_read16(struct map_info *map, unsigned long ofs) return d; d.x[0] = readw(win_base + ofs); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04lx", + pr_debug("ofs = 0x%08lx (%p) data = 0x%04lx\n", ofs, win_base + ofs, d.x[0]); return d; } @@ -268,7 +252,7 @@ static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, if(DEV_REMOVED(map)) return; - DEBUG(3, "to = %p from = %lu len = %zd", to, from, len); + pr_debug("to = %p from = %lu len = %zd\n", to, from, len); memcpy_fromio(to, win_base + from, len); } @@ -280,7 +264,7 @@ static void pcmcia_write8(struct map_info *map, map_word d, unsigned long adr) if(DEV_REMOVED(map)) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02lx", + pr_debug("adr = 0x%08lx (%p) data = 0x%02lx\n", adr, win_base + adr, d.x[0]); writeb(d.x[0], win_base + adr); } @@ -293,7 +277,7 @@ static void pcmcia_write16(struct map_info *map, map_word d, unsigned long adr) if(DEV_REMOVED(map)) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04lx", + pr_debug("adr = 0x%08lx (%p) data = 0x%04lx\n", adr, win_base + adr, d.x[0]); writew(d.x[0], win_base + adr); } @@ -306,7 +290,7 @@ static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *f if(DEV_REMOVED(map)) return; - DEBUG(3, "to = %lu from = %p len = %zd", to, from, len); + pr_debug("to = %lu from = %p len = %zd\n", to, from, len); memcpy_toio(win_base + to, from, len); } @@ -316,7 +300,7 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on) struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; struct pcmcia_device *link = dev->p_dev; - DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp); + pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp); pcmcia_fixup_vpp(link, on ? dev->vpp : 0); } @@ -325,7 +309,7 @@ static void pcmciamtd_release(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; - DEBUG(3, "link = 0x%p", link); + pr_debug("link = 0x%p\n", link); if (link->resource[2]->end) { if(dev->win_base) { @@ -337,7 +321,6 @@ static void pcmciamtd_release(struct pcmcia_device *link) } -#ifdef CONFIG_MTD_DEBUG static int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev, tuple_t *tuple, void *priv_data) @@ -347,7 +330,7 @@ static int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev, if (!pcmcia_parse_tuple(tuple, &parse)) { cistpl_format_t *t = &parse.format; (void)t; /* Shut up, gcc */ - DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", + pr_debug("Format type: %u, Error Detection: %u, offset = %u, length =%u\n", t->type, t->edc, t->offset, t->length); } return -ENOSPC; @@ -363,12 +346,11 @@ static int pcmciamtd_cistpl_jedec(struct pcmcia_device *p_dev, if (!pcmcia_parse_tuple(tuple, &parse)) { cistpl_jedec_t *t = &parse.jedec; for (i = 0; i < t->nid; i++) - DEBUG(2, "JEDEC: 0x%02x 0x%02x", + pr_debug("JEDEC: 0x%02x 0x%02x\n", t->id[i].mfr, t->id[i].info); } return -ENOSPC; } -#endif static int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev, tuple_t *tuple, @@ -382,14 +364,14 @@ static int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev, if (pcmcia_parse_tuple(tuple, &parse)) return -EINVAL; - DEBUG(2, "Common memory:"); + pr_debug("Common memory:\n"); dev->pcmcia_map.size = t->dev[0].size; /* from here on: DEBUG only */ for (i = 0; i < t->ndev; i++) { - DEBUG(2, "Region %d, type = %u", i, t->dev[i].type); - DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp); - DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed); - DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size); + pr_debug("Region %d, type = %u\n", i, t->dev[i].type); + pr_debug("Region %d, wp = %u\n", i, t->dev[i].wp); + pr_debug("Region %d, speed = %u ns\n", i, t->dev[i].speed); + pr_debug("Region %d, size = %u bytes\n", i, t->dev[i].size); } return 0; } @@ -409,12 +391,12 @@ static int pcmciamtd_cistpl_geo(struct pcmcia_device *p_dev, dev->pcmcia_map.bankwidth = t->geo[0].buswidth; /* from here on: DEBUG only */ for (i = 0; i < t->ngeo; i++) { - DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth); - DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block); - DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block); - DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block); - DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition); - DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave); + pr_debug("region: %d bankwidth = %u\n", i, t->geo[i].buswidth); + pr_debug("region: %d erase_block = %u\n", i, t->geo[i].erase_block); + pr_debug("region: %d read_block = %u\n", i, t->geo[i].read_block); + pr_debug("region: %d write_block = %u\n", i, t->geo[i].write_block); + pr_debug("region: %d partition = %u\n", i, t->geo[i].partition); + pr_debug("region: %d interleave = %u\n", i, t->geo[i].interleave); } return 0; } @@ -432,13 +414,11 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev if (p_dev->prod_id[i]) strcat(dev->mtd_name, p_dev->prod_id[i]); } - DEBUG(2, "Found name: %s", dev->mtd_name); + pr_debug("Found name: %s\n", dev->mtd_name); } -#ifdef CONFIG_MTD_DEBUG pcmcia_loop_tuple(p_dev, CISTPL_FORMAT, pcmciamtd_cistpl_format, NULL); pcmcia_loop_tuple(p_dev, CISTPL_JEDEC_C, pcmciamtd_cistpl_jedec, NULL); -#endif pcmcia_loop_tuple(p_dev, CISTPL_DEVICE, pcmciamtd_cistpl_device, dev); pcmcia_loop_tuple(p_dev, CISTPL_DEVICE_GEO, pcmciamtd_cistpl_geo, dev); @@ -450,12 +430,12 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev if(force_size) { dev->pcmcia_map.size = force_size << 20; - DEBUG(2, "size forced to %dM", force_size); + pr_debug("size forced to %dM\n", force_size); } if(bankwidth) { dev->pcmcia_map.bankwidth = bankwidth; - DEBUG(2, "bankwidth forced to %d", bankwidth); + pr_debug("bankwidth forced to %d\n", bankwidth); } dev->pcmcia_map.name = dev->mtd_name; @@ -464,7 +444,7 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev *new_name = 1; } - DEBUG(1, "Device: Size: %lu Width:%d Name: %s", + pr_debug("Device: Size: %lu Width:%d Name: %s\n", dev->pcmcia_map.size, dev->pcmcia_map.bankwidth << 3, dev->mtd_name); } @@ -479,7 +459,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) static char *probes[] = { "jedec_probe", "cfi_probe" }; int new_name = 0; - DEBUG(3, "link=0x%p", link); + pr_debug("link=0x%p\n", link); card_settings(dev, link, &new_name); @@ -512,11 +492,11 @@ static int pcmciamtd_config(struct pcmcia_device *link) do { int ret; - DEBUG(2, "requesting window with size = %luKiB memspeed = %d", + pr_debug("requesting window with size = %luKiB memspeed = %d\n", (unsigned long) resource_size(link->resource[2]) >> 10, mem_speed); ret = pcmcia_request_window(link, link->resource[2], mem_speed); - DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size); + pr_debug("ret = %d dev->win_size = %d\n", ret, dev->win_size); if(ret) { j++; link->resource[2]->start = 0; @@ -524,21 +504,21 @@ static int pcmciamtd_config(struct pcmcia_device *link) force_size << 20 : MAX_PCMCIA_ADDR; link->resource[2]->end >>= j; } else { - DEBUG(2, "Got window of size %luKiB", (unsigned long) + pr_debug("Got window of size %luKiB\n", (unsigned long) resource_size(link->resource[2]) >> 10); dev->win_size = resource_size(link->resource[2]); break; } } while (link->resource[2]->end >= 0x1000); - DEBUG(2, "dev->win_size = %d", dev->win_size); + pr_debug("dev->win_size = %d\n", dev->win_size); if(!dev->win_size) { dev_err(&dev->p_dev->dev, "Cannot allocate memory window\n"); pcmciamtd_release(link); return -ENODEV; } - DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); + pr_debug("Allocated a window of %dKiB\n", dev->win_size >> 10); /* Get write protect status */ dev->win_base = ioremap(link->resource[2]->start, @@ -549,7 +529,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) pcmciamtd_release(link); return -ENODEV; } - DEBUG(1, "mapped window dev = %p @ %pR, base = %p", + pr_debug("mapped window dev = %p @ %pR, base = %p\n", dev, link->resource[2], dev->win_base); dev->offset = 0; @@ -564,7 +544,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) } link->config_index = 0; - DEBUG(2, "Setting Configuration"); + pr_debug("Setting Configuration\n"); ret = pcmcia_enable_device(link); if (ret != 0) { if (dev->win_base) { @@ -580,17 +560,17 @@ static int pcmciamtd_config(struct pcmcia_device *link) mtd = do_map_probe("map_rom", &dev->pcmcia_map); } else { for(i = 0; i < ARRAY_SIZE(probes); i++) { - DEBUG(1, "Trying %s", probes[i]); + pr_debug("Trying %s\n", probes[i]); mtd = do_map_probe(probes[i], &dev->pcmcia_map); if(mtd) break; - DEBUG(1, "FAILED: %s", probes[i]); + pr_debug("FAILED: %s\n", probes[i]); } } if(!mtd) { - DEBUG(1, "Can not find an MTD"); + pr_debug("Can not find an MTD\n"); pcmciamtd_release(link); return -ENODEV; } @@ -617,7 +597,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) /* If the memory found is fits completely into the mapped PCMCIA window, use the faster non-remapping read/write functions */ if(mtd->size <= dev->win_size) { - DEBUG(1, "Using non remapping memory functions"); + pr_debug("Using non remapping memory functions\n"); dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base; if (dev->pcmcia_map.bankwidth == 1) { dev->pcmcia_map.read = pcmcia_read8; @@ -645,7 +625,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) static int pcmciamtd_suspend(struct pcmcia_device *dev) { - DEBUG(2, "EVENT_PM_RESUME"); + pr_debug("EVENT_PM_RESUME\n"); /* get_lock(link); */ @@ -654,7 +634,7 @@ static int pcmciamtd_suspend(struct pcmcia_device *dev) static int pcmciamtd_resume(struct pcmcia_device *dev) { - DEBUG(2, "EVENT_PM_SUSPEND"); + pr_debug("EVENT_PM_SUSPEND\n"); /* free_lock(link); */ @@ -666,7 +646,7 @@ static void pcmciamtd_detach(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; - DEBUG(3, "link=0x%p", link); + pr_debug("link=0x%p\n", link); if(dev->mtd_info) { mtd_device_unregister(dev->mtd_info); @@ -686,7 +666,7 @@ static int pcmciamtd_probe(struct pcmcia_device *link) /* Create new memory card device */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - DEBUG(1, "dev=0x%p", dev); + pr_debug("dev=0x%p\n", dev); dev->p_dev = link; link->priv = dev; @@ -755,7 +735,7 @@ static int __init init_pcmciamtd(void) static void __exit exit_pcmciamtd(void) { - DEBUG(1, DRIVER_DESC " unloading"); + pr_debug(DRIVER_DESC " unloading"); pcmcia_unregister_driver(&pcmciamtd_driver); } diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index f64cee4a3bfb..66e8200079c2 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -27,8 +27,6 @@ struct physmap_flash_info { struct mtd_info *mtd[MAX_RESOURCES]; struct mtd_info *cmtd; struct map_info map[MAX_RESOURCES]; - int nr_parts; - struct mtd_partition *parts; }; static int physmap_flash_remove(struct platform_device *dev) @@ -46,8 +44,6 @@ static int physmap_flash_remove(struct platform_device *dev) if (info->cmtd) { mtd_device_unregister(info->cmtd); - if (info->nr_parts) - kfree(info->parts); if (info->cmtd != info->mtd[0]) mtd_concat_destroy(info->cmtd); } @@ -175,23 +171,8 @@ static int physmap_flash_probe(struct platform_device *dev) if (err) goto err_out; - err = parse_mtd_partitions(info->cmtd, part_probe_types, - &info->parts, 0); - if (err > 0) { - mtd_device_register(info->cmtd, info->parts, err); - info->nr_parts = err; - return 0; - } - - if (physmap_data->nr_parts) { - printk(KERN_NOTICE "Using physmap partition information\n"); - mtd_device_register(info->cmtd, physmap_data->parts, - physmap_data->nr_parts); - return 0; - } - - mtd_device_register(info->cmtd, NULL, 0); - + mtd_device_parse_register(info->cmtd, part_probe_types, 0, + physmap_data->parts, physmap_data->nr_parts); return 0; err_out: @@ -245,21 +226,6 @@ static struct platform_device physmap_flash = { .num_resources = 1, .resource = &physmap_flash_resource, }; - -void physmap_configure(unsigned long addr, unsigned long size, - int bankwidth, void (*set_vpp)(struct map_info *, int)) -{ - physmap_flash_resource.start = addr; - physmap_flash_resource.end = addr + size - 1; - physmap_flash_data.width = bankwidth; - physmap_flash_data.set_vpp = set_vpp; -} - -void physmap_set_partitions(struct mtd_partition *parts, int num_parts) -{ - physmap_flash_data.nr_parts = num_parts; - physmap_flash_data.parts = parts; -} #endif static int __init physmap_init(void) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index d251d1db129b..7d65f9d3e690 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -34,58 +34,10 @@ struct of_flash_list { struct of_flash { struct mtd_info *cmtd; - struct mtd_partition *parts; int list_size; /* number of elements in of_flash_list */ struct of_flash_list list[0]; }; -#define OF_FLASH_PARTS(info) ((info)->parts) -static int parse_obsolete_partitions(struct platform_device *dev, - struct of_flash *info, - struct device_node *dp) -{ - int i, plen, nr_parts; - const struct { - __be32 offset, len; - } *part; - const char *names; - - part = of_get_property(dp, "partitions", &plen); - if (!part) - return 0; /* No partitions found */ - - dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n"); - - nr_parts = plen / sizeof(part[0]); - - info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL); - if (!info->parts) - return -ENOMEM; - - names = of_get_property(dp, "partition-names", &plen); - - for (i = 0; i < nr_parts; i++) { - info->parts[i].offset = be32_to_cpu(part->offset); - info->parts[i].size = be32_to_cpu(part->len) & ~1; - if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */ - info->parts[i].mask_flags = MTD_WRITEABLE; - - if (names && (plen > 0)) { - int len = strlen(names) + 1; - - info->parts[i].name = (char *)names; - plen -= len; - names += len; - } else { - info->parts[i].name = "unnamed"; - } - - part++; - } - - return nr_parts; -} - static int of_flash_remove(struct platform_device *dev) { struct of_flash *info; @@ -101,11 +53,8 @@ static int of_flash_remove(struct platform_device *dev) mtd_concat_destroy(info->cmtd); } - if (info->cmtd) { - if (OF_FLASH_PARTS(info)) - kfree(OF_FLASH_PARTS(info)); + if (info->cmtd) mtd_device_unregister(info->cmtd); - } for (i = 0; i < info->list_size; i++) { if (info->list[i].mtd) @@ -165,7 +114,8 @@ static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev, specifies the list of partition probers to use. If none is given then the default is use. These take precedence over other device tree information. */ -static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", NULL }; +static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", + "ofpart", "ofoldpart", NULL }; static const char ** __devinit of_get_probes(struct device_node *dp) { const char *cp; @@ -218,6 +168,7 @@ static int __devinit of_flash_probe(struct platform_device *dev) int reg_tuple_size; struct mtd_info **mtd_list = NULL; resource_size_t res_size; + struct mtd_part_parser_data ppdata; match = of_match_device(of_flash_match, &dev->dev); if (!match) @@ -331,29 +282,12 @@ static int __devinit of_flash_probe(struct platform_device *dev) if (err) goto err_out; + ppdata.of_node = dp; part_probe_types = of_get_probes(dp); - err = parse_mtd_partitions(info->cmtd, part_probe_types, - &info->parts, 0); - if (err < 0) { - of_free_probes(part_probe_types); - goto err_out; - } + mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata, + NULL, 0); of_free_probes(part_probe_types); - if (err == 0) { - err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts); - if (err < 0) - goto err_out; - } - - if (err == 0) { - err = parse_obsolete_partitions(dev, info, dp); - if (err < 0) - goto err_out; - } - - mtd_device_register(info->cmtd, info->parts, err); - kfree(mtd_list); return 0; diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 9ca1eccba4bc..94f553489725 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -44,8 +44,6 @@ struct platram_info { struct device *dev; struct mtd_info *mtd; struct map_info map; - struct mtd_partition *partitions; - bool free_partitions; struct resource *area; struct platdata_mtd_ram *pdata; }; @@ -95,10 +93,6 @@ static int platram_remove(struct platform_device *pdev) if (info->mtd) { mtd_device_unregister(info->mtd); - if (info->partitions) { - if (info->free_partitions) - kfree(info->partitions); - } map_destroy(info->mtd); } @@ -228,21 +222,8 @@ static int platram_probe(struct platform_device *pdev) /* check to see if there are any available partitions, or wether * to add this device whole */ - if (!pdata->nr_partitions) { - /* try to probe using the supplied probe type */ - if (pdata->probes) { - err = parse_mtd_partitions(info->mtd, pdata->probes, - &info->partitions, 0); - info->free_partitions = 1; - if (err > 0) - err = mtd_device_register(info->mtd, - info->partitions, err); - } - } - /* use the static mapping */ - else - err = mtd_device_register(info->mtd, pdata->partitions, - pdata->nr_partitions); + err = mtd_device_parse_register(info->mtd, pdata->probes, 0, + pdata->partitions, pdata->nr_partitions); if (!err) dev_info(&pdev->dev, "registered mtd device\n"); diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 7ae137d4b998..411a17df9fc1 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -41,8 +41,6 @@ static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from, } struct pxa2xx_flash_info { - struct mtd_partition *parts; - int nr_parts; struct mtd_info *mtd; struct map_info map; }; @@ -55,9 +53,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) { struct flash_platform_data *flash = pdev->dev.platform_data; struct pxa2xx_flash_info *info; - struct mtd_partition *parts; struct resource *res; - int ret = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -71,8 +67,6 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) info->map.bankwidth = flash->width; info->map.phys = res->start; info->map.size = resource_size(res); - info->parts = flash->parts; - info->nr_parts = flash->nr_parts; info->map.virt = ioremap(info->map.phys, info->map.size); if (!info->map.virt) { @@ -104,18 +98,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) } info->mtd->owner = THIS_MODULE; - ret = parse_mtd_partitions(info->mtd, probes, &parts, 0); - - if (ret > 0) { - info->nr_parts = ret; - info->parts = parts; - } - - if (!info->nr_parts) - printk("Registering %s as whole device\n", - info->map.name); - - mtd_device_register(info->mtd, info->parts, info->nr_parts); + mtd_device_parse_register(info->mtd, probes, 0, NULL, 0); platform_set_drvdata(pdev, info); return 0; @@ -133,7 +116,6 @@ static int __devexit pxa2xx_flash_remove(struct platform_device *dev) iounmap(info->map.virt); if (info->map.cached) iounmap(info->map.cached); - kfree(info->parts); kfree(info); return 0; } diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c index 761fb459d2c7..0237f197fd12 100644 --- a/drivers/mtd/maps/rbtx4939-flash.c +++ b/drivers/mtd/maps/rbtx4939-flash.c @@ -25,8 +25,6 @@ struct rbtx4939_flash_info { struct mtd_info *mtd; struct map_info map; - int nr_parts; - struct mtd_partition *parts; }; static int rbtx4939_flash_remove(struct platform_device *dev) @@ -41,8 +39,6 @@ static int rbtx4939_flash_remove(struct platform_device *dev) if (info->mtd) { struct rbtx4939_flash_data *pdata = dev->dev.platform_data; - if (info->nr_parts) - kfree(info->parts); mtd_device_unregister(info->mtd); map_destroy(info->mtd); } @@ -50,7 +46,6 @@ static int rbtx4939_flash_remove(struct platform_device *dev) } static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; -static const char *part_probe_types[] = { "cmdlinepart", NULL }; static int rbtx4939_flash_probe(struct platform_device *dev) { @@ -107,22 +102,11 @@ static int rbtx4939_flash_probe(struct platform_device *dev) info->mtd->owner = THIS_MODULE; if (err) goto err_out; + err = mtd_device_parse_register(info->mtd, NULL, 0, + pdata->parts, pdata->nr_parts); - err = parse_mtd_partitions(info->mtd, part_probe_types, - &info->parts, 0); - if (err > 0) { - mtd_device_register(info->mtd, info->parts, err); - info->nr_parts = err; - return 0; - } - - if (pdata->nr_parts) { - pr_notice("Using rbtx4939 partition information\n"); - mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); - return 0; - } - - mtd_device_register(info->mtd, NULL, 0); + if (err) + goto err_out; return 0; err_out: diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index a9b5e0e5c4c5..fa9c0a9670cd 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -131,10 +131,8 @@ struct sa_subdev_info { }; struct sa_info { - struct mtd_partition *parts; struct mtd_info *mtd; int num_subdev; - unsigned int nr_parts; struct sa_subdev_info subdev[0]; }; @@ -231,8 +229,6 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla mtd_concat_destroy(info->mtd); } - kfree(info->parts); - for (i = info->num_subdev - 1; i >= 0; i--) sa1100_destroy_subdev(&info->subdev[i]); kfree(info); @@ -341,10 +337,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static int __devinit sa1100_mtd_probe(struct platform_device *pdev) { struct flash_platform_data *plat = pdev->dev.platform_data; - struct mtd_partition *parts; - const char *part_type = NULL; struct sa_info *info; - int err, nr_parts = 0; + int err; if (!plat) return -ENODEV; @@ -358,26 +352,8 @@ static int __devinit sa1100_mtd_probe(struct platform_device *pdev) /* * Partition selection stuff. */ - nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0); - if (nr_parts > 0) { - info->parts = parts; - part_type = "dynamic"; - } else { - parts = plat->parts; - nr_parts = plat->nr_parts; - part_type = "static"; - } - - if (nr_parts == 0) - printk(KERN_NOTICE "SA1100 flash: no partition info " - "available, registering whole flash\n"); - else - printk(KERN_NOTICE "SA1100 flash: using %s partition " - "definition\n", part_type); - - mtd_device_register(info->mtd, parts, nr_parts); - - info->nr_parts = nr_parts; + mtd_device_parse_register(info->mtd, part_probes, 0, + plat->parts, plat->nr_parts); platform_set_drvdata(pdev, info); err = 0; diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index cbf6bade9354..496c40704aff 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -19,8 +19,6 @@ static struct mtd_info *flash_mtd; static struct mtd_info *eprom_mtd; -static struct mtd_partition *parsed_parts; - struct map_info soleng_eprom_map = { .name = "Solution Engine EPROM", .size = 0x400000, @@ -51,12 +49,14 @@ static struct mtd_partition superh_se_partitions[] = { .size = MTDPART_SIZ_FULL, } }; +#define NUM_PARTITIONS ARRAY_SIZE(superh_se_partitions) +#else +#define superh_se_partitions NULL +#define NUM_PARTITIONS 0 #endif /* CONFIG_MTD_SUPERH_RESERVE */ static int __init init_soleng_maps(void) { - int nr_parts = 0; - /* First probe at offset 0 */ soleng_flash_map.phys = 0; soleng_flash_map.virt = (void __iomem *)P2SEGADDR(0); @@ -92,21 +92,8 @@ static int __init init_soleng_maps(void) mtd_device_register(eprom_mtd, NULL, 0); } - nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); - -#ifdef CONFIG_MTD_SUPERH_RESERVE - if (nr_parts <= 0) { - printk(KERN_NOTICE "Using configured partition at 0x%08x.\n", - CONFIG_MTD_SUPERH_RESERVE); - parsed_parts = superh_se_partitions; - nr_parts = sizeof(superh_se_partitions)/sizeof(*parsed_parts); - } -#endif /* CONFIG_MTD_SUPERH_RESERVE */ - - if (nr_parts > 0) - mtd_device_register(flash_mtd, parsed_parts, nr_parts); - else - mtd_device_register(flash_mtd, NULL, 0); + mtd_device_parse_register(flash_mtd, probes, 0, + superh_se_partitions, NUM_PARTITIONS); return 0; } @@ -118,10 +105,7 @@ static void __exit cleanup_soleng_maps(void) map_destroy(eprom_mtd); } - if (parsed_parts) - mtd_device_unregister(flash_mtd); - else - mtd_device_unregister(flash_mtd); + mtd_device_unregister(flash_mtd); map_destroy(flash_mtd); } diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index 901ce968efae..aa7e0cb2893c 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -20,7 +20,6 @@ #include <asm/immap_cpm2.h> static struct mtd_info *sbcmtd[3]; -static struct mtd_partition *sbcmtd_parts[3]; struct map_info sbc82xx_flash_map[3] = { {.name = "Boot flash"}, @@ -101,6 +100,7 @@ static int __init init_sbc82xx_flash(void) for (i=0; i<3; i++) { int8_t flashcs[3] = { 0, 6, 1 }; int nr_parts; + struct mtd_partition *defparts; printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d", sbc82xx_flash_map[i].name, @@ -113,7 +113,8 @@ static int __init init_sbc82xx_flash(void) } printk(" at %08lx)\n", sbc82xx_flash_map[i].phys); - sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size); + sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, + sbc82xx_flash_map[i].size); if (!sbc82xx_flash_map[i].virt) { printk("Failed to ioremap\n"); @@ -129,24 +130,20 @@ static int __init init_sbc82xx_flash(void) sbcmtd[i]->owner = THIS_MODULE; - nr_parts = parse_mtd_partitions(sbcmtd[i], part_probes, - &sbcmtd_parts[i], 0); - if (nr_parts > 0) { - mtd_device_register(sbcmtd[i], sbcmtd_parts[i], - nr_parts); - continue; - } - /* No partitioning detected. Use default */ if (i == 2) { - mtd_device_register(sbcmtd[i], NULL, 0); + defparts = NULL; + nr_parts = 0; } else if (i == bigflash) { - mtd_device_register(sbcmtd[i], bigflash_parts, - ARRAY_SIZE(bigflash_parts)); + defparts = bigflash_parts; + nr_parts = ARRAY_SIZE(bigflash_parts); } else { - mtd_device_register(sbcmtd[i], smallflash_parts, - ARRAY_SIZE(smallflash_parts)); + defparts = smallflash_parts; + nr_parts = ARRAY_SIZE(smallflash_parts); } + + mtd_device_parse_register(sbcmtd[i], part_probes, 0, + defparts, nr_parts); } return 0; } @@ -159,12 +156,8 @@ static void __exit cleanup_sbc82xx_flash(void) if (!sbcmtd[i]) continue; - if (i<2 || sbcmtd_parts[i]) - mtd_device_unregister(sbcmtd[i]); - else - mtd_device_unregister(sbcmtd[i]); + mtd_device_unregister(sbcmtd[i]); - kfree(sbcmtd_parts[i]); map_destroy(sbcmtd[i]); iounmap((void *)sbc82xx_flash_map[i].virt); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index ca385697446e..ed8b5e744b12 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -426,6 +426,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) new->rq->queuedata = new; blk_queue_logical_block_size(new->rq, tr->blksize); + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, new->rq); + if (tr->discard) { queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, new->rq); new->rq->limits.max_discard_sectors = UINT_MAX; diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 3326615ad66b..7c1dc908a174 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -44,7 +44,7 @@ struct mtdblk_dev { enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state; }; -static struct mutex mtdblks_lock; +static DEFINE_MUTEX(mtdblks_lock); /* * Cache stuff... @@ -119,7 +119,7 @@ static int write_cached_data (struct mtdblk_dev *mtdblk) if (mtdblk->cache_state != STATE_DIRTY) return 0; - DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" " + pr_debug("mtdblock: writing cached data for \"%s\" " "at 0x%lx, size 0x%x\n", mtd->name, mtdblk->cache_offset, mtdblk->cache_size); @@ -148,7 +148,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, size_t retlen; int ret; - DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", + pr_debug("mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); if (!sect_size) @@ -218,7 +218,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, size_t retlen; int ret; - DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", + pr_debug("mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); if (!sect_size) @@ -283,7 +283,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) { struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); - DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); + pr_debug("mtdblock_open\n"); mutex_lock(&mtdblks_lock); if (mtdblk->count) { @@ -303,7 +303,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) mutex_unlock(&mtdblks_lock); - DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + pr_debug("ok\n"); return 0; } @@ -312,7 +312,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) { struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); - DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); + pr_debug("mtdblock_release\n"); mutex_lock(&mtdblks_lock); @@ -329,7 +329,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) mutex_unlock(&mtdblks_lock); - DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + pr_debug("ok\n"); return 0; } @@ -389,8 +389,6 @@ static struct mtd_blktrans_ops mtdblock_tr = { static int __init init_mtdblock(void) { - mutex_init(&mtdblks_lock); - return register_mtd_blktrans(&mtdblock_tr); } diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index 795a8c0a05b8..0470a6e86309 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/blktrans.h> +#include <linux/module.h> static int mtdblock_readsect(struct mtd_blktrans_dev *dev, unsigned long block, char *buf) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 61086ea3cc6b..e7dc732ddabc 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -43,7 +43,7 @@ static struct vfsmount *mtd_inode_mnt __read_mostly; /* * Data structure to hold the pointer to the mtd device as well - * as mode information ofr various use cases. + * as mode information of various use cases. */ struct mtd_file_info { struct mtd_info *mtd; @@ -86,7 +86,7 @@ static int mtd_open(struct inode *inode, struct file *file) struct mtd_file_info *mfi; struct inode *mtd_ino; - DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); + pr_debug("MTD_open\n"); /* You can't open the RO devices RW */ if ((file->f_mode & FMODE_WRITE) && (minor & 1)) @@ -151,7 +151,7 @@ static int mtd_close(struct inode *inode, struct file *file) struct mtd_file_info *mfi = file->private_data; struct mtd_info *mtd = mfi->mtd; - DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); + pr_debug("MTD_close\n"); /* Only sync if opened RW */ if ((file->f_mode & FMODE_WRITE) && mtd->sync) @@ -195,7 +195,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t size_t size = count; char *kbuf; - DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); + pr_debug("MTD_read\n"); if (*ppos + count > mtd->size) count = mtd->size - *ppos; @@ -211,17 +211,17 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t len = min_t(size_t, count, size); switch (mfi->mode) { - case MTD_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_FACTORY: ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); break; - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_USER: ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); break; - case MTD_MODE_RAW: + case MTD_FILE_MODE_RAW: { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.datbuf = kbuf; ops.oobbuf = NULL; ops.len = len; @@ -233,16 +233,16 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t default: ret = mtd->read(mtd, *ppos, len, &retlen, kbuf); } - /* Nand returns -EBADMSG on ecc errors, but it returns + /* Nand returns -EBADMSG on ECC errors, but it returns * the data. For our userspace tools it is important - * to dump areas with ecc errors ! + * to dump areas with ECC errors! * For kernel internal usage it also might return -EUCLEAN * to signal the caller that a bitflip has occurred and has * been corrected by the ECC algorithm. * Userspace software which accesses NAND this way * must be aware of the fact that it deals with NAND */ - if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) { + if (!ret || mtd_is_bitflip_or_eccerr(ret)) { *ppos += retlen; if (copy_to_user(buf, kbuf, retlen)) { kfree(kbuf); @@ -278,7 +278,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count int ret=0; int len; - DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); + pr_debug("MTD_write\n"); if (*ppos == mtd->size) return -ENOSPC; @@ -302,10 +302,10 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count } switch (mfi->mode) { - case MTD_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_FACTORY: ret = -EROFS; break; - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_USER: if (!mtd->write_user_prot_reg) { ret = -EOPNOTSUPP; break; @@ -313,13 +313,14 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); break; - case MTD_MODE_RAW: + case MTD_FILE_MODE_RAW: { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.datbuf = kbuf; ops.oobbuf = NULL; + ops.ooboffs = 0; ops.len = len; ret = mtd->write_oob(mtd, *ppos, &ops); @@ -367,13 +368,13 @@ static int otp_select_filemode(struct mtd_file_info *mfi, int mode) if (!mtd->read_fact_prot_reg) ret = -EOPNOTSUPP; else - mfi->mode = MTD_MODE_OTP_FACTORY; + mfi->mode = MTD_FILE_MODE_OTP_FACTORY; break; case MTD_OTP_USER: if (!mtd->read_fact_prot_reg) ret = -EOPNOTSUPP; else - mfi->mode = MTD_MODE_OTP_USER; + mfi->mode = MTD_FILE_MODE_OTP_USER; break; default: ret = -EINVAL; @@ -390,6 +391,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, uint64_t start, uint32_t length, void __user *ptr, uint32_t __user *retp) { + struct mtd_file_info *mfi = file->private_data; struct mtd_oob_ops ops; uint32_t retlen; int ret = 0; @@ -409,9 +411,10 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, return ret; ops.ooblen = length; - ops.ooboffs = start & (mtd->oobsize - 1); + ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = (mfi->mode == MTD_FILE_MODE_RAW) ? MTD_OPS_RAW : + MTD_OPS_PLACE_OOB; if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; @@ -420,7 +423,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, if (IS_ERR(ops.oobbuf)) return PTR_ERR(ops.oobbuf); - start &= ~((uint64_t)mtd->oobsize - 1); + start &= ~((uint64_t)mtd->writesize - 1); ret = mtd->write_oob(mtd, start, &ops); if (ops.oobretlen > 0xFFFFFFFFU) @@ -433,9 +436,11 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, return ret; } -static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, - uint32_t length, void __user *ptr, uint32_t __user *retp) +static int mtd_do_readoob(struct file *file, struct mtd_info *mtd, + uint64_t start, uint32_t length, void __user *ptr, + uint32_t __user *retp) { + struct mtd_file_info *mfi = file->private_data; struct mtd_oob_ops ops; int ret = 0; @@ -451,9 +456,10 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, return ret; ops.ooblen = length; - ops.ooboffs = start & (mtd->oobsize - 1); + ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = (mfi->mode == MTD_FILE_MODE_RAW) ? MTD_OPS_RAW : + MTD_OPS_PLACE_OOB; if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; @@ -462,7 +468,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, if (!ops.oobbuf) return -ENOMEM; - start &= ~((uint64_t)mtd->oobsize - 1); + start &= ~((uint64_t)mtd->writesize - 1); ret = mtd->read_oob(mtd, start, &ops); if (put_user(ops.oobretlen, retp)) @@ -472,13 +478,29 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, ret = -EFAULT; kfree(ops.oobbuf); + + /* + * NAND returns -EBADMSG on ECC errors, but it returns the OOB + * data. For our userspace tools it is important to dump areas + * with ECC errors! + * For kernel internal usage it also might return -EUCLEAN + * to signal the caller that a bitflip has occured and has + * been corrected by the ECC algorithm. + * + * Note: currently the standard NAND function, nand_read_oob_std, + * does not calculate ECC for the OOB area, so do not rely on + * this behavior unless you have replaced it with your own. + */ + if (mtd_is_bitflip_or_eccerr(ret)) + return 0; + return ret; } /* * Copies (and truncates, if necessary) data from the larger struct, * nand_ecclayout, to the smaller, deprecated layout struct, - * nand_ecclayout_user. This is necessary only to suppport the deprecated + * nand_ecclayout_user. This is necessary only to support the deprecated * API ioctl ECCGETLAYOUT while allowing all new functionality to use * nand_ecclayout flexibly (i.e. the struct may change size in new * releases without requiring major rewrites). @@ -544,6 +566,55 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, } } +static int mtd_write_ioctl(struct mtd_info *mtd, + struct mtd_write_req __user *argp) +{ + struct mtd_write_req req; + struct mtd_oob_ops ops; + void __user *usr_data, *usr_oob; + int ret; + + if (copy_from_user(&req, argp, sizeof(req)) || + !access_ok(VERIFY_READ, req.usr_data, req.len) || + !access_ok(VERIFY_READ, req.usr_oob, req.ooblen)) + return -EFAULT; + if (!mtd->write_oob) + return -EOPNOTSUPP; + + ops.mode = req.mode; + ops.len = (size_t)req.len; + ops.ooblen = (size_t)req.ooblen; + ops.ooboffs = 0; + + usr_data = (void __user *)(uintptr_t)req.usr_data; + usr_oob = (void __user *)(uintptr_t)req.usr_oob; + + if (req.usr_data) { + ops.datbuf = memdup_user(usr_data, ops.len); + if (IS_ERR(ops.datbuf)) + return PTR_ERR(ops.datbuf); + } else { + ops.datbuf = NULL; + } + + if (req.usr_oob) { + ops.oobbuf = memdup_user(usr_oob, ops.ooblen); + if (IS_ERR(ops.oobbuf)) { + kfree(ops.datbuf); + return PTR_ERR(ops.oobbuf); + } + } else { + ops.oobbuf = NULL; + } + + ret = mtd->write_oob(mtd, (loff_t)req.start, &ops); + + kfree(ops.datbuf); + kfree(ops.oobbuf); + + return ret; +} + static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) { struct mtd_file_info *mfi = file->private_data; @@ -553,7 +624,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) u_long size; struct mtd_info_user info; - DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); + pr_debug("MTD_ioctl\n"); size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; if (cmd & IOC_IN) { @@ -601,8 +672,8 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) info.erasesize = mtd->erasesize; info.writesize = mtd->writesize; info.oobsize = mtd->oobsize; - /* The below fields are obsolete */ - info.ecctype = -1; + /* The below field is obsolete */ + info.padding = 0; if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) return -EFAULT; break; @@ -698,7 +769,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; else - ret = mtd_do_readoob(mtd, buf.start, buf.length, + ret = mtd_do_readoob(file, mtd, buf.start, buf.length, buf.ptr, &buf_user->start); break; } @@ -725,12 +796,19 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; else - ret = mtd_do_readoob(mtd, buf.start, buf.length, + ret = mtd_do_readoob(file, mtd, buf.start, buf.length, (void __user *)(uintptr_t)buf.usr_ptr, &buf_user->length); break; } + case MEMWRITE: + { + ret = mtd_write_ioctl(mtd, + (struct mtd_write_req __user *)arg); + break; + } + case MEMLOCK: { struct erase_info_user einfo; @@ -827,7 +905,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) if (copy_from_user(&mode, argp, sizeof(int))) return -EFAULT; - mfi->mode = MTD_MODE_NORMAL; + mfi->mode = MTD_FILE_MODE_NORMAL; ret = otp_select_filemode(mfi, mode); @@ -843,11 +921,11 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) return -ENOMEM; ret = -EOPNOTSUPP; switch (mfi->mode) { - case MTD_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_FACTORY: if (mtd->get_fact_prot_info) ret = mtd->get_fact_prot_info(mtd, buf, 4096); break; - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_USER: if (mtd->get_user_prot_info) ret = mtd->get_user_prot_info(mtd, buf, 4096); break; @@ -871,7 +949,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) { struct otp_info oinfo; - if (mfi->mode != MTD_MODE_OTP_USER) + if (mfi->mode != MTD_FILE_MODE_OTP_USER) return -EINVAL; if (copy_from_user(&oinfo, argp, sizeof(oinfo))) return -EFAULT; @@ -882,7 +960,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) } #endif - /* This ioctl is being deprecated - it truncates the ecc layout */ + /* This ioctl is being deprecated - it truncates the ECC layout */ case ECCGETLAYOUT: { struct nand_ecclayout_user *usrlay; @@ -915,17 +993,17 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) mfi->mode = 0; switch(arg) { - case MTD_MODE_OTP_FACTORY: - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_USER: ret = otp_select_filemode(mfi, arg); break; - case MTD_MODE_RAW: + case MTD_FILE_MODE_RAW: if (!mtd->read_oob || !mtd->write_oob) return -EOPNOTSUPP; mfi->mode = arg; - case MTD_MODE_NORMAL: + case MTD_FILE_MODE_NORMAL: break; default: ret = -EINVAL; @@ -1011,7 +1089,7 @@ static long mtd_compat_ioctl(struct file *file, unsigned int cmd, if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; else - ret = mtd_do_readoob(mtd, buf.start, + ret = mtd_do_readoob(file, mtd, buf.start, buf.length, compat_ptr(buf.ptr), &buf_user->start); break; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index e601672a5305..6df4d4d4eb92 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -95,10 +95,10 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len, /* Save information about bitflips! */ if (unlikely(err)) { - if (err == -EBADMSG) { + if (mtd_is_eccerr(err)) { mtd->ecc_stats.failed++; ret = err; - } else if (err == -EUCLEAN) { + } else if (mtd_is_bitflip(err)) { mtd->ecc_stats.corrected++; /* Do not overwrite -EBADMSG !! */ if (!ret) @@ -279,10 +279,10 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) /* Save information about bitflips! */ if (unlikely(err)) { - if (err == -EBADMSG) { + if (mtd_is_eccerr(err)) { mtd->ecc_stats.failed++; ret = err; - } else if (err == -EUCLEAN) { + } else if (mtd_is_bitflip(err)) { mtd->ecc_stats.corrected++; /* Do not overwrite -EBADMSG !! */ if (!ret) @@ -770,7 +770,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c /* * Set up the new "super" device's MTD object structure, check for - * incompatibilites between the subdevices. + * incompatibilities between the subdevices. */ concat->mtd.type = subdev[0]->type; concat->mtd.flags = subdev[0]->flags; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c510aff289a8..b01993ea260e 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -362,7 +362,7 @@ int add_mtd_device(struct mtd_info *mtd) MTD_DEVT(i) + 1, NULL, "mtd%dro", i); - DEBUG(0, "mtd: Giving out device %d to %s\n", i, mtd->name); + pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name); /* No need to get a refcount on the module containing the notifier, since we hold the mtd_table_mutex */ list_for_each_entry(not, &mtd_notifiers, list) @@ -429,27 +429,63 @@ out_error: } /** - * mtd_device_register - register an MTD device. + * mtd_device_parse_register - parse partitions and register an MTD device. * - * @master: the MTD device to register - * @parts: the partitions to register - only valid if nr_parts > 0 - * @nr_parts: the number of partitions in parts. If zero then the full MTD - * device is registered + * @mtd: the MTD device to register + * @types: the list of MTD partition probes to try, see + * 'parse_mtd_partitions()' for more information + * @parser_data: MTD partition parser-specific data + * @parts: fallback partition information to register, if parsing fails; + * only valid if %nr_parts > %0 + * @nr_parts: the number of partitions in parts, if zero then the full + * MTD device is registered if no partition info is found * - * Register an MTD device with the system and optionally, a number of - * partitions. If nr_parts is 0 then the whole device is registered, otherwise - * only the partitions are registered. To register both the full device *and* - * the partitions, call mtd_device_register() twice, once with nr_parts == 0 - * and once equal to the number of partitions. + * This function aggregates MTD partitions parsing (done by + * 'parse_mtd_partitions()') and MTD device and partitions registering. It + * basically follows the most common pattern found in many MTD drivers: + * + * * It first tries to probe partitions on MTD device @mtd using parsers + * specified in @types (if @types is %NULL, then the default list of parsers + * is used, see 'parse_mtd_partitions()' for more information). If none are + * found this functions tries to fallback to information specified in + * @parts/@nr_parts. + * * If any partitioning info was found, this function registers the found + * partitions. + * * If no partitions were found this function just registers the MTD device + * @mtd and exits. + * + * Returns zero in case of success and a negative error code in case of failure. */ -int mtd_device_register(struct mtd_info *master, - const struct mtd_partition *parts, - int nr_parts) +int mtd_device_parse_register(struct mtd_info *mtd, const char **types, + struct mtd_part_parser_data *parser_data, + const struct mtd_partition *parts, + int nr_parts) { - return parts ? add_mtd_partitions(master, parts, nr_parts) : - add_mtd_device(master); + int err; + struct mtd_partition *real_parts; + + err = parse_mtd_partitions(mtd, types, &real_parts, parser_data); + if (err <= 0 && nr_parts && parts) { + real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, + GFP_KERNEL); + if (!real_parts) + err = -ENOMEM; + else + err = nr_parts; + } + + if (err > 0) { + err = add_mtd_partitions(mtd, real_parts, err); + kfree(real_parts); + } else if (err == 0) { + err = add_mtd_device(mtd); + if (err == 1) + err = -ENODEV; + } + + return err; } -EXPORT_SYMBOL_GPL(mtd_device_register); +EXPORT_SYMBOL_GPL(mtd_device_parse_register); /** * mtd_device_unregister - unregister an existing MTD device. diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h index 0ed6126b4c1f..961a38408542 100644 --- a/drivers/mtd/mtdcore.h +++ b/drivers/mtd/mtdcore.h @@ -15,6 +15,9 @@ extern int del_mtd_device(struct mtd_info *mtd); extern int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); extern int del_mtd_partitions(struct mtd_info *); +extern int parse_mtd_partitions(struct mtd_info *master, const char **types, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data); #define mtd_for_each_device(mtd) \ for ((mtd) = __mtd_next_device(0); \ diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index e3e40f440323..1e2fa6236705 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -258,7 +258,7 @@ static void find_next_position(struct mtdoops_context *cxt) ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE, &retlen, (u_char *) &count[0]); if (retlen != MTDOOPS_HEADER_SIZE || - (ret < 0 && ret != -EUCLEAN)) { + (ret < 0 && !mtd_is_bitflip(ret))) { printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n", page * record_size, retlen, MTDOOPS_HEADER_SIZE, ret); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 630be3e7da04..a0bd2de4752b 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -73,9 +73,9 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len, res = part->master->read(part->master, from + part->offset, len, retlen, buf); if (unlikely(res)) { - if (res == -EUCLEAN) + if (mtd_is_bitflip(res)) mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; - if (res == -EBADMSG) + if (mtd_is_eccerr(res)) mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed; } return res; @@ -130,7 +130,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, if (ops->oobbuf) { size_t len, pages; - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) len = mtd->oobavail; else len = mtd->oobsize; @@ -142,9 +142,9 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, res = part->master->read_oob(part->master, from + part->offset, ops); if (unlikely(res)) { - if (res == -EUCLEAN) + if (mtd_is_bitflip(res)) mtd->ecc_stats.corrected++; - if (res == -EBADMSG) + if (mtd_is_eccerr(res)) mtd->ecc_stats.failed++; } return res; @@ -479,6 +479,19 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, (unsigned long long)cur_offset, (unsigned long long)slave->offset); } } + if (slave->offset == MTDPART_OFS_RETAIN) { + slave->offset = cur_offset; + if (master->size - slave->offset >= slave->mtd.size) { + slave->mtd.size = master->size - slave->offset + - slave->mtd.size; + } else { + printk(KERN_ERR "mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n", + part->name, master->size - slave->offset, + slave->mtd.size); + /* register to preserve ordering */ + goto out_register; + } + } if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; @@ -693,6 +706,8 @@ static struct mtd_part_parser *get_partition_parser(const char *name) return ret; } +#define put_partition_parser(p) do { module_put((p)->owner); } while (0) + int register_mtd_parser(struct mtd_part_parser *p) { spin_lock(&part_parser_lock); @@ -712,19 +727,51 @@ int deregister_mtd_parser(struct mtd_part_parser *p) } EXPORT_SYMBOL_GPL(deregister_mtd_parser); +/* + * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you + * are changing this array! + */ +static const char *default_mtd_part_types[] = { + "cmdlinepart", + "ofpart", + NULL +}; + +/** + * parse_mtd_partitions - parse MTD partitions + * @master: the master partition (describes whole MTD device) + * @types: names of partition parsers to try or %NULL + * @pparts: array of partitions found is returned here + * @data: MTD partition parser-specific data + * + * This function tries to find partition on MTD device @master. It uses MTD + * partition parsers, specified in @types. However, if @types is %NULL, then + * the default list of parsers is used. The default list contains only the + * "cmdlinepart" and "ofpart" parsers ATM. + * + * This function may return: + * o a negative error code in case of failure + * o zero if no partitions were found + * o a positive number of found partitions, in which case on exit @pparts will + * point to an array containing this number of &struct mtd_info objects. + */ int parse_mtd_partitions(struct mtd_info *master, const char **types, - struct mtd_partition **pparts, unsigned long origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { struct mtd_part_parser *parser; int ret = 0; + if (!types) + types = default_mtd_part_types; + for ( ; ret <= 0 && *types; types++) { parser = get_partition_parser(*types); if (!parser && !request_module("%s", *types)) parser = get_partition_parser(*types); if (!parser) continue; - ret = (*parser->parse_fn)(master, pparts, origin); + ret = (*parser->parse_fn)(master, pparts, data); if (ret > 0) { printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", ret, parser->name, master->name); @@ -733,7 +780,6 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, } return ret; } -EXPORT_SYMBOL_GPL(parse_mtd_partitions); int mtd_is_partition(struct mtd_info *mtd) { diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 16b02a1fc100..a90bfe79916d 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -14,6 +14,7 @@ #include <linux/mtd/super.h> #include <linux/namei.h> +#include <linux/export.h> #include <linux/ctype.h> #include <linux/slab.h> @@ -26,12 +27,12 @@ static int get_sb_mtd_compare(struct super_block *sb, void *_mtd) struct mtd_info *mtd = _mtd; if (sb->s_mtd == mtd) { - DEBUG(2, "MTDSB: Match on device %d (\"%s\")\n", + pr_debug("MTDSB: Match on device %d (\"%s\")\n", mtd->index, mtd->name); return 1; } - DEBUG(2, "MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", + pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name); return 0; } @@ -70,7 +71,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags, goto already_mounted; /* fresh new superblock */ - DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n", + pr_debug("MTDSB: New superblock for device %d (\"%s\")\n", mtd->index, mtd->name); sb->s_flags = flags; @@ -87,7 +88,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags, /* new mountpoint for an already mounted superblock */ already_mounted: - DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n", + pr_debug("MTDSB: Device %d (\"%s\") is already mounted\n", mtd->index, mtd->name); put_mtd_device(mtd); return dget(sb->s_root); @@ -108,7 +109,7 @@ static struct dentry *mount_mtd_nr(struct file_system_type *fs_type, int flags, mtd = get_mtd_device(NULL, mtdnr); if (IS_ERR(mtd)) { - DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr); + pr_debug("MTDSB: Device #%u doesn't appear to exist\n", mtdnr); return ERR_CAST(mtd); } @@ -131,7 +132,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, if (!dev_name) return ERR_PTR(-EINVAL); - DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name); + pr_debug("MTDSB: dev_name \"%s\"\n", dev_name); /* the preferred way of mounting in future; especially when * CONFIG_BLOCK=n - we specify the underlying MTD device by number or @@ -142,7 +143,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, struct mtd_info *mtd; /* mount by MTD device name */ - DEBUG(1, "MTDSB: mtd:%%s, name \"%s\"\n", + pr_debug("MTDSB: mtd:%%s, name \"%s\"\n", dev_name + 4); mtd = get_mtd_device_nm(dev_name + 4); @@ -163,7 +164,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, mtdnr = simple_strtoul(dev_name + 3, &endptr, 0); if (!*endptr) { /* It was a valid number */ - DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n", + pr_debug("MTDSB: mtd%%d, mtdnr %d\n", mtdnr); return mount_mtd_nr(fs_type, flags, dev_name, data, @@ -179,10 +180,10 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, bdev = lookup_bdev(dev_name); if (IS_ERR(bdev)) { ret = PTR_ERR(bdev); - DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret); + pr_debug("MTDSB: lookup_bdev() returned %d\n", ret); return ERR_PTR(ret); } - DEBUG(1, "MTDSB: lookup_bdev() returned 0\n"); + pr_debug("MTDSB: lookup_bdev() returned 0\n"); ret = -EINVAL; diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index fd7885327611..bd9590c723e4 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -86,7 +86,7 @@ struct swap_eb { unsigned int flags; unsigned int active_count; unsigned int erase_count; - unsigned int pad; /* speeds up pointer decremtnt */ + unsigned int pad; /* speeds up pointer decrement */ }; #define MTDSWAP_ECNT_MIN(rbroot) (rb_entry(rb_first(rbroot), struct swap_eb, \ @@ -314,7 +314,7 @@ static int mtdswap_read_oob(struct mtdswap_dev *d, loff_t from, { int ret = d->mtd->read_oob(d->mtd, from, ops); - if (ret == -EUCLEAN) + if (mtd_is_bitflip(ret)) return ret; if (ret) { @@ -350,11 +350,11 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) ops.oobbuf = d->oob_buf; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ret = mtdswap_read_oob(d, offset, &ops); - if (ret && ret != -EUCLEAN) + if (ret && !mtd_is_bitflip(ret)) return ret; data = (struct mtdswap_oobdata *)d->oob_buf; @@ -363,7 +363,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) { eb->erase_count = le32_to_cpu(data->count); - if (ret == -EUCLEAN) + if (mtd_is_bitflip(ret)) ret = MTDSWAP_SCANNED_BITFLIP; else { if (le16_to_cpu(data2->magic) == MTDSWAP_MAGIC_DIRTY) @@ -389,7 +389,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb, ops.ooboffs = 0; ops.oobbuf = (uint8_t *)&n; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = NULL; if (marker == MTDSWAP_TYPE_CLEAN) { @@ -408,7 +408,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb, if (ret) { dev_warn(d->dev, "Write OOB failed for block at %08llx " "error %d\n", offset, ret); - if (ret == -EIO || ret == -EBADMSG) + if (ret == -EIO || mtd_is_eccerr(ret)) mtdswap_handle_write_error(d, eb); return ret; } @@ -628,7 +628,7 @@ static int mtdswap_map_free_block(struct mtdswap_dev *d, unsigned int page, TREE_COUNT(d, CLEAN)--; ret = mtdswap_write_marker(d, eb, MTDSWAP_TYPE_DIRTY); - } while (ret == -EIO || ret == -EBADMSG); + } while (ret == -EIO || mtd_is_eccerr(ret)); if (ret) return ret; @@ -678,7 +678,7 @@ retry: ret = mtdswap_map_free_block(d, page, bp); eb = d->eb_data + (*bp / d->pages_per_eblk); - if (ret == -EIO || ret == -EBADMSG) { + if (ret == -EIO || mtd_is_eccerr(ret)) { d->curr_write = NULL; eb->active_count--; d->revmap[*bp] = PAGE_UNDEF; @@ -690,7 +690,7 @@ retry: writepos = (loff_t)*bp << PAGE_SHIFT; ret = mtd->write(mtd, writepos, PAGE_SIZE, &retlen, buf); - if (ret == -EIO || ret == -EBADMSG) { + if (ret == -EIO || mtd_is_eccerr(ret)) { d->curr_write_pos--; eb->active_count--; d->revmap[*bp] = PAGE_UNDEF; @@ -738,7 +738,7 @@ static int mtdswap_move_block(struct mtdswap_dev *d, unsigned int oldblock, retry: ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, d->page_buf); - if (ret < 0 && ret != -EUCLEAN) { + if (ret < 0 && !mtd_is_bitflip(ret)) { oldeb = d->eb_data + oldblock / d->pages_per_eblk; oldeb->flags |= EBLOCK_READERR; @@ -931,7 +931,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = mtd->writesize; ops.ooblen = mtd->ecclayout->oobavail; ops.ooboffs = 0; @@ -1016,7 +1016,7 @@ static int mtdswap_gc(struct mtdswap_dev *d, unsigned int background) if (ret == 0) mtdswap_rb_add(d, eb, MTDSWAP_CLEAN); - else if (ret != -EIO && ret != -EBADMSG) + else if (ret != -EIO && !mtd_is_eccerr(ret)) mtdswap_rb_add(d, eb, MTDSWAP_DIRTY); return 0; @@ -1164,7 +1164,7 @@ retry: ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, buf); d->mtd_read_count++; - if (ret == -EUCLEAN) { + if (mtd_is_bitflip(ret)) { eb->flags |= EBLOCK_BITFLIP; mtdswap_rb_add(d, eb, MTDSWAP_BITFLIP); ret = 0; @@ -1374,11 +1374,10 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks, goto revmap_fail; eblk_bytes = sizeof(struct swap_eb)*d->eblks; - d->eb_data = vmalloc(eblk_bytes); + d->eb_data = vzalloc(eblk_bytes); if (!d->eb_data) goto eb_data_fail; - memset(d->eb_data, 0, eblk_bytes); for (i = 0; i < pages; i++) d->page_data[i] = BLOCK_UNDEF; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index dbfa0f7fb464..cce7b70824c3 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -83,16 +83,9 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR scratch register here to enable this feature. On Intel Moorestown boards, the scratch register is at 0xFF108018. -config MTD_NAND_EDB7312 - tristate "Support for Cirrus Logic EBD7312 evaluation board" - depends on ARCH_EDB7312 - help - This enables the driver for the Cirrus Logic EBD7312 evaluation - board to access the onboard NAND Flash. - config MTD_NAND_H1900 tristate "iPAQ H1900 flash" - depends on ARCH_PXA + depends on ARCH_PXA && BROKEN help This enables the driver for the iPAQ h1900 flash. @@ -116,10 +109,11 @@ config MTD_NAND_AMS_DELTA Support for NAND flash on Amstrad E3 (Delta). config MTD_NAND_OMAP2 - tristate "NAND Flash device on OMAP2 and OMAP3" - depends on ARM && (ARCH_OMAP2 || ARCH_OMAP3) + tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4" + depends on ARM && (ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4) help - Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. + Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4 + platforms. config MTD_NAND_IDS tristate @@ -423,6 +417,19 @@ config MTD_NAND_NANDSIM The simulator may simulate various NAND flash chips for the MTD nand layer. +config MTD_NAND_GPMI_NAND + bool "GPMI NAND Flash Controller driver" + depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28) + select MTD_PARTITIONS + select MTD_CMDLINE_PARTS + help + Enables NAND Flash support for IMX23 or IMX28. + The GPMI controller is very powerful, with the help of BCH + module, it can do the hardware ECC. The GPMI supports several + NAND flashs at the same time. The GPMI may conflicts with other + block, such as SD card. So pay attention to it when you enable + the GPMI. + config MTD_NAND_PLATFORM tristate "Support for generic platform NAND driver" help diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 5745d831168e..618f4ba23699 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_MTD_NAND_SPIA) += spia.o obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_DENALI) += denali.o -obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o @@ -49,5 +48,6 @@ obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o obj-$(CONFIG_MTD_NAND_RICOH) += r852.o obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o +obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 55da20ccc7a8..23e5d77c39fc 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -161,37 +161,6 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) !!host->board->rdy_pin_active_low; } -/* - * Minimal-overhead PIO for data access. - */ -static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_readsb(nand_chip->IO_ADDR_R, buf, len); -} - -static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); -} - -static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_writesb(nand_chip->IO_ADDR_W, buf, len); -} - -static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); -} - static void dma_complete_func(void *completion) { complete(completion); @@ -266,33 +235,27 @@ err_buf: static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) { struct nand_chip *chip = mtd->priv; - struct atmel_nand_host *host = chip->priv; if (use_dma && len > mtd->oobsize) /* only use DMA for bigger than oob size: better performances */ if (atmel_nand_dma_op(mtd, buf, len, 1) == 0) return; - if (host->board->bus_width_16) - atmel_read_buf16(mtd, buf, len); - else - atmel_read_buf8(mtd, buf, len); + /* if no DMA operation possible, use PIO */ + memcpy_fromio(buf, chip->IO_ADDR_R, len); } static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) { struct nand_chip *chip = mtd->priv; - struct atmel_nand_host *host = chip->priv; if (use_dma && len > mtd->oobsize) /* only use DMA for bigger than oob size: better performances */ if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0) return; - if (host->board->bus_width_16) - atmel_write_buf16(mtd, buf, len); - else - atmel_write_buf8(mtd, buf, len); + /* if no DMA operation possible, use PIO */ + memcpy_toio(chip->IO_ADDR_W, buf, len); } /* @@ -481,10 +444,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) } } -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = { "cmdlinepart", NULL }; -#endif - /* * Probe for the NAND device. */ @@ -496,8 +455,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev) struct resource *regs; struct resource *mem; int res; - struct mtd_partition *partitions = NULL; - int num_partitions = 0; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { @@ -583,7 +540,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) if (on_flash_bbt) { printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); - nand_chip->options |= NAND_USE_FLASH_BBT; + nand_chip->bbt_options |= NAND_BBT_USE_FLASH; } if (!cpu_has_dma()) @@ -594,7 +551,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) dma_cap_zero(mask); dma_cap_set(DMA_MEMCPY, mask); - host->dma_chan = dma_request_channel(mask, 0, NULL); + host->dma_chan = dma_request_channel(mask, NULL, NULL); if (!host->dma_chan) { dev_err(host->dev, "Failed to request DMA channel\n"); use_dma = 0; @@ -655,27 +612,12 @@ static int __init atmel_nand_probe(struct platform_device *pdev) goto err_scan_tail; } -#ifdef CONFIG_MTD_CMDLINE_PARTS mtd->name = "atmel_nand"; - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partitions, 0); -#endif - if (num_partitions <= 0 && host->board->partition_info) - partitions = host->board->partition_info(mtd->size, - &num_partitions); - - if ((!partitions) || (num_partitions == 0)) { - printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n"); - res = -ENXIO; - goto err_no_partitions; - } - - res = mtd_device_register(mtd, partitions, num_partitions); + res = mtd_device_parse_register(mtd, NULL, 0, + host->board->parts, host->board->num_parts); if (!res) return res; -err_no_partitions: - nand_release(mtd); err_scan_tail: err_scan_ident: err_no_card: diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index fa5736b9286c..7dd3700f2303 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -52,7 +52,7 @@ static const struct mtd_partition partition_info[] = { * au_read_byte - read one byte from the chip * @mtd: MTD device structure * - * read function for 8bit buswith + * read function for 8bit buswidth */ static u_char au_read_byte(struct mtd_info *mtd) { @@ -67,7 +67,7 @@ static u_char au_read_byte(struct mtd_info *mtd) * @mtd: MTD device structure * @byte: pointer to data byte to write * - * write function for 8it buswith + * write function for 8it buswidth */ static void au_write_byte(struct mtd_info *mtd, u_char byte) { @@ -77,11 +77,10 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte) } /** - * au_read_byte16 - read one byte endianess aware from the chip + * au_read_byte16 - read one byte endianness aware from the chip * @mtd: MTD device structure * - * read function for 16bit buswith with - * endianess conversion + * read function for 16bit buswidth with endianness conversion */ static u_char au_read_byte16(struct mtd_info *mtd) { @@ -92,12 +91,11 @@ static u_char au_read_byte16(struct mtd_info *mtd) } /** - * au_write_byte16 - write one byte endianess aware to the chip + * au_write_byte16 - write one byte endianness aware to the chip * @mtd: MTD device structure * @byte: pointer to data byte to write * - * write function for 16bit buswith with - * endianess conversion + * write function for 16bit buswidth with endianness conversion */ static void au_write_byte16(struct mtd_info *mtd, u_char byte) { @@ -110,8 +108,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte) * au_read_word - read one word from the chip * @mtd: MTD device structure * - * read function for 16bit buswith without - * endianess conversion + * read function for 16bit buswidth without endianness conversion */ static u16 au_read_word(struct mtd_info *mtd) { @@ -127,7 +124,7 @@ static u16 au_read_word(struct mtd_info *mtd) * @buf: data buffer * @len: number of bytes to write * - * write function for 8bit buswith + * write function for 8bit buswidth */ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { @@ -146,7 +143,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) * @buf: buffer to store date * @len: number of bytes to read * - * read function for 8bit buswith + * read function for 8bit buswidth */ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) { @@ -165,7 +162,7 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) * @buf: buffer containing the data to compare * @len: number of bytes to compare * - * verify function for 8bit buswith + * verify function for 8bit buswidth */ static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) { @@ -187,7 +184,7 @@ static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) * @buf: data buffer * @len: number of bytes to write * - * write function for 16bit buswith + * write function for 16bit buswidth */ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) { @@ -209,7 +206,7 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) * @buf: buffer to store date * @len: number of bytes to read * - * read function for 16bit buswith + * read function for 16bit buswidth */ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) { @@ -230,7 +227,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) * @buf: buffer containing the data to compare * @len: number of bytes to compare * - * verify function for 16bit buswith + * verify function for 16bit buswidth */ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) { diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index eddc9a224985..2e42ec2e8ff4 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -172,9 +172,9 @@ static int __init autcpu12_init(void) /* Enable the following for a flash based bad block table */ /* - this->options = NAND_USE_FLASH_BBT; + this->bbt_options = NAND_BBT_USE_FLASH; */ - this->options = NAND_USE_FLASH_BBT; + this->bbt_options = NAND_BBT_USE_FLASH; /* Scan to find existence of the device */ if (nand_scan(autcpu12_mtd, 1)) { diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index 8c569e454dc5..46b58d672847 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -52,8 +52,6 @@ static const __devinitconst char gBanner[] = KERN_INFO \ "BCM UMI MTD NAND Driver: 1.00\n"; -const char *part_probes[] = { "cmdlinepart", NULL }; - #if NAND_ECC_BCH static uint8_t scan_ff_pattern[] = { 0xff }; @@ -376,16 +374,18 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -ENXIO; + if (!r) { + err = -ENXIO; + goto out_free; + } /* map physical address */ bcm_umi_io_base = ioremap(r->start, resource_size(r)); if (!bcm_umi_io_base) { printk(KERN_ERR "ioremap to access BCM UMI NAND chip failed\n"); - kfree(board_mtd); - return -EIO; + err = -EIO; + goto out_free; } /* Get pointer to private data */ @@ -401,9 +401,8 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) /* Initialize the NAND hardware. */ if (bcm_umi_nand_inithw() < 0) { printk(KERN_ERR "BCM UMI NAND chip could not be initialized\n"); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return -EIO; + err = -EIO; + goto out_unmap; } /* Set address of NAND IO lines */ @@ -436,7 +435,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) #if USE_DMA err = nand_dma_init(); if (err != 0) - return err; + goto out_unmap; #endif /* Figure out the size of the device that we have. @@ -447,9 +446,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) err = nand_scan_ident(board_mtd, 1, NULL); if (err) { printk(KERN_ERR "nand_scan failed: %d\n", err); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return err; + goto out_unmap; } /* Now that we know the nand size, we can setup the ECC layout */ @@ -468,13 +465,14 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) { printk(KERN_ERR "NAND - Unrecognized pagesize: %d\n", board_mtd->writesize); - return -EINVAL; + err = -EINVAL; + goto out_unmap; } } #if NAND_ECC_BCH if (board_mtd->writesize > 512) { - if (this->options & NAND_USE_FLASH_BBT) + if (this->bbt_options & NAND_BBT_USE_FLASH) largepage_bbt.options = NAND_BBT_SCAN2NDPAGE; this->badblock_pattern = &largepage_bbt; } @@ -485,33 +483,20 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) err = nand_scan_tail(board_mtd); if (err) { printk(KERN_ERR "nand_scan failed: %d\n", err); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return err; + goto out_unmap; } /* Register the partitions */ - { - int nr_partitions; - struct mtd_partition *partition_info; - - board_mtd->name = "bcm_umi-nand"; - nr_partitions = - parse_mtd_partitions(board_mtd, part_probes, - &partition_info, 0); - - if (nr_partitions <= 0) { - printk(KERN_ERR "BCM UMI NAND: Too few partitions - %d\n", - nr_partitions); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return -EIO; - } - mtd_device_register(board_mtd, partition_info, nr_partitions); - } + board_mtd->name = "bcm_umi-nand"; + mtd_device_parse_register(board_mtd, NULL, 0, NULL, 0); /* Return happy */ return 0; +out_unmap: + iounmap(bcm_umi_io_base); +out_free: + kfree(board_mtd); + return err; } static int bcm_umi_nand_remove(struct platform_device *pdev) diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 87ebb4e5b0c3..72d3f23490c5 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -21,6 +21,7 @@ #include <linux/interrupt.h> #include <linux/dma-mapping.h> #include <linux/slab.h> +#include <linux/module.h> #include <asm/io.h> #define CAFE_NAND_CTRL1 0x00 @@ -57,7 +58,6 @@ struct cafe_priv { struct nand_chip nand; - struct mtd_partition *parts; struct pci_dev *pdev; void __iomem *mmio; struct rs_control *rs; @@ -371,7 +371,7 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, return 1; } /** - * cafe_nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read + * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -630,8 +630,6 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, struct cafe_priv *cafe; uint32_t ctrl; int err = 0; - struct mtd_partition *parts; - int nr_parts; /* Very old versions shared the same PCI ident for all three functions on the chip. Verify the class too... */ @@ -686,7 +684,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, cafe->nand.chip_delay = 0; /* Enable the following for a flash based bad block table */ - cafe->nand.options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; + cafe->nand.bbt_options = NAND_BBT_USE_FLASH; + cafe->nand.options = NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; if (skipbbt) { cafe->nand.options |= NAND_SKIP_BBTSCAN; @@ -799,18 +798,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, mtd); - /* We register the whole device first, separate from the partitions */ - mtd_device_register(mtd, NULL, 0); - -#ifdef CONFIG_MTD_CMDLINE_PARTS mtd->name = "cafe_nand"; -#endif - nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); - if (nr_parts > 0) { - cafe->parts = parts; - dev_info(&cafe->pdev->dev, "%d partitions found\n", nr_parts); - mtd_device_register(mtd, parts, nr_parts); - } + mtd_device_parse_register(mtd, part_probes, 0, NULL, 0); + goto out; out_irq: diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index 6fc043a30d1e..737ef9a04fdb 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -22,6 +22,7 @@ #include <linux/mtd/partitions.h> #include <linux/slab.h> #include <linux/gpio.h> +#include <linux/module.h> #include <asm/io.h> #include <asm/irq.h> @@ -50,8 +51,6 @@ static struct mtd_partition partition_info[] = { }; #define NUM_PARTITIONS (ARRAY_SIZE(partition_info)) -const char *part_probes[] = { "cmdlinepart", NULL }; - static u_char cmx270_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; @@ -151,9 +150,6 @@ static int cmx270_device_ready(struct mtd_info *mtd) static int __init cmx270_init(void) { struct nand_chip *this; - const char *part_type; - struct mtd_partition *mtd_parts; - int mtd_parts_nb = 0; int ret; if (!(machine_is_armcore() && cpu_is_pxa27x())) @@ -222,23 +218,9 @@ static int __init cmx270_init(void) goto err_scan; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, part_probes, - &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; -#endif - if (!mtd_parts_nb) { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } - /* Register the partitions */ - pr_notice("Using %s partition definition\n", part_type); - ret = mtd_device_register(cmx270_nand_mtd, mtd_parts, mtd_parts_nb); + ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, 0, + partition_info, NUM_PARTITIONS); if (ret) goto err_scan; diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index f59ad1f2d5db..414afa793563 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -239,7 +239,8 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) this->ecc.correct = nand_correct_data; /* Enable the following for a flash based bad block table */ - this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; + this->bbt_options = NAND_BBT_USE_FLASH; + this->options = NAND_NO_AUTOINCR; /* Scan to find existence of the device */ if (nand_scan(new_mtd, 1)) { @@ -277,15 +278,11 @@ static int is_geode(void) return 0; } -static const char *part_probes[] = { "cmdlinepart", NULL }; - static int __init cs553x_init(void) { int err = -ENXIO; int i; uint64_t val; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = NULL; /* If the CPU isn't a Geode GX or LX, abort */ if (!is_geode()) @@ -315,13 +312,9 @@ static int __init cs553x_init(void) do mtdconcat etc. if we want to. */ for (i = 0; i < NR_CS553X_CONTROLLERS; i++) { if (cs553x_mtd[i]) { - /* If any devices registered, return success. Else the last error. */ - mtd_parts_nb = parse_mtd_partitions(cs553x_mtd[i], part_probes, &mtd_parts, 0); - if (mtd_parts_nb > 0) - printk(KERN_NOTICE "Using command line partition definition\n"); - mtd_device_register(cs553x_mtd[i], mtd_parts, - mtd_parts_nb); + mtd_device_parse_register(cs553x_mtd[i], NULL, 0, + NULL, 0); err = 0; } } diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 1f34951ae1a7..c153e1f77f90 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -57,7 +57,6 @@ struct davinci_nand_info { struct device *dev; struct clk *clk; - bool partitioned; bool is_readmode; @@ -530,8 +529,6 @@ static int __init nand_davinci_probe(struct platform_device *pdev) int ret; uint32_t val; nand_ecc_modes_t ecc_mode; - struct mtd_partition *mtd_parts = NULL; - int mtd_parts_nb = 0; /* insist on board-specific configuration */ if (!pdata) @@ -581,7 +578,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->chip.chip_delay = 0; info->chip.select_chip = nand_davinci_select_chip; - /* options such as NAND_USE_FLASH_BBT or 16-bit widths */ + /* options such as NAND_BBT_USE_FLASH */ + info->chip.bbt_options = pdata->bbt_options; + /* options such as 16-bit widths */ info->chip.options = pdata->options; info->chip.bbt_td = pdata->bbt_td; info->chip.bbt_md = pdata->bbt_md; @@ -751,33 +750,8 @@ syndrome_done: if (ret < 0) goto err_scan; - if (mtd_has_cmdlinepart()) { - static const char *probes[] __initconst = { - "cmdlinepart", NULL - }; - - mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes, - &mtd_parts, 0); - } - - if (mtd_parts_nb <= 0) { - mtd_parts = pdata->parts; - mtd_parts_nb = pdata->nr_parts; - } - - /* Register any partitions */ - if (mtd_parts_nb > 0) { - ret = mtd_device_register(&info->mtd, mtd_parts, - mtd_parts_nb); - if (ret == 0) - info->partitioned = true; - } - - /* If there's no partition info, just package the whole chip - * as a single MTD device. - */ - if (!info->partitioned) - ret = mtd_device_register(&info->mtd, NULL, 0) ? -ENODEV : 0; + ret = mtd_device_parse_register(&info->mtd, NULL, 0, + pdata->parts, pdata->nr_parts); if (ret < 0) goto err_scan; @@ -816,9 +790,6 @@ err_nomem: static int __exit nand_davinci_remove(struct platform_device *pdev) { struct davinci_nand_info *info = platform_get_drvdata(pdev); - int status; - - status = mtd_device_unregister(&info->mtd); spin_lock_irq(&davinci_nand_lock); if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d5276218945f..3984d488f9ab 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1346,6 +1346,7 @@ static void denali_hw_init(struct denali_nand_info *denali) * */ denali->bbtskipbytes = ioread32(denali->flash_reg + SPARE_AREA_SKIP_BYTES); + detect_max_banks(denali); denali_nand_reset(denali); iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED); iowrite32(CHIP_EN_DONT_CARE__FLAG, @@ -1356,7 +1357,6 @@ static void denali_hw_init(struct denali_nand_info *denali) /* Should set value for these registers when init */ iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES); iowrite32(1, denali->flash_reg + ECC_ENABLE); - detect_max_banks(denali); denali_nand_timing_set(denali); denali_irq_init(denali); } @@ -1577,7 +1577,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) denali->nand.bbt_md = &bbt_mirror_descr; /* skip the scan for now until we have OOB read and write support */ - denali->nand.options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; + denali->nand.bbt_options |= NAND_BBT_USE_FLASH; + denali->nand.options |= NAND_SKIP_BBTSCAN; denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; /* Denali Controller only support 15bit and 8bit ECC in MRST, @@ -1676,7 +1677,6 @@ static void denali_pci_remove(struct pci_dev *dev) struct denali_nand_info *denali = pci_get_drvdata(dev); nand_release(&denali->mtd); - mtd_device_unregister(&denali->mtd); denali_irq_cleanup(dev->irq, denali); diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 7837728d02ff..5780dbab6113 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -31,6 +31,7 @@ #include <linux/mtd/doc2000.h> #include <linux/mtd/partitions.h> #include <linux/mtd/inftl.h> +#include <linux/module.h> /* Where to look for the devices? */ #ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS @@ -132,7 +133,7 @@ static struct rs_control *rs_decoder; /* * The HW decoder in the DoC ASIC's provides us a error syndrome, - * which we must convert to a standard syndrom usable by the generic + * which we must convert to a standard syndrome usable by the generic * Reed-Solomon library code. * * Fabrice Bellard figured this out in the old docecc code. I added @@ -153,7 +154,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc) ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2); parity = ecc[1]; - /* Initialize the syndrom buffer */ + /* Initialize the syndrome buffer */ for (i = 0; i < NROOTS; i++) s[i] = ds[0]; /* @@ -1031,7 +1032,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); else WriteDOC(DOC_ECC_DIS, docptr, ECCConf); - if (no_ecc_failures && (ret == -EBADMSG)) { + if (no_ecc_failures && mtd_is_eccerr(ret)) { printk(KERN_ERR "suppressing ECC failure\n"); ret = 0; } @@ -1652,7 +1653,7 @@ static int __init doc_probe(unsigned long physadr) nand->ecc.mode = NAND_ECC_HW_SYNDROME; nand->ecc.size = 512; nand->ecc.bytes = 6; - nand->options = NAND_USE_FLASH_BBT; + nand->bbt_options = NAND_BBT_USE_FLASH; doc->physadr = physadr; doc->virtadr = virtadr; diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c deleted file mode 100644 index 8400d0f6dada..000000000000 --- a/drivers/mtd/nand/edb7312.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * drivers/mtd/nand/edb7312.c - * - * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) - * - * Derived from drivers/mtd/nand/autcpu12.c - * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Overview: - * This is a device driver for the NAND flash device found on the - * CLEP7312 board which utilizes the Toshiba TC58V64AFT part. This is - * a 64Mibit (8MiB x 8 bits) NAND flash device. - */ - -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/partitions.h> -#include <asm/io.h> -#include <mach/hardware.h> /* for CLPS7111_VIRT_BASE */ -#include <asm/sizes.h> -#include <asm/hardware/clps7111.h> - -/* - * MTD structure for EDB7312 board - */ -static struct mtd_info *ep7312_mtd = NULL; - -/* - * Values specific to the EDB7312 board (used with EP7312 processor) - */ -#define EP7312_FIO_PBASE 0x10000000 /* Phys address of flash */ -#define EP7312_PXDR 0x0001 /* - * IO offset to Port B data register - * where the CLE, ALE and NCE pins - * are wired to. - */ -#define EP7312_PXDDR 0x0041 /* - * IO offset to Port B data direction - * register so we can control the IO - * lines. - */ - -/* - * Module stuff - */ - -static unsigned long ep7312_fio_pbase = EP7312_FIO_PBASE; -static void __iomem *ep7312_pxdr = (void __iomem *)EP7312_PXDR; -static void __iomem *ep7312_pxddr = (void __iomem *)EP7312_PXDDR; - -/* - * Define static partitions for flash device - */ -static struct mtd_partition partition_info[] = { - {.name = "EP7312 Nand Flash", - .offset = 0, - .size = 8 * 1024 * 1024} -}; - -#define NUM_PARTITIONS 1 - -/* - * hardware specific access to control-lines - * - * NAND_NCE: bit 0 -> bit 6 (bit 7 = 1) - * NAND_CLE: bit 1 -> bit 4 - * NAND_ALE: bit 2 -> bit 5 - */ -static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *chip = mtd->priv; - - if (ctrl & NAND_CTRL_CHANGE) { - unsigned char bits = 0x80; - - bits |= (ctrl & (NAND_CLE | NAND_ALE)) << 3; - bits |= (ctrl & NAND_NCE) ? 0x00 : 0x40; - - clps_writeb((clps_readb(ep7312_pxdr) & 0xF0) | bits, - ep7312_pxdr); - } - if (cmd != NAND_CMD_NONE) - writeb(cmd, chip->IO_ADDR_W); -} - -/* - * read device ready pin - */ -static int ep7312_device_ready(struct mtd_info *mtd) -{ - return 1; -} - -const char *part_probes[] = { "cmdlinepart", NULL }; - -/* - * Main initialization routine - */ -static int __init ep7312_init(void) -{ - struct nand_chip *this; - const char *part_type = 0; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; - void __iomem *ep7312_fio_base; - - /* Allocate memory for MTD device structure and private data */ - ep7312_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); - if (!ep7312_mtd) { - printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); - return -ENOMEM; - } - - /* map physical address */ - ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K); - if (!ep7312_fio_base) { - printk("ioremap EDB7312 NAND flash failed\n"); - kfree(ep7312_mtd); - return -EIO; - } - - /* Get pointer to private data */ - this = (struct nand_chip *)(&ep7312_mtd[1]); - - /* Initialize structures */ - memset(ep7312_mtd, 0, sizeof(struct mtd_info)); - memset(this, 0, sizeof(struct nand_chip)); - - /* Link the private data with the MTD structure */ - ep7312_mtd->priv = this; - ep7312_mtd->owner = THIS_MODULE; - - /* - * Set GPIO Port B control register so that the pins are configured - * to be outputs for controlling the NAND flash. - */ - clps_writeb(0xf0, ep7312_pxddr); - - /* insert callbacks */ - this->IO_ADDR_R = ep7312_fio_base; - this->IO_ADDR_W = ep7312_fio_base; - this->cmd_ctrl = ep7312_hwcontrol; - this->dev_ready = ep7312_device_ready; - /* 15 us command delay time */ - this->chip_delay = 15; - - /* Scan to find existence of the device */ - if (nand_scan(ep7312_mtd, 1)) { - iounmap((void *)ep7312_fio_base); - kfree(ep7312_mtd); - return -ENXIO; - } - ep7312_mtd->name = "edb7312-nand"; - mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - if (mtd_parts_nb == 0) { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } - - /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(ep7312_mtd, mtd_parts, mtd_parts_nb); - - /* Return happy */ - return 0; -} - -module_init(ep7312_init); - -/* - * Clean up routine - */ -static void __exit ep7312_cleanup(void) -{ - struct nand_chip *this = (struct nand_chip *)&ep7312_mtd[1]; - - /* Release resources, unregister device */ - nand_release(ap7312_mtd); - - /* Release io resource */ - iounmap(this->IO_ADDR_R); - - /* Free the MTD device structure */ - kfree(ep7312_mtd); -} - -module_exit(ep7312_cleanup); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); -MODULE_DESCRIPTION("MTD map driver for Cogent EDB7312 board"); diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 33d8aad8bba5..eedd8ee2c9ac 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -75,7 +75,6 @@ struct fsl_elbc_fcm_ctrl { unsigned int use_mdr; /* Non zero if the MDR is to be set */ unsigned int oob; /* Non zero if operating on OOB data */ unsigned int counter; /* counter for the initializations */ - char *oob_poi; /* Place to write ECC after read back */ }; /* These map to the positions used by the FCM hardware ECC generator */ @@ -244,6 +243,25 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) return -EIO; } + if (chip->ecc.mode != NAND_ECC_HW) + return 0; + + if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) { + uint32_t lteccr = in_be32(&lbc->lteccr); + /* + * if command was a full page read and the ELBC + * has the LTECCR register, then bits 12-15 (ppc order) of + * LTECCR indicates which 512 byte sub-pages had fixed errors. + * bits 28-31 are uncorrectable errors, marked elsewhere. + * for small page nand only 1 bit is used. + * if the ELBC doesn't have the lteccr register it reads 0 + */ + if (lteccr & 0x000F000F) + out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */ + if (lteccr & 0x000F0000) + mtd->ecc_stats.corrected++; + } + return 0; } @@ -435,7 +453,6 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ case NAND_CMD_PAGEPROG: { - int full_page; dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " "writing %d bytes.\n", elbc_fcm_ctrl->index); @@ -445,34 +462,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, * write so the HW generates the ECC. */ if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 || - elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) { + elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) out_be32(&lbc->fbcr, elbc_fcm_ctrl->index); - full_page = 0; - } else { + else out_be32(&lbc->fbcr, 0); - full_page = 1; - } fsl_elbc_run_command(mtd); - - /* Read back the page in order to fill in the ECC for the - * caller. Is this really needed? - */ - if (full_page && elbc_fcm_ctrl->oob_poi) { - out_be32(&lbc->fbcr, 3); - set_addr(mtd, 6, page_addr, 1); - - elbc_fcm_ctrl->read_bytes = mtd->writesize + 9; - - fsl_elbc_do_read(chip, 1); - fsl_elbc_run_command(mtd); - - memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6, - &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3); - elbc_fcm_ctrl->index += 3; - } - - elbc_fcm_ctrl->oob_poi = NULL; return; } @@ -752,13 +747,8 @@ static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; - fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - elbc_fcm_ctrl->oob_poi = chip->oob_poi; } static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) @@ -791,8 +781,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->bbt_md = &bbt_mirror_descr; /* set up nand options */ - chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | - NAND_USE_FLASH_BBT; + chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; + chip->bbt_options = NAND_BBT_USE_FLASH; chip->controller = &elbc_fcm_ctrl->controller; chip->priv = priv; @@ -829,7 +819,6 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) elbc_fcm_ctrl->chips[priv->bank] = NULL; kfree(priv); - kfree(elbc_fcm_ctrl); return 0; } @@ -842,13 +831,14 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) struct resource res; struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl; static const char *part_probe_types[] - = { "cmdlinepart", "RedBoot", NULL }; - struct mtd_partition *parts; + = { "cmdlinepart", "RedBoot", "ofpart", NULL }; int ret; int bank; struct device *dev; struct device_node *node = pdev->dev.of_node; + struct mtd_part_parser_data ppdata; + ppdata.of_node = pdev->dev.of_node; if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) return -ENODEV; lbc = fsl_lbc_ctrl_dev->regs; @@ -934,17 +924,8 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) /* First look for RedBoot table or partitions on the command * line, these take precedence over device tree information */ - ret = parse_mtd_partitions(&priv->mtd, part_probe_types, &parts, 0); - if (ret < 0) - goto err; - - if (ret == 0) { - ret = of_mtd_parse_partitions(priv->dev, node, &parts); - if (ret < 0) - goto err; - } - - mtd_device_register(&priv->mtd, parts, ret); + mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata, + NULL, 0); printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n", (unsigned long long)res.start, priv->bank); diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 23752fd5bc59..b4f3cc9f32fb 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -158,7 +158,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, { int ret; struct device_node *flash_np; - static const char *part_types[] = { "cmdlinepart", NULL, }; + struct mtd_part_parser_data ppdata; fun->chip.IO_ADDR_R = fun->io_base; fun->chip.IO_ADDR_W = fun->io_base; @@ -192,18 +192,12 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, if (ret) goto err; - ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0); - -#ifdef CONFIG_MTD_OF_PARTS - if (ret == 0) { - ret = of_mtd_parse_partitions(fun->dev, flash_np, &fun->parts); - if (ret < 0) - goto err; - } -#endif - ret = mtd_device_register(&fun->mtd, fun->parts, ret); + ppdata.of_node = flash_np; + ret = mtd_device_parse_register(&fun->mtd, NULL, &ppdata, NULL, 0); err: of_node_put(flash_np); + if (ret) + kfree(fun->mtd.name); return ret; } diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index e9b275ac381c..e53b76064133 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -146,7 +146,7 @@ static struct mtd_partition partition_info_16KB_blk[] = { { .name = "Root File System", .offset = 0x460000, - .size = 0, + .size = MTDPART_SIZ_FULL, }, }; @@ -173,13 +173,10 @@ static struct mtd_partition partition_info_128KB_blk[] = { { .name = "Root File System", .offset = 0x800000, - .size = 0, + .size = MTDPART_SIZ_FULL, }, }; -#ifdef CONFIG_MTD_CMDLINE_PARTS -const char *part_probes[] = { "cmdlinepart", NULL }; -#endif /** * struct fsmc_nand_data - structure for FSMC NAND device state @@ -187,8 +184,6 @@ const char *part_probes[] = { "cmdlinepart", NULL }; * @pid: Part ID on the AMBA PrimeCell format * @mtd: MTD info for a NAND flash. * @nand: Chip related info for a NAND flash. - * @partitions: Partition info for a NAND Flash. - * @nr_partitions: Total number of partition of a NAND flash. * * @ecc_place: ECC placing locations in oobfree type format. * @bank: Bank number for probed device. @@ -203,8 +198,6 @@ struct fsmc_nand_data { u32 pid; struct mtd_info mtd; struct nand_chip nand; - struct mtd_partition *partitions; - unsigned int nr_partitions; struct fsmc_eccplace *ecc_place; unsigned int bank; @@ -716,65 +709,17 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) * platform data, * default partition information present in driver. */ -#ifdef CONFIG_MTD_CMDLINE_PARTS /* - * Check if partition info passed via command line + * Check for partition info passed */ host->mtd.name = "nand"; - host->nr_partitions = parse_mtd_partitions(&host->mtd, part_probes, - &host->partitions, 0); - if (host->nr_partitions <= 0) { -#endif - /* - * Check if partition info passed via command line - */ - if (pdata->partitions) { - host->partitions = pdata->partitions; - host->nr_partitions = pdata->nr_partitions; - } else { - struct mtd_partition *partition; - int i; - - /* Select the default partitions info */ - switch (host->mtd.size) { - case 0x01000000: - case 0x02000000: - case 0x04000000: - host->partitions = partition_info_16KB_blk; - host->nr_partitions = - sizeof(partition_info_16KB_blk) / - sizeof(struct mtd_partition); - break; - case 0x08000000: - case 0x10000000: - case 0x20000000: - case 0x40000000: - host->partitions = partition_info_128KB_blk; - host->nr_partitions = - sizeof(partition_info_128KB_blk) / - sizeof(struct mtd_partition); - break; - default: - ret = -ENXIO; - pr_err("Unsupported NAND size\n"); - goto err_probe; - } - - partition = host->partitions; - for (i = 0; i < host->nr_partitions; i++, partition++) { - if (partition->size == 0) { - partition->size = host->mtd.size - - partition->offset; - break; - } - } - } -#ifdef CONFIG_MTD_CMDLINE_PARTS - } -#endif - - ret = mtd_device_register(&host->mtd, host->partitions, - host->nr_partitions); + ret = mtd_device_parse_register(&host->mtd, NULL, 0, + host->mtd.size <= 0x04000000 ? + partition_info_16KB_blk : + partition_info_128KB_blk, + host->mtd.size <= 0x04000000 ? + ARRAY_SIZE(partition_info_16KB_blk) : + ARRAY_SIZE(partition_info_128KB_blk)); if (ret) goto err_probe; @@ -822,7 +767,7 @@ static int fsmc_nand_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (host) { - mtd_device_unregister(&host->mtd); + nand_release(&host->mtd); clk_disable(host->clk); clk_put(host->clk); diff --git a/drivers/mtd/nand/gpmi-nand/Makefile b/drivers/mtd/nand/gpmi-nand/Makefile new file mode 100644 index 000000000000..3a462487c35e --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o +gpmi_nand-objs += gpmi-nand.o +gpmi_nand-objs += gpmi-lib.o diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/gpmi-nand/bch-regs.h new file mode 100644 index 000000000000..4effb8c579db --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/bch-regs.h @@ -0,0 +1,84 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __GPMI_NAND_BCH_REGS_H +#define __GPMI_NAND_BCH_REGS_H + +#define HW_BCH_CTRL 0x00000000 +#define HW_BCH_CTRL_SET 0x00000004 +#define HW_BCH_CTRL_CLR 0x00000008 +#define HW_BCH_CTRL_TOG 0x0000000c + +#define BM_BCH_CTRL_COMPLETE_IRQ_EN (1 << 8) +#define BM_BCH_CTRL_COMPLETE_IRQ (1 << 0) + +#define HW_BCH_STATUS0 0x00000010 +#define HW_BCH_MODE 0x00000020 +#define HW_BCH_ENCODEPTR 0x00000030 +#define HW_BCH_DATAPTR 0x00000040 +#define HW_BCH_METAPTR 0x00000050 +#define HW_BCH_LAYOUTSELECT 0x00000070 + +#define HW_BCH_FLASH0LAYOUT0 0x00000080 + +#define BP_BCH_FLASH0LAYOUT0_NBLOCKS 24 +#define BM_BCH_FLASH0LAYOUT0_NBLOCKS (0xff << BP_BCH_FLASH0LAYOUT0_NBLOCKS) +#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_NBLOCKS) & BM_BCH_FLASH0LAYOUT0_NBLOCKS) + +#define BP_BCH_FLASH0LAYOUT0_META_SIZE 16 +#define BM_BCH_FLASH0LAYOUT0_META_SIZE (0xff << BP_BCH_FLASH0LAYOUT0_META_SIZE) +#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_META_SIZE)\ + & BM_BCH_FLASH0LAYOUT0_META_SIZE) + +#define BP_BCH_FLASH0LAYOUT0_ECC0 12 +#define BM_BCH_FLASH0LAYOUT0_ECC0 (0xf << BP_BCH_FLASH0LAYOUT0_ECC0) +#define BF_BCH_FLASH0LAYOUT0_ECC0(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_ECC0) & BM_BCH_FLASH0LAYOUT0_ECC0) + +#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0 +#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \ + (0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE) +#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)\ + & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) + +#define HW_BCH_FLASH0LAYOUT1 0x00000090 + +#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16 +#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE \ + (0xffff << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) +#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) \ + & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE) + +#define BP_BCH_FLASH0LAYOUT1_ECCN 12 +#define BM_BCH_FLASH0LAYOUT1_ECCN (0xf << BP_BCH_FLASH0LAYOUT1_ECCN) +#define BF_BCH_FLASH0LAYOUT1_ECCN(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_ECCN) & BM_BCH_FLASH0LAYOUT1_ECCN) + +#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0 +#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \ + (0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) +#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) \ + & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) +#endif diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c new file mode 100644 index 000000000000..de4db7604a3f --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -0,0 +1,1057 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <linux/mtd/gpmi-nand.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <mach/mxs.h> + +#include "gpmi-nand.h" +#include "gpmi-regs.h" +#include "bch-regs.h" + +struct timing_threshod timing_default_threshold = { + .max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >> + BP_GPMI_TIMING0_DATA_SETUP), + .internal_data_setup_in_ns = 0, + .max_sample_delay_factor = (BM_GPMI_CTRL1_RDN_DELAY >> + BP_GPMI_CTRL1_RDN_DELAY), + .max_dll_clock_period_in_ns = 32, + .max_dll_delay_in_ns = 16, +}; + +/* + * Clear the bit and poll it cleared. This is usually called with + * a reset address and mask being either SFTRST(bit 31) or CLKGATE + * (bit 30). + */ +static int clear_poll_bit(void __iomem *addr, u32 mask) +{ + int timeout = 0x400; + + /* clear the bit */ + __mxs_clrl(mask, addr); + + /* + * SFTRST needs 3 GPMI clocks to settle, the reference manual + * recommends to wait 1us. + */ + udelay(1); + + /* poll the bit becoming clear */ + while ((readl(addr) & mask) && --timeout) + /* nothing */; + + return !timeout; +} + +#define MODULE_CLKGATE (1 << 30) +#define MODULE_SFTRST (1 << 31) +/* + * The current mxs_reset_block() will do two things: + * [1] enable the module. + * [2] reset the module. + * + * In most of the cases, it's ok. But there is a hardware bug in the BCH block. + * If you try to soft reset the BCH block, it becomes unusable until + * the next hard reset. This case occurs in the NAND boot mode. When the board + * boots by NAND, the ROM of the chip will initialize the BCH blocks itself. + * So If the driver tries to reset the BCH again, the BCH will not work anymore. + * You will see a DMA timeout in this case. + * + * To avoid this bug, just add a new parameter `just_enable` for + * the mxs_reset_block(), and rewrite it here. + */ +int gpmi_reset_block(void __iomem *reset_addr, bool just_enable) +{ + int ret; + int timeout = 0x400; + + /* clear and poll SFTRST */ + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); + if (unlikely(ret)) + goto error; + + /* clear CLKGATE */ + __mxs_clrl(MODULE_CLKGATE, reset_addr); + + if (!just_enable) { + /* set SFTRST to reset the block */ + __mxs_setl(MODULE_SFTRST, reset_addr); + udelay(1); + + /* poll CLKGATE becoming set */ + while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout) + /* nothing */; + if (unlikely(!timeout)) + goto error; + } + + /* clear and poll SFTRST */ + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); + if (unlikely(ret)) + goto error; + + /* clear and poll CLKGATE */ + ret = clear_poll_bit(reset_addr, MODULE_CLKGATE); + if (unlikely(ret)) + goto error; + + return 0; + +error: + pr_err("%s(%p): module reset timeout\n", __func__, reset_addr); + return -ETIMEDOUT; +} + +int gpmi_init(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + int ret; + + ret = clk_enable(r->clock); + if (ret) + goto err_out; + ret = gpmi_reset_block(r->gpmi_regs, false); + if (ret) + goto err_out; + + /* Choose NAND mode. */ + writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); + + /* Set the IRQ polarity. */ + writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY, + r->gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Disable Write-Protection. */ + writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Select BCH ECC. */ + writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET); + + clk_disable(r->clock); + return 0; +err_out: + return ret; +} + +/* This function is very useful. It is called only when the bug occur. */ +void gpmi_dump_info(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + struct bch_geometry *geo = &this->bch_geometry; + u32 reg; + int i; + + pr_err("Show GPMI registers :\n"); + for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) { + reg = readl(r->gpmi_regs + i * 0x10); + pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); + } + + /* start to print out the BCH info */ + pr_err("BCH Geometry :\n"); + pr_err("GF length : %u\n", geo->gf_len); + pr_err("ECC Strength : %u\n", geo->ecc_strength); + pr_err("Page Size in Bytes : %u\n", geo->page_size); + pr_err("Metadata Size in Bytes : %u\n", geo->metadata_size); + pr_err("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size); + pr_err("ECC Chunk Count : %u\n", geo->ecc_chunk_count); + pr_err("Payload Size in Bytes : %u\n", geo->payload_size); + pr_err("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size); + pr_err("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset); + pr_err("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset); + pr_err("Block Mark Bit Offset : %u\n", geo->block_mark_bit_offset); +} + +/* Configures the geometry for BCH. */ +int bch_set_geometry(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + struct bch_geometry *bch_geo = &this->bch_geometry; + unsigned int block_count; + unsigned int block_size; + unsigned int metadata_size; + unsigned int ecc_strength; + unsigned int page_size; + int ret; + + if (common_nfc_set_geometry(this)) + return !0; + + block_count = bch_geo->ecc_chunk_count - 1; + block_size = bch_geo->ecc_chunk_size; + metadata_size = bch_geo->metadata_size; + ecc_strength = bch_geo->ecc_strength >> 1; + page_size = bch_geo->page_size; + + ret = clk_enable(r->clock); + if (ret) + goto err_out; + + ret = gpmi_reset_block(r->bch_regs, true); + if (ret) + goto err_out; + + /* Configure layout 0. */ + writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) + | BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) + | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) + | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size), + r->bch_regs + HW_BCH_FLASH0LAYOUT0); + + writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) + | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) + | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size), + r->bch_regs + HW_BCH_FLASH0LAYOUT1); + + /* Set *all* chip selects to use layout 0. */ + writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT); + + /* Enable interrupts. */ + writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, + r->bch_regs + HW_BCH_CTRL_SET); + + clk_disable(r->clock); + return 0; +err_out: + return ret; +} + +/* Converts time in nanoseconds to cycles. */ +static unsigned int ns_to_cycles(unsigned int time, + unsigned int period, unsigned int min) +{ + unsigned int k; + + k = (time + period - 1) / period; + return max(k, min); +} + +/* Apply timing to current hardware conditions. */ +static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, + struct gpmi_nfc_hardware_timing *hw) +{ + struct gpmi_nand_platform_data *pdata = this->pdata; + struct timing_threshod *nfc = &timing_default_threshold; + struct nand_chip *nand = &this->nand; + struct nand_timing target = this->timing; + bool improved_timing_is_available; + unsigned long clock_frequency_in_hz; + unsigned int clock_period_in_ns; + bool dll_use_half_periods; + unsigned int dll_delay_shift; + unsigned int max_sample_delay_in_ns; + unsigned int address_setup_in_cycles; + unsigned int data_setup_in_ns; + unsigned int data_setup_in_cycles; + unsigned int data_hold_in_cycles; + int ideal_sample_delay_in_ns; + unsigned int sample_delay_factor; + int tEYE; + unsigned int min_prop_delay_in_ns = pdata->min_prop_delay_in_ns; + unsigned int max_prop_delay_in_ns = pdata->max_prop_delay_in_ns; + + /* + * If there are multiple chips, we need to relax the timings to allow + * for signal distortion due to higher capacitance. + */ + if (nand->numchips > 2) { + target.data_setup_in_ns += 10; + target.data_hold_in_ns += 10; + target.address_setup_in_ns += 10; + } else if (nand->numchips > 1) { + target.data_setup_in_ns += 5; + target.data_hold_in_ns += 5; + target.address_setup_in_ns += 5; + } + + /* Check if improved timing information is available. */ + improved_timing_is_available = + (target.tREA_in_ns >= 0) && + (target.tRLOH_in_ns >= 0) && + (target.tRHOH_in_ns >= 0) ; + + /* Inspect the clock. */ + clock_frequency_in_hz = nfc->clock_frequency_in_hz; + clock_period_in_ns = 1000000000 / clock_frequency_in_hz; + + /* + * The NFC quantizes setup and hold parameters in terms of clock cycles. + * Here, we quantize the setup and hold timing parameters to the + * next-highest clock period to make sure we apply at least the + * specified times. + * + * For data setup and data hold, the hardware interprets a value of zero + * as the largest possible delay. This is not what's intended by a zero + * in the input parameter, so we impose a minimum of one cycle. + */ + data_setup_in_cycles = ns_to_cycles(target.data_setup_in_ns, + clock_period_in_ns, 1); + data_hold_in_cycles = ns_to_cycles(target.data_hold_in_ns, + clock_period_in_ns, 1); + address_setup_in_cycles = ns_to_cycles(target.address_setup_in_ns, + clock_period_in_ns, 0); + + /* + * The clock's period affects the sample delay in a number of ways: + * + * (1) The NFC HAL tells us the maximum clock period the sample delay + * DLL can tolerate. If the clock period is greater than half that + * maximum, we must configure the DLL to be driven by half periods. + * + * (2) We need to convert from an ideal sample delay, in ns, to a + * "sample delay factor," which the NFC uses. This factor depends on + * whether we're driving the DLL with full or half periods. + * Paraphrasing the reference manual: + * + * AD = SDF x 0.125 x RP + * + * where: + * + * AD is the applied delay, in ns. + * SDF is the sample delay factor, which is dimensionless. + * RP is the reference period, in ns, which is a full clock period + * if the DLL is being driven by full periods, or half that if + * the DLL is being driven by half periods. + * + * Let's re-arrange this in a way that's more useful to us: + * + * 8 + * SDF = AD x ---- + * RP + * + * The reference period is either the clock period or half that, so this + * is: + * + * 8 AD x DDF + * SDF = AD x ----- = -------- + * f x P P + * + * where: + * + * f is 1 or 1/2, depending on how we're driving the DLL. + * P is the clock period. + * DDF is the DLL Delay Factor, a dimensionless value that + * incorporates all the constants in the conversion. + * + * DDF will be either 8 or 16, both of which are powers of two. We can + * reduce the cost of this conversion by using bit shifts instead of + * multiplication or division. Thus: + * + * AD << DDS + * SDF = --------- + * P + * + * or + * + * AD = (SDF >> DDS) x P + * + * where: + * + * DDS is the DLL Delay Shift, the logarithm to base 2 of the DDF. + */ + if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) { + dll_use_half_periods = true; + dll_delay_shift = 3 + 1; + } else { + dll_use_half_periods = false; + dll_delay_shift = 3; + } + + /* + * Compute the maximum sample delay the NFC allows, under current + * conditions. If the clock is running too slowly, no sample delay is + * possible. + */ + if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns) + max_sample_delay_in_ns = 0; + else { + /* + * Compute the delay implied by the largest sample delay factor + * the NFC allows. + */ + max_sample_delay_in_ns = + (nfc->max_sample_delay_factor * clock_period_in_ns) >> + dll_delay_shift; + + /* + * Check if the implied sample delay larger than the NFC + * actually allows. + */ + if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns) + max_sample_delay_in_ns = nfc->max_dll_delay_in_ns; + } + + /* + * Check if improved timing information is available. If not, we have to + * use a less-sophisticated algorithm. + */ + if (!improved_timing_is_available) { + /* + * Fold the read setup time required by the NFC into the ideal + * sample delay. + */ + ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns + + nfc->internal_data_setup_in_ns; + + /* + * The ideal sample delay may be greater than the maximum + * allowed by the NFC. If so, we can trade off sample delay time + * for more data setup time. + * + * In each iteration of the following loop, we add a cycle to + * the data setup time and subtract a corresponding amount from + * the sample delay until we've satisified the constraints or + * can't do any better. + */ + while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + + data_setup_in_cycles++; + ideal_sample_delay_in_ns -= clock_period_in_ns; + + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + + } + + /* + * Compute the sample delay factor that corresponds most closely + * to the ideal sample delay. If the result is too large for the + * NFC, use the maximum value. + * + * Notice that we use the ns_to_cycles function to compute the + * sample delay factor. We do this because the form of the + * computation is the same as that for calculating cycles. + */ + sample_delay_factor = + ns_to_cycles( + ideal_sample_delay_in_ns << dll_delay_shift, + clock_period_in_ns, 0); + + if (sample_delay_factor > nfc->max_sample_delay_factor) + sample_delay_factor = nfc->max_sample_delay_factor; + + /* Skip to the part where we return our results. */ + goto return_results; + } + + /* + * If control arrives here, we have more detailed timing information, + * so we can use a better algorithm. + */ + + /* + * Fold the read setup time required by the NFC into the maximum + * propagation delay. + */ + max_prop_delay_in_ns += nfc->internal_data_setup_in_ns; + + /* + * Earlier, we computed the number of clock cycles required to satisfy + * the data setup time. Now, we need to know the actual nanoseconds. + */ + data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles; + + /* + * Compute tEYE, the width of the data eye when reading from the NAND + * Flash. The eye width is fundamentally determined by the data setup + * time, perturbed by propagation delays and some characteristics of the + * NAND Flash device. + * + * start of the eye = max_prop_delay + tREA + * end of the eye = min_prop_delay + tRHOH + data_setup + */ + tEYE = (int)min_prop_delay_in_ns + (int)target.tRHOH_in_ns + + (int)data_setup_in_ns; + + tEYE -= (int)max_prop_delay_in_ns + (int)target.tREA_in_ns; + + /* + * The eye must be open. If it's not, we can try to open it by + * increasing its main forcer, the data setup time. + * + * In each iteration of the following loop, we increase the data setup + * time by a single clock cycle. We do this until either the eye is + * open or we run into NFC limits. + */ + while ((tEYE <= 0) && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + /* Give a cycle to data setup. */ + data_setup_in_cycles++; + /* Synchronize the data setup time with the cycles. */ + data_setup_in_ns += clock_period_in_ns; + /* Adjust tEYE accordingly. */ + tEYE += clock_period_in_ns; + } + + /* + * When control arrives here, the eye is open. The ideal time to sample + * the data is in the center of the eye: + * + * end of the eye + start of the eye + * --------------------------------- - data_setup + * 2 + * + * After some algebra, this simplifies to the code immediately below. + */ + ideal_sample_delay_in_ns = + ((int)max_prop_delay_in_ns + + (int)target.tREA_in_ns + + (int)min_prop_delay_in_ns + + (int)target.tRHOH_in_ns - + (int)data_setup_in_ns) >> 1; + + /* + * The following figure illustrates some aspects of a NAND Flash read: + * + * + * __ _____________________________________ + * RDN \_________________/ + * + * <---- tEYE -----> + * /-----------------\ + * Read Data ----------------------------< >--------- + * \-----------------/ + * ^ ^ ^ ^ + * | | | | + * |<--Data Setup -->|<--Delay Time -->| | + * | | | | + * | | | + * | |<-- Quantized Delay Time -->| + * | | | + * + * + * We have some issues we must now address: + * + * (1) The *ideal* sample delay time must not be negative. If it is, we + * jam it to zero. + * + * (2) The *ideal* sample delay time must not be greater than that + * allowed by the NFC. If it is, we can increase the data setup + * time, which will reduce the delay between the end of the data + * setup and the center of the eye. It will also make the eye + * larger, which might help with the next issue... + * + * (3) The *quantized* sample delay time must not fall either before the + * eye opens or after it closes (the latter is the problem + * illustrated in the above figure). + */ + + /* Jam a negative ideal sample delay to zero. */ + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + + /* + * Extend the data setup as needed to reduce the ideal sample delay + * below the maximum permitted by the NFC. + */ + while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + + /* Give a cycle to data setup. */ + data_setup_in_cycles++; + /* Synchronize the data setup time with the cycles. */ + data_setup_in_ns += clock_period_in_ns; + /* Adjust tEYE accordingly. */ + tEYE += clock_period_in_ns; + + /* + * Decrease the ideal sample delay by one half cycle, to keep it + * in the middle of the eye. + */ + ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1); + + /* Jam a negative ideal sample delay to zero. */ + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + } + + /* + * Compute the sample delay factor that corresponds to the ideal sample + * delay. If the result is too large, then use the maximum allowed + * value. + * + * Notice that we use the ns_to_cycles function to compute the sample + * delay factor. We do this because the form of the computation is the + * same as that for calculating cycles. + */ + sample_delay_factor = + ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift, + clock_period_in_ns, 0); + + if (sample_delay_factor > nfc->max_sample_delay_factor) + sample_delay_factor = nfc->max_sample_delay_factor; + + /* + * These macros conveniently encapsulate a computation we'll use to + * continuously evaluate whether or not the data sample delay is inside + * the eye. + */ + #define IDEAL_DELAY ((int) ideal_sample_delay_in_ns) + + #define QUANTIZED_DELAY \ + ((int) ((sample_delay_factor * clock_period_in_ns) >> \ + dll_delay_shift)) + + #define DELAY_ERROR (abs(QUANTIZED_DELAY - IDEAL_DELAY)) + + #define SAMPLE_IS_NOT_WITHIN_THE_EYE (DELAY_ERROR > (tEYE >> 1)) + + /* + * While the quantized sample time falls outside the eye, reduce the + * sample delay or extend the data setup to move the sampling point back + * toward the eye. Do not allow the number of data setup cycles to + * exceed the maximum allowed by the NFC. + */ + while (SAMPLE_IS_NOT_WITHIN_THE_EYE && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + /* + * If control arrives here, the quantized sample delay falls + * outside the eye. Check if it's before the eye opens, or after + * the eye closes. + */ + if (QUANTIZED_DELAY > IDEAL_DELAY) { + /* + * If control arrives here, the quantized sample delay + * falls after the eye closes. Decrease the quantized + * delay time and then go back to re-evaluate. + */ + if (sample_delay_factor != 0) + sample_delay_factor--; + continue; + } + + /* + * If control arrives here, the quantized sample delay falls + * before the eye opens. Shift the sample point by increasing + * data setup time. This will also make the eye larger. + */ + + /* Give a cycle to data setup. */ + data_setup_in_cycles++; + /* Synchronize the data setup time with the cycles. */ + data_setup_in_ns += clock_period_in_ns; + /* Adjust tEYE accordingly. */ + tEYE += clock_period_in_ns; + + /* + * Decrease the ideal sample delay by one half cycle, to keep it + * in the middle of the eye. + */ + ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1); + + /* ...and one less period for the delay time. */ + ideal_sample_delay_in_ns -= clock_period_in_ns; + + /* Jam a negative ideal sample delay to zero. */ + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + + /* + * We have a new ideal sample delay, so re-compute the quantized + * delay. + */ + sample_delay_factor = + ns_to_cycles( + ideal_sample_delay_in_ns << dll_delay_shift, + clock_period_in_ns, 0); + + if (sample_delay_factor > nfc->max_sample_delay_factor) + sample_delay_factor = nfc->max_sample_delay_factor; + } + + /* Control arrives here when we're ready to return our results. */ +return_results: + hw->data_setup_in_cycles = data_setup_in_cycles; + hw->data_hold_in_cycles = data_hold_in_cycles; + hw->address_setup_in_cycles = address_setup_in_cycles; + hw->use_half_periods = dll_use_half_periods; + hw->sample_delay_factor = sample_delay_factor; + + /* Return success. */ + return 0; +} + +/* Begin the I/O */ +void gpmi_begin(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + struct timing_threshod *nfc = &timing_default_threshold; + unsigned char *gpmi_regs = r->gpmi_regs; + unsigned int clock_period_in_ns; + uint32_t reg; + unsigned int dll_wait_time_in_us; + struct gpmi_nfc_hardware_timing hw; + int ret; + + /* Enable the clock. */ + ret = clk_enable(r->clock); + if (ret) { + pr_err("We failed in enable the clk\n"); + goto err_out; + } + + /* set ready/busy timeout */ + writel(0x500 << BP_GPMI_TIMING1_BUSY_TIMEOUT, + gpmi_regs + HW_GPMI_TIMING1); + + /* Get the timing information we need. */ + nfc->clock_frequency_in_hz = clk_get_rate(r->clock); + clock_period_in_ns = 1000000000 / nfc->clock_frequency_in_hz; + + gpmi_nfc_compute_hardware_timing(this, &hw); + + /* Set up all the simple timing parameters. */ + reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | + BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles) | + BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles) ; + + writel(reg, gpmi_regs + HW_GPMI_TIMING0); + + /* + * DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. + */ + writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR); + + /* Clear out the DLL control fields. */ + writel(BM_GPMI_CTRL1_RDN_DELAY, gpmi_regs + HW_GPMI_CTRL1_CLR); + writel(BM_GPMI_CTRL1_HALF_PERIOD, gpmi_regs + HW_GPMI_CTRL1_CLR); + + /* If no sample delay is called for, return immediately. */ + if (!hw.sample_delay_factor) + return; + + /* Configure the HALF_PERIOD flag. */ + if (hw.use_half_periods) + writel(BM_GPMI_CTRL1_HALF_PERIOD, + gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Set the delay factor. */ + writel(BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor), + gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Enable the DLL. */ + writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET); + + /* + * After we enable the GPMI DLL, we have to wait 64 clock cycles before + * we can use the GPMI. + * + * Calculate the amount of time we need to wait, in microseconds. + */ + dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000; + + if (!dll_wait_time_in_us) + dll_wait_time_in_us = 1; + + /* Wait for the DLL to settle. */ + udelay(dll_wait_time_in_us); + +err_out: + return; +} + +void gpmi_end(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + clk_disable(r->clock); +} + +/* Clears a BCH interrupt. */ +void gpmi_clear_bch(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR); +} + +/* Returns the Ready/Busy status of the given chip. */ +int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip) +{ + struct resources *r = &this->resources; + uint32_t mask = 0; + uint32_t reg = 0; + + if (GPMI_IS_MX23(this)) { + mask = MX23_BM_GPMI_DEBUG_READY0 << chip; + reg = readl(r->gpmi_regs + HW_GPMI_DEBUG); + } else if (GPMI_IS_MX28(this)) { + mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); + reg = readl(r->gpmi_regs + HW_GPMI_STAT); + } else + pr_err("unknow arch.\n"); + return reg & mask; +} + +static inline void set_dma_type(struct gpmi_nand_data *this, + enum dma_ops_type type) +{ + this->last_dma_type = this->dma_type; + this->dma_type = type; +} + +int gpmi_send_command(struct gpmi_nand_data *this) +{ + struct dma_chan *channel = get_dma_chan(this); + struct dma_async_tx_descriptor *desc; + struct scatterlist *sgl; + int chip = this->current_chip; + u32 pio[3]; + + /* [1] send out the PIO words */ + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE) + | BM_GPMI_CTRL0_ADDRESS_INCREMENT + | BF_GPMI_CTRL0_XFER_COUNT(this->command_length); + pio[1] = pio[2] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] send out the COMMAND + ADDRESS string stored in @buffer */ + sgl = &this->cmd_sgl; + + sg_init_one(sgl, this->cmd_buffer, this->command_length); + dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE); + desc = channel->device->device_prep_slave_sg(channel, + sgl, 1, DMA_TO_DEVICE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + + /* [3] submit the DMA */ + set_dma_type(this, DMA_FOR_COMMAND); + return start_dma_without_bch_irq(this, desc); +} + +int gpmi_send_data(struct gpmi_nand_data *this) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + uint32_t command_mode; + uint32_t address; + u32 pio[2]; + + /* [1] PIO */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(this->upper_len); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] send DMA request */ + prepare_data_dma(this, DMA_TO_DEVICE); + desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, + 1, DMA_TO_DEVICE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + /* [3] submit the DMA */ + set_dma_type(this, DMA_FOR_WRITE_DATA); + return start_dma_without_bch_irq(this, desc); +} + +int gpmi_read_data(struct gpmi_nand_data *this) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + u32 pio[2]; + + /* [1] : send PIO */ + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) + | BF_GPMI_CTRL0_XFER_COUNT(this->upper_len); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] : send DMA request */ + prepare_data_dma(this, DMA_FROM_DEVICE); + desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, + 1, DMA_FROM_DEVICE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + + /* [3] : submit the DMA */ + set_dma_type(this, DMA_FOR_READ_DATA); + return start_dma_without_bch_irq(this, desc); +} + +int gpmi_send_page(struct gpmi_nand_data *this, + dma_addr_t payload, dma_addr_t auxiliary) +{ + struct bch_geometry *geo = &this->bch_geometry; + uint32_t command_mode; + uint32_t address; + uint32_t ecc_command; + uint32_t buffer_mask; + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + u32 pio[6]; + + /* A DMA descriptor that does an ECC page read. */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE; + buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE | + BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(0); + pio[1] = 0; + pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC + | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) + | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask); + pio[3] = geo->page_size; + pio[4] = payload; + pio[5] = auxiliary; + + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE); + return start_dma_with_bch_irq(this, desc); +} + +int gpmi_read_page(struct gpmi_nand_data *this, + dma_addr_t payload, dma_addr_t auxiliary) +{ + struct bch_geometry *geo = &this->bch_geometry; + uint32_t command_mode; + uint32_t address; + uint32_t ecc_command; + uint32_t buffer_mask; + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + u32 pio[6]; + + /* [1] Wait for the chip to report ready. */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(0); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, 2, DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] Enable the BCH block and read. */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE; + buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE + | BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); + + pio[1] = 0; + pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC + | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) + | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask); + pio[3] = geo->page_size; + pio[4] = payload; + pio[5] = auxiliary; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + + /* [3] Disable the BCH block */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, 2, DMA_NONE, 1); + if (!desc) { + pr_err("step 3 error\n"); + return -1; + } + + /* [4] submit the DMA */ + set_dma_type(this, DMA_FOR_READ_ECC_PAGE); + return start_dma_with_bch_irq(this, desc); +} diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c new file mode 100644 index 000000000000..071b63420f0e --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -0,0 +1,1619 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/mtd/gpmi-nand.h> +#include <linux/mtd/partitions.h> + +#include "gpmi-nand.h" + +/* add our owner bbt descriptor */ +static uint8_t scan_ff_pattern[] = { 0xff }; +static struct nand_bbt_descr gpmi_bbt_descr = { + .options = 0, + .offs = 0, + .len = 1, + .pattern = scan_ff_pattern +}; + +/* We will use all the (page + OOB). */ +static struct nand_ecclayout gpmi_hw_ecclayout = { + .eccbytes = 0, + .eccpos = { 0, }, + .oobfree = { {.offset = 0, .length = 0} } +}; + +static irqreturn_t bch_irq(int irq, void *cookie) +{ + struct gpmi_nand_data *this = cookie; + + gpmi_clear_bch(this); + complete(&this->bch_done); + return IRQ_HANDLED; +} + +/* + * Calculate the ECC strength by hand: + * E : The ECC strength. + * G : the length of Galois Field. + * N : The chunk count of per page. + * O : the oobsize of the NAND chip. + * M : the metasize of per page. + * + * The formula is : + * E * G * N + * ------------ <= (O - M) + * 8 + * + * So, we get E by: + * (O - M) * 8 + * E <= ------------- + * G * N + */ +static inline int get_ecc_strength(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + struct mtd_info *mtd = &this->mtd; + int ecc_strength; + + ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8) + / (geo->gf_len * geo->ecc_chunk_count); + + /* We need the minor even number. */ + return round_down(ecc_strength, 2); +} + +int common_nfc_set_geometry(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + struct mtd_info *mtd = &this->mtd; + unsigned int metadata_size; + unsigned int status_size; + unsigned int block_mark_bit_offset; + + /* + * The size of the metadata can be changed, though we set it to 10 + * bytes now. But it can't be too large, because we have to save + * enough space for BCH. + */ + geo->metadata_size = 10; + + /* The default for the length of Galois Field. */ + geo->gf_len = 13; + + /* The default for chunk size. There is no oobsize greater then 512. */ + geo->ecc_chunk_size = 512; + while (geo->ecc_chunk_size < mtd->oobsize) + geo->ecc_chunk_size *= 2; /* keep C >= O */ + + geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size; + + /* We use the same ECC strength for all chunks. */ + geo->ecc_strength = get_ecc_strength(this); + if (!geo->ecc_strength) { + pr_err("We get a wrong ECC strength.\n"); + return -EINVAL; + } + + geo->page_size = mtd->writesize + mtd->oobsize; + geo->payload_size = mtd->writesize; + + /* + * The auxiliary buffer contains the metadata and the ECC status. The + * metadata is padded to the nearest 32-bit boundary. The ECC status + * contains one byte for every ECC chunk, and is also padded to the + * nearest 32-bit boundary. + */ + metadata_size = ALIGN(geo->metadata_size, 4); + status_size = ALIGN(geo->ecc_chunk_count, 4); + + geo->auxiliary_size = metadata_size + status_size; + geo->auxiliary_status_offset = metadata_size; + + if (!this->swap_block_mark) + return 0; + + /* + * We need to compute the byte and bit offsets of + * the physical block mark within the ECC-based view of the page. + * + * NAND chip with 2K page shows below: + * (Block Mark) + * | | + * | D | + * |<---->| + * V V + * +---+----------+-+----------+-+----------+-+----------+-+ + * | M | data |E| data |E| data |E| data |E| + * +---+----------+-+----------+-+----------+-+----------+-+ + * + * The position of block mark moves forward in the ECC-based view + * of page, and the delta is: + * + * E * G * (N - 1) + * D = (---------------- + M) + * 8 + * + * With the formula to compute the ECC strength, and the condition + * : C >= O (C is the ecc chunk size) + * + * It's easy to deduce to the following result: + * + * E * G (O - M) C - M C - M + * ----------- <= ------- <= -------- < --------- + * 8 N N (N - 1) + * + * So, we get: + * + * E * G * (N - 1) + * D = (---------------- + M) < C + * 8 + * + * The above inequality means the position of block mark + * within the ECC-based view of the page is still in the data chunk, + * and it's NOT in the ECC bits of the chunk. + * + * Use the following to compute the bit position of the + * physical block mark within the ECC-based view of the page: + * (page_size - D) * 8 + * + * --Huang Shijie + */ + block_mark_bit_offset = mtd->writesize * 8 - + (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1) + + geo->metadata_size * 8); + + geo->block_mark_byte_offset = block_mark_bit_offset / 8; + geo->block_mark_bit_offset = block_mark_bit_offset % 8; + return 0; +} + +struct dma_chan *get_dma_chan(struct gpmi_nand_data *this) +{ + int chipnr = this->current_chip; + + return this->dma_chans[chipnr]; +} + +/* Can we use the upper's buffer directly for DMA? */ +void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) +{ + struct scatterlist *sgl = &this->data_sgl; + int ret; + + this->direct_dma_map_ok = true; + + /* first try to map the upper buffer directly */ + sg_init_one(sgl, this->upper_buf, this->upper_len); + ret = dma_map_sg(this->dev, sgl, 1, dr); + if (ret == 0) { + /* We have to use our own DMA buffer. */ + sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE); + + if (dr == DMA_TO_DEVICE) + memcpy(this->data_buffer_dma, this->upper_buf, + this->upper_len); + + ret = dma_map_sg(this->dev, sgl, 1, dr); + if (ret == 0) + pr_err("map failed.\n"); + + this->direct_dma_map_ok = false; + } +} + +/* This will be called after the DMA operation is finished. */ +static void dma_irq_callback(void *param) +{ + struct gpmi_nand_data *this = param; + struct completion *dma_c = &this->dma_done; + + complete(dma_c); + + switch (this->dma_type) { + case DMA_FOR_COMMAND: + dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE); + break; + + case DMA_FOR_READ_DATA: + dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE); + if (this->direct_dma_map_ok == false) + memcpy(this->upper_buf, this->data_buffer_dma, + this->upper_len); + break; + + case DMA_FOR_WRITE_DATA: + dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE); + break; + + case DMA_FOR_READ_ECC_PAGE: + case DMA_FOR_WRITE_ECC_PAGE: + /* We have to wait the BCH interrupt to finish. */ + break; + + default: + pr_err("in wrong DMA operation.\n"); + } +} + +int start_dma_without_bch_irq(struct gpmi_nand_data *this, + struct dma_async_tx_descriptor *desc) +{ + struct completion *dma_c = &this->dma_done; + int err; + + init_completion(dma_c); + + desc->callback = dma_irq_callback; + desc->callback_param = this; + dmaengine_submit(desc); + + /* Wait for the interrupt from the DMA block. */ + err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); + if (!err) { + pr_err("DMA timeout, last DMA :%d\n", this->last_dma_type); + gpmi_dump_info(this); + return -ETIMEDOUT; + } + return 0; +} + +/* + * This function is used in BCH reading or BCH writing pages. + * It will wait for the BCH interrupt as long as ONE second. + * Actually, we must wait for two interrupts : + * [1] firstly the DMA interrupt and + * [2] secondly the BCH interrupt. + */ +int start_dma_with_bch_irq(struct gpmi_nand_data *this, + struct dma_async_tx_descriptor *desc) +{ + struct completion *bch_c = &this->bch_done; + int err; + + /* Prepare to receive an interrupt from the BCH block. */ + init_completion(bch_c); + + /* start the DMA */ + start_dma_without_bch_irq(this, desc); + + /* Wait for the interrupt from the BCH block. */ + err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); + if (!err) { + pr_err("BCH timeout, last DMA :%d\n", this->last_dma_type); + gpmi_dump_info(this); + return -ETIMEDOUT; + } + return 0; +} + +static int __devinit +acquire_register_block(struct gpmi_nand_data *this, const char *res_name) +{ + struct platform_device *pdev = this->pdev; + struct resources *res = &this->resources; + struct resource *r; + void *p; + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); + if (!r) { + pr_err("Can't get resource for %s\n", res_name); + return -ENXIO; + } + + p = ioremap(r->start, resource_size(r)); + if (!p) { + pr_err("Can't remap %s\n", res_name); + return -ENOMEM; + } + + if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME)) + res->gpmi_regs = p; + else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME)) + res->bch_regs = p; + else + pr_err("unknown resource name : %s\n", res_name); + + return 0; +} + +static void release_register_block(struct gpmi_nand_data *this) +{ + struct resources *res = &this->resources; + if (res->gpmi_regs) + iounmap(res->gpmi_regs); + if (res->bch_regs) + iounmap(res->bch_regs); + res->gpmi_regs = NULL; + res->bch_regs = NULL; +} + +static int __devinit +acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) +{ + struct platform_device *pdev = this->pdev; + struct resources *res = &this->resources; + const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME; + struct resource *r; + int err; + + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); + if (!r) { + pr_err("Can't get resource for %s\n", res_name); + return -ENXIO; + } + + err = request_irq(r->start, irq_h, 0, res_name, this); + if (err) { + pr_err("Can't own %s\n", res_name); + return err; + } + + res->bch_low_interrupt = r->start; + res->bch_high_interrupt = r->end; + return 0; +} + +static void release_bch_irq(struct gpmi_nand_data *this) +{ + struct resources *res = &this->resources; + int i = res->bch_low_interrupt; + + for (; i <= res->bch_high_interrupt; i++) + free_irq(i, this); +} + +static bool gpmi_dma_filter(struct dma_chan *chan, void *param) +{ + struct gpmi_nand_data *this = param; + struct resource *r = this->private; + + if (!mxs_dma_is_apbh(chan)) + return false; + /* + * only catch the GPMI dma channels : + * for mx23 : MX23_DMA_GPMI0 ~ MX23_DMA_GPMI3 + * (These four channels share the same IRQ!) + * + * for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7 + * (These eight channels share the same IRQ!) + */ + if (r->start <= chan->chan_id && chan->chan_id <= r->end) { + chan->private = &this->dma_data; + return true; + } + return false; +} + +static void release_dma_channels(struct gpmi_nand_data *this) +{ + unsigned int i; + for (i = 0; i < DMA_CHANS; i++) + if (this->dma_chans[i]) { + dma_release_channel(this->dma_chans[i]); + this->dma_chans[i] = NULL; + } +} + +static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) +{ + struct platform_device *pdev = this->pdev; + struct gpmi_nand_platform_data *pdata = this->pdata; + struct resources *res = &this->resources; + struct resource *r, *r_dma; + unsigned int i; + + r = platform_get_resource_byname(pdev, IORESOURCE_DMA, + GPMI_NAND_DMA_CHANNELS_RES_NAME); + r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ, + GPMI_NAND_DMA_INTERRUPT_RES_NAME); + if (!r || !r_dma) { + pr_err("Can't get resource for DMA\n"); + return -ENXIO; + } + + /* used in gpmi_dma_filter() */ + this->private = r; + + for (i = r->start; i <= r->end; i++) { + struct dma_chan *dma_chan; + dma_cap_mask_t mask; + + if (i - r->start >= pdata->max_chip_count) + break; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* get the DMA interrupt */ + if (r_dma->start == r_dma->end) { + /* only register the first. */ + if (i == r->start) + this->dma_data.chan_irq = r_dma->start; + else + this->dma_data.chan_irq = NO_IRQ; + } else + this->dma_data.chan_irq = r_dma->start + (i - r->start); + + dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); + if (!dma_chan) + goto acquire_err; + + /* fill the first empty item */ + this->dma_chans[i - r->start] = dma_chan; + } + + res->dma_low_channel = r->start; + res->dma_high_channel = i; + return 0; + +acquire_err: + pr_err("Can't acquire DMA channel %u\n", i); + release_dma_channels(this); + return -EINVAL; +} + +static int __devinit acquire_resources(struct gpmi_nand_data *this) +{ + struct resources *res = &this->resources; + int ret; + + ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME); + if (ret) + goto exit_regs; + + ret = acquire_register_block(this, GPMI_NAND_BCH_REGS_ADDR_RES_NAME); + if (ret) + goto exit_regs; + + ret = acquire_bch_irq(this, bch_irq); + if (ret) + goto exit_regs; + + ret = acquire_dma_channels(this); + if (ret) + goto exit_dma_channels; + + res->clock = clk_get(&this->pdev->dev, NULL); + if (IS_ERR(res->clock)) { + pr_err("can not get the clock\n"); + ret = -ENOENT; + goto exit_clock; + } + return 0; + +exit_clock: + release_dma_channels(this); +exit_dma_channels: + release_bch_irq(this); +exit_regs: + release_register_block(this); + return ret; +} + +static void release_resources(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + + clk_put(r->clock); + release_register_block(this); + release_bch_irq(this); + release_dma_channels(this); +} + +static int __devinit init_hardware(struct gpmi_nand_data *this) +{ + int ret; + + /* + * This structure contains the "safe" GPMI timing that should succeed + * with any NAND Flash device + * (although, with less-than-optimal performance). + */ + struct nand_timing safe_timing = { + .data_setup_in_ns = 80, + .data_hold_in_ns = 60, + .address_setup_in_ns = 25, + .gpmi_sample_delay_in_ns = 6, + .tREA_in_ns = -1, + .tRLOH_in_ns = -1, + .tRHOH_in_ns = -1, + }; + + /* Initialize the hardwares. */ + ret = gpmi_init(this); + if (ret) + return ret; + + this->timing = safe_timing; + return 0; +} + +static int read_page_prepare(struct gpmi_nand_data *this, + void *destination, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + void **use_virt, dma_addr_t *use_phys) +{ + struct device *dev = this->dev; + + if (virt_addr_valid(destination)) { + dma_addr_t dest_phys; + + dest_phys = dma_map_single(dev, destination, + length, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, dest_phys)) { + if (alt_size < length) { + pr_err("Alternate buffer is too small\n"); + return -ENOMEM; + } + goto map_failed; + } + *use_virt = destination; + *use_phys = dest_phys; + this->direct_dma_map_ok = true; + return 0; + } + +map_failed: + *use_virt = alt_virt; + *use_phys = alt_phys; + this->direct_dma_map_ok = false; + return 0; +} + +static inline void read_page_end(struct gpmi_nand_data *this, + void *destination, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + void *used_virt, dma_addr_t used_phys) +{ + if (this->direct_dma_map_ok) + dma_unmap_single(this->dev, used_phys, length, DMA_FROM_DEVICE); +} + +static inline void read_page_swap_end(struct gpmi_nand_data *this, + void *destination, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + void *used_virt, dma_addr_t used_phys) +{ + if (!this->direct_dma_map_ok) + memcpy(destination, alt_virt, length); +} + +static int send_page_prepare(struct gpmi_nand_data *this, + const void *source, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + const void **use_virt, dma_addr_t *use_phys) +{ + struct device *dev = this->dev; + + if (virt_addr_valid(source)) { + dma_addr_t source_phys; + + source_phys = dma_map_single(dev, (void *)source, length, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, source_phys)) { + if (alt_size < length) { + pr_err("Alternate buffer is too small\n"); + return -ENOMEM; + } + goto map_failed; + } + *use_virt = source; + *use_phys = source_phys; + return 0; + } +map_failed: + /* + * Copy the content of the source buffer into the alternate + * buffer and set up the return values accordingly. + */ + memcpy(alt_virt, source, length); + + *use_virt = alt_virt; + *use_phys = alt_phys; + return 0; +} + +static void send_page_end(struct gpmi_nand_data *this, + const void *source, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + const void *used_virt, dma_addr_t used_phys) +{ + struct device *dev = this->dev; + if (used_virt == source) + dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE); +} + +static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) +{ + struct device *dev = this->dev; + + if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt)) + dma_free_coherent(dev, this->page_buffer_size, + this->page_buffer_virt, + this->page_buffer_phys); + kfree(this->cmd_buffer); + kfree(this->data_buffer_dma); + + this->cmd_buffer = NULL; + this->data_buffer_dma = NULL; + this->page_buffer_virt = NULL; + this->page_buffer_size = 0; +} + +/* Allocate the DMA buffers */ +static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + struct device *dev = this->dev; + + /* [1] Allocate a command buffer. PAGE_SIZE is enough. */ + this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA); + if (this->cmd_buffer == NULL) + goto error_alloc; + + /* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */ + this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA); + if (this->data_buffer_dma == NULL) + goto error_alloc; + + /* + * [3] Allocate the page buffer. + * + * Both the payload buffer and the auxiliary buffer must appear on + * 32-bit boundaries. We presume the size of the payload buffer is a + * power of two and is much larger than four, which guarantees the + * auxiliary buffer will appear on a 32-bit boundary. + */ + this->page_buffer_size = geo->payload_size + geo->auxiliary_size; + this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size, + &this->page_buffer_phys, GFP_DMA); + if (!this->page_buffer_virt) + goto error_alloc; + + + /* Slice up the page buffer. */ + this->payload_virt = this->page_buffer_virt; + this->payload_phys = this->page_buffer_phys; + this->auxiliary_virt = this->payload_virt + geo->payload_size; + this->auxiliary_phys = this->payload_phys + geo->payload_size; + return 0; + +error_alloc: + gpmi_free_dma_buffer(this); + pr_err("allocate DMA buffer ret!!\n"); + return -ENOMEM; +} + +static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + int ret; + + /* + * Every operation begins with a command byte and a series of zero or + * more address bytes. These are distinguished by either the Address + * Latch Enable (ALE) or Command Latch Enable (CLE) signals being + * asserted. When MTD is ready to execute the command, it will deassert + * both latch enables. + * + * Rather than run a separate DMA operation for every single byte, we + * queue them up and run a single DMA operation for the entire series + * of command and data bytes. NAND_CMD_NONE means the END of the queue. + */ + if ((ctrl & (NAND_ALE | NAND_CLE))) { + if (data != NAND_CMD_NONE) + this->cmd_buffer[this->command_length++] = data; + return; + } + + if (!this->command_length) + return; + + ret = gpmi_send_command(this); + if (ret) + pr_err("Chip: %u, Error %d\n", this->current_chip, ret); + + this->command_length = 0; +} + +static int gpmi_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + return gpmi_is_ready(this, this->current_chip); +} + +static void gpmi_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + if ((this->current_chip < 0) && (chipnr >= 0)) + gpmi_begin(this); + else if ((this->current_chip >= 0) && (chipnr < 0)) + gpmi_end(this); + + this->current_chip = chipnr; +} + +static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + pr_debug("len is %d\n", len); + this->upper_buf = buf; + this->upper_len = len; + + gpmi_read_data(this); +} + +static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + pr_debug("len is %d\n", len); + this->upper_buf = (uint8_t *)buf; + this->upper_len = len; + + gpmi_send_data(this); +} + +static uint8_t gpmi_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + uint8_t *buf = this->data_buffer_dma; + + gpmi_read_buf(mtd, buf, 1); + return buf[0]; +} + +/* + * Handles block mark swapping. + * It can be called in swapping the block mark, or swapping it back, + * because the the operations are the same. + */ +static void block_mark_swapping(struct gpmi_nand_data *this, + void *payload, void *auxiliary) +{ + struct bch_geometry *nfc_geo = &this->bch_geometry; + unsigned char *p; + unsigned char *a; + unsigned int bit; + unsigned char mask; + unsigned char from_data; + unsigned char from_oob; + + if (!this->swap_block_mark) + return; + + /* + * If control arrives here, we're swapping. Make some convenience + * variables. + */ + bit = nfc_geo->block_mark_bit_offset; + p = payload + nfc_geo->block_mark_byte_offset; + a = auxiliary; + + /* + * Get the byte from the data area that overlays the block mark. Since + * the ECC engine applies its own view to the bits in the page, the + * physical block mark won't (in general) appear on a byte boundary in + * the data. + */ + from_data = (p[0] >> bit) | (p[1] << (8 - bit)); + + /* Get the byte from the OOB. */ + from_oob = a[0]; + + /* Swap them. */ + a[0] = from_data; + + mask = (0x1 << bit) - 1; + p[0] = (p[0] & mask) | (from_oob << bit); + + mask = ~0 << bit; + p[1] = (p[1] & mask) | (from_oob >> (8 - bit)); +} + +static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + void *payload_virt; + dma_addr_t payload_phys; + void *auxiliary_virt; + dma_addr_t auxiliary_phys; + unsigned int i; + unsigned char *status; + unsigned int failed; + unsigned int corrected; + int ret; + + pr_debug("page number is : %d\n", page); + ret = read_page_prepare(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + &payload_virt, &payload_phys); + if (ret) { + pr_err("Inadequate DMA buffer\n"); + ret = -ENOMEM; + return ret; + } + auxiliary_virt = this->auxiliary_virt; + auxiliary_phys = this->auxiliary_phys; + + /* go! */ + ret = gpmi_read_page(this, payload_phys, auxiliary_phys); + read_page_end(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + payload_virt, payload_phys); + if (ret) { + pr_err("Error in ECC-based read: %d\n", ret); + goto exit_nfc; + } + + /* handle the block mark swapping */ + block_mark_swapping(this, payload_virt, auxiliary_virt); + + /* Loop over status bytes, accumulating ECC status. */ + failed = 0; + corrected = 0; + status = auxiliary_virt + nfc_geo->auxiliary_status_offset; + + for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) { + if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED)) + continue; + + if (*status == STATUS_UNCORRECTABLE) { + failed++; + continue; + } + corrected += *status; + } + + /* + * Propagate ECC status to the owning MTD only when failed or + * corrected times nearly reaches our ECC correction threshold. + */ + if (failed || corrected >= (nfc_geo->ecc_strength - 1)) { + mtd->ecc_stats.failed += failed; + mtd->ecc_stats.corrected += corrected; + } + + /* + * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() for + * details about our policy for delivering the OOB. + * + * We fill the caller's buffer with set bits, and then copy the block + * mark to th caller's buffer. Note that, if block mark swapping was + * necessary, it has already been done, so we can rely on the first + * byte of the auxiliary buffer to contain the block mark. + */ + memset(chip->oob_poi, ~0, mtd->oobsize); + chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; + + read_page_swap_end(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + payload_virt, payload_phys); +exit_nfc: + return ret; +} + +static void gpmi_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + const void *payload_virt; + dma_addr_t payload_phys; + const void *auxiliary_virt; + dma_addr_t auxiliary_phys; + int ret; + + pr_debug("ecc write page.\n"); + if (this->swap_block_mark) { + /* + * If control arrives here, we're doing block mark swapping. + * Since we can't modify the caller's buffers, we must copy them + * into our own. + */ + memcpy(this->payload_virt, buf, mtd->writesize); + payload_virt = this->payload_virt; + payload_phys = this->payload_phys; + + memcpy(this->auxiliary_virt, chip->oob_poi, + nfc_geo->auxiliary_size); + auxiliary_virt = this->auxiliary_virt; + auxiliary_phys = this->auxiliary_phys; + + /* Handle block mark swapping. */ + block_mark_swapping(this, + (void *) payload_virt, (void *) auxiliary_virt); + } else { + /* + * If control arrives here, we're not doing block mark swapping, + * so we can to try and use the caller's buffers. + */ + ret = send_page_prepare(this, + buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + &payload_virt, &payload_phys); + if (ret) { + pr_err("Inadequate payload DMA buffer\n"); + return; + } + + ret = send_page_prepare(this, + chip->oob_poi, mtd->oobsize, + this->auxiliary_virt, this->auxiliary_phys, + nfc_geo->auxiliary_size, + &auxiliary_virt, &auxiliary_phys); + if (ret) { + pr_err("Inadequate auxiliary DMA buffer\n"); + goto exit_auxiliary; + } + } + + /* Ask the NFC. */ + ret = gpmi_send_page(this, payload_phys, auxiliary_phys); + if (ret) + pr_err("Error in ECC-based write: %d\n", ret); + + if (!this->swap_block_mark) { + send_page_end(this, chip->oob_poi, mtd->oobsize, + this->auxiliary_virt, this->auxiliary_phys, + nfc_geo->auxiliary_size, + auxiliary_virt, auxiliary_phys); +exit_auxiliary: + send_page_end(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + payload_virt, payload_phys); + } +} + +/* + * There are several places in this driver where we have to handle the OOB and + * block marks. This is the function where things are the most complicated, so + * this is where we try to explain it all. All the other places refer back to + * here. + * + * These are the rules, in order of decreasing importance: + * + * 1) Nothing the caller does can be allowed to imperil the block mark. + * + * 2) In read operations, the first byte of the OOB we return must reflect the + * true state of the block mark, no matter where that block mark appears in + * the physical page. + * + * 3) ECC-based read operations return an OOB full of set bits (since we never + * allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads + * return). + * + * 4) "Raw" read operations return a direct view of the physical bytes in the + * page, using the conventional definition of which bytes are data and which + * are OOB. This gives the caller a way to see the actual, physical bytes + * in the page, without the distortions applied by our ECC engine. + * + * + * What we do for this specific read operation depends on two questions: + * + * 1) Are we doing a "raw" read, or an ECC-based read? + * + * 2) Are we using block mark swapping or transcription? + * + * There are four cases, illustrated by the following Karnaugh map: + * + * | Raw | ECC-based | + * -------------+-------------------------+-------------------------+ + * | Read the conventional | | + * | OOB at the end of the | | + * Swapping | page and return it. It | | + * | contains exactly what | | + * | we want. | Read the block mark and | + * -------------+-------------------------+ return it in a buffer | + * | Read the conventional | full of set bits. | + * | OOB at the end of the | | + * | page and also the block | | + * Transcribing | mark in the metadata. | | + * | Copy the block mark | | + * | into the first byte of | | + * | the OOB. | | + * -------------+-------------------------+-------------------------+ + * + * Note that we break rule #4 in the Transcribing/Raw case because we're not + * giving an accurate view of the actual, physical bytes in the page (we're + * overwriting the block mark). That's OK because it's more important to follow + * rule #2. + * + * It turns out that knowing whether we want an "ECC-based" or "raw" read is not + * easy. When reading a page, for example, the NAND Flash MTD code calls our + * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an + * ECC-based or raw view of the page is implicit in which function it calls + * (there is a similar pair of ECC-based/raw functions for writing). + * + * Since MTD assumes the OOB is not covered by ECC, there is no pair of + * ECC-based/raw functions for reading or or writing the OOB. The fact that the + * caller wants an ECC-based or raw view of the page is not propagated down to + * this driver. + */ +static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd) +{ + struct gpmi_nand_data *this = chip->priv; + + pr_debug("page number is %d\n", page); + /* clear the OOB buffer */ + memset(chip->oob_poi, ~0, mtd->oobsize); + + /* Read out the conventional OOB. */ + chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* + * Now, we want to make sure the block mark is correct. In the + * Swapping/Raw case, we already have it. Otherwise, we need to + * explicitly read it. + */ + if (!this->swap_block_mark) { + /* Read the block mark into the first byte of the OOB buffer. */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + chip->oob_poi[0] = chip->read_byte(mtd); + } + + /* + * Return true, indicating that the next call to this function must send + * a command. + */ + return true; +} + +static int +gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) +{ + /* + * The BCH will use all the (page + oob). + * Our gpmi_hw_ecclayout can only prohibit the JFFS2 to write the oob. + * But it can not stop some ioctls such MEMWRITEOOB which uses + * MTD_OPS_PLACE_OOB. So We have to implement this function to prohibit + * these ioctls too. + */ + return -EPERM; +} + +static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + int block, ret = 0; + uint8_t *block_mark; + int column, page, status, chipnr; + + /* Get block number */ + block = (int)(ofs >> chip->bbt_erase_shift); + if (chip->bbt) + chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + + /* Do we have a flash based bad block table ? */ + if (chip->options & NAND_BBT_USE_FLASH) + ret = nand_update_bbt(mtd, ofs); + else { + chipnr = (int)(ofs >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + column = this->swap_block_mark ? mtd->writesize : 0; + + /* Write the block mark. */ + block_mark = this->data_buffer_dma; + block_mark[0] = 0; /* bad block marker */ + + /* Shift to get page */ + page = (int)(ofs >> chip->page_shift); + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page); + chip->write_buf(mtd, block_mark, 1); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + ret = -EIO; + + chip->select_chip(mtd, -1); + } + if (!ret) + mtd->ecc_stats.badblocks++; + + return ret; +} + +static int __devinit nand_boot_set_geometry(struct gpmi_nand_data *this) +{ + struct boot_rom_geometry *geometry = &this->rom_geometry; + + /* + * Set the boot block stride size. + * + * In principle, we should be reading this from the OTP bits, since + * that's where the ROM is going to get it. In fact, we don't have any + * way to read the OTP bits, so we go with the default and hope for the + * best. + */ + geometry->stride_size_in_pages = 64; + + /* + * Set the search area stride exponent. + * + * In principle, we should be reading this from the OTP bits, since + * that's where the ROM is going to get it. In fact, we don't have any + * way to read the OTP bits, so we go with the default and hope for the + * best. + */ + geometry->search_area_stride_exponent = 2; + return 0; +} + +static const char *fingerprint = "STMP"; +static int __devinit mx23_check_transcription_stamp(struct gpmi_nand_data *this) +{ + struct boot_rom_geometry *rom_geo = &this->rom_geometry; + struct device *dev = this->dev; + struct mtd_info *mtd = &this->mtd; + struct nand_chip *chip = &this->nand; + unsigned int search_area_size_in_strides; + unsigned int stride; + unsigned int page; + loff_t byte; + uint8_t *buffer = chip->buffers->databuf; + int saved_chip_number; + int found_an_ncb_fingerprint = false; + + /* Compute the number of strides in a search area. */ + search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; + + saved_chip_number = this->current_chip; + chip->select_chip(mtd, 0); + + /* + * Loop through the first search area, looking for the NCB fingerprint. + */ + dev_dbg(dev, "Scanning for an NCB fingerprint...\n"); + + for (stride = 0; stride < search_area_size_in_strides; stride++) { + /* Compute the page and byte addresses. */ + page = stride * rom_geo->stride_size_in_pages; + byte = page * mtd->writesize; + + dev_dbg(dev, "Looking for a fingerprint in page 0x%x\n", page); + + /* + * Read the NCB fingerprint. The fingerprint is four bytes long + * and starts in the 12th byte of the page. + */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 12, page); + chip->read_buf(mtd, buffer, strlen(fingerprint)); + + /* Look for the fingerprint. */ + if (!memcmp(buffer, fingerprint, strlen(fingerprint))) { + found_an_ncb_fingerprint = true; + break; + } + + } + + chip->select_chip(mtd, saved_chip_number); + + if (found_an_ncb_fingerprint) + dev_dbg(dev, "\tFound a fingerprint\n"); + else + dev_dbg(dev, "\tNo fingerprint found\n"); + return found_an_ncb_fingerprint; +} + +/* Writes a transcription stamp. */ +static int __devinit mx23_write_transcription_stamp(struct gpmi_nand_data *this) +{ + struct device *dev = this->dev; + struct boot_rom_geometry *rom_geo = &this->rom_geometry; + struct mtd_info *mtd = &this->mtd; + struct nand_chip *chip = &this->nand; + unsigned int block_size_in_pages; + unsigned int search_area_size_in_strides; + unsigned int search_area_size_in_pages; + unsigned int search_area_size_in_blocks; + unsigned int block; + unsigned int stride; + unsigned int page; + loff_t byte; + uint8_t *buffer = chip->buffers->databuf; + int saved_chip_number; + int status; + + /* Compute the search area geometry. */ + block_size_in_pages = mtd->erasesize / mtd->writesize; + search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; + search_area_size_in_pages = search_area_size_in_strides * + rom_geo->stride_size_in_pages; + search_area_size_in_blocks = + (search_area_size_in_pages + (block_size_in_pages - 1)) / + block_size_in_pages; + + dev_dbg(dev, "Search Area Geometry :\n"); + dev_dbg(dev, "\tin Blocks : %u\n", search_area_size_in_blocks); + dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides); + dev_dbg(dev, "\tin Pages : %u\n", search_area_size_in_pages); + + /* Select chip 0. */ + saved_chip_number = this->current_chip; + chip->select_chip(mtd, 0); + + /* Loop over blocks in the first search area, erasing them. */ + dev_dbg(dev, "Erasing the search area...\n"); + + for (block = 0; block < search_area_size_in_blocks; block++) { + /* Compute the page address. */ + page = block * block_size_in_pages; + + /* Erase this block. */ + dev_dbg(dev, "\tErasing block 0x%x\n", block); + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); + + /* Wait for the erase to finish. */ + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + dev_err(dev, "[%s] Erase failed.\n", __func__); + } + + /* Write the NCB fingerprint into the page buffer. */ + memset(buffer, ~0, mtd->writesize); + memset(chip->oob_poi, ~0, mtd->oobsize); + memcpy(buffer + 12, fingerprint, strlen(fingerprint)); + + /* Loop through the first search area, writing NCB fingerprints. */ + dev_dbg(dev, "Writing NCB fingerprints...\n"); + for (stride = 0; stride < search_area_size_in_strides; stride++) { + /* Compute the page and byte addresses. */ + page = stride * rom_geo->stride_size_in_pages; + byte = page * mtd->writesize; + + /* Write the first page of the current stride. */ + dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + chip->ecc.write_page_raw(mtd, chip, buffer); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + /* Wait for the write to finish. */ + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + dev_err(dev, "[%s] Write failed.\n", __func__); + } + + /* Deselect chip 0. */ + chip->select_chip(mtd, saved_chip_number); + return 0; +} + +static int __devinit mx23_boot_init(struct gpmi_nand_data *this) +{ + struct device *dev = this->dev; + struct nand_chip *chip = &this->nand; + struct mtd_info *mtd = &this->mtd; + unsigned int block_count; + unsigned int block; + int chipnr; + int page; + loff_t byte; + uint8_t block_mark; + int ret = 0; + + /* + * If control arrives here, we can't use block mark swapping, which + * means we're forced to use transcription. First, scan for the + * transcription stamp. If we find it, then we don't have to do + * anything -- the block marks are already transcribed. + */ + if (mx23_check_transcription_stamp(this)) + return 0; + + /* + * If control arrives here, we couldn't find a transcription stamp, so + * so we presume the block marks are in the conventional location. + */ + dev_dbg(dev, "Transcribing bad block marks...\n"); + + /* Compute the number of blocks in the entire medium. */ + block_count = chip->chipsize >> chip->phys_erase_shift; + + /* + * Loop over all the blocks in the medium, transcribing block marks as + * we go. + */ + for (block = 0; block < block_count; block++) { + /* + * Compute the chip, page and byte addresses for this block's + * conventional mark. + */ + chipnr = block >> (chip->chip_shift - chip->phys_erase_shift); + page = block << (chip->phys_erase_shift - chip->page_shift); + byte = block << chip->phys_erase_shift; + + /* Send the command to read the conventional block mark. */ + chip->select_chip(mtd, chipnr); + chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); + block_mark = chip->read_byte(mtd); + chip->select_chip(mtd, -1); + + /* + * Check if the block is marked bad. If so, we need to mark it + * again, but this time the result will be a mark in the + * location where we transcribe block marks. + */ + if (block_mark != 0xff) { + dev_dbg(dev, "Transcribing mark in block %u\n", block); + ret = chip->block_markbad(mtd, byte); + if (ret) + dev_err(dev, "Failed to mark block bad with " + "ret %d\n", ret); + } + } + + /* Write the stamp that indicates we've transcribed the block marks. */ + mx23_write_transcription_stamp(this); + return 0; +} + +static int __devinit nand_boot_init(struct gpmi_nand_data *this) +{ + nand_boot_set_geometry(this); + + /* This is ROM arch-specific initilization before the BBT scanning. */ + if (GPMI_IS_MX23(this)) + return mx23_boot_init(this); + return 0; +} + +static int __devinit gpmi_set_geometry(struct gpmi_nand_data *this) +{ + int ret; + + /* Free the temporary DMA memory for reading ID. */ + gpmi_free_dma_buffer(this); + + /* Set up the NFC geometry which is used by BCH. */ + ret = bch_set_geometry(this); + if (ret) { + pr_err("set geometry ret : %d\n", ret); + return ret; + } + + /* Alloc the new DMA buffers according to the pagesize and oobsize */ + return gpmi_alloc_dma_buffer(this); +} + +static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) +{ + int ret; + + /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ + if (GPMI_IS_MX23(this)) + this->swap_block_mark = false; + else + this->swap_block_mark = true; + + /* Set up the medium geometry */ + ret = gpmi_set_geometry(this); + if (ret) + return ret; + + /* NAND boot init, depends on the gpmi_set_geometry(). */ + return nand_boot_init(this); +} + +static int gpmi_scan_bbt(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + int ret; + + /* Prepare for the BBT scan. */ + ret = gpmi_pre_bbt_scan(this); + if (ret) + return ret; + + /* use the default BBT implementation */ + return nand_default_bbt(mtd); +} + +void gpmi_nfc_exit(struct gpmi_nand_data *this) +{ + nand_release(&this->mtd); + gpmi_free_dma_buffer(this); +} + +static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) +{ + struct gpmi_nand_platform_data *pdata = this->pdata; + struct mtd_info *mtd = &this->mtd; + struct nand_chip *chip = &this->nand; + int ret; + + /* init current chip */ + this->current_chip = -1; + + /* init the MTD data structures */ + mtd->priv = chip; + mtd->name = "gpmi-nand"; + mtd->owner = THIS_MODULE; + + /* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */ + chip->priv = this; + chip->select_chip = gpmi_select_chip; + chip->cmd_ctrl = gpmi_cmd_ctrl; + chip->dev_ready = gpmi_dev_ready; + chip->read_byte = gpmi_read_byte; + chip->read_buf = gpmi_read_buf; + chip->write_buf = gpmi_write_buf; + chip->ecc.read_page = gpmi_ecc_read_page; + chip->ecc.write_page = gpmi_ecc_write_page; + chip->ecc.read_oob = gpmi_ecc_read_oob; + chip->ecc.write_oob = gpmi_ecc_write_oob; + chip->scan_bbt = gpmi_scan_bbt; + chip->badblock_pattern = &gpmi_bbt_descr; + chip->block_markbad = gpmi_block_markbad; + chip->options |= NAND_NO_SUBPAGE_WRITE; + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = 1; + chip->ecc.layout = &gpmi_hw_ecclayout; + + /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */ + this->bch_geometry.payload_size = 1024; + this->bch_geometry.auxiliary_size = 128; + ret = gpmi_alloc_dma_buffer(this); + if (ret) + goto err_out; + + ret = nand_scan(mtd, pdata->max_chip_count); + if (ret) { + pr_err("Chip scan failed\n"); + goto err_out; + } + + ret = mtd_device_parse_register(mtd, NULL, NULL, + pdata->partitions, pdata->partition_count); + if (ret) + goto err_out; + return 0; + +err_out: + gpmi_nfc_exit(this); + return ret; +} + +static int __devinit gpmi_nand_probe(struct platform_device *pdev) +{ + struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data; + struct gpmi_nand_data *this; + int ret; + + this = kzalloc(sizeof(*this), GFP_KERNEL); + if (!this) { + pr_err("Failed to allocate per-device memory\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, this); + this->pdev = pdev; + this->dev = &pdev->dev; + this->pdata = pdata; + + if (pdata->platform_init) { + ret = pdata->platform_init(); + if (ret) + goto platform_init_error; + } + + ret = acquire_resources(this); + if (ret) + goto exit_acquire_resources; + + ret = init_hardware(this); + if (ret) + goto exit_nfc_init; + + ret = gpmi_nfc_init(this); + if (ret) + goto exit_nfc_init; + + return 0; + +exit_nfc_init: + release_resources(this); +platform_init_error: +exit_acquire_resources: + platform_set_drvdata(pdev, NULL); + kfree(this); + return ret; +} + +static int __exit gpmi_nand_remove(struct platform_device *pdev) +{ + struct gpmi_nand_data *this = platform_get_drvdata(pdev); + + gpmi_nfc_exit(this); + release_resources(this); + platform_set_drvdata(pdev, NULL); + kfree(this); + return 0; +} + +static const struct platform_device_id gpmi_ids[] = { + { + .name = "imx23-gpmi-nand", + .driver_data = IS_MX23, + }, { + .name = "imx28-gpmi-nand", + .driver_data = IS_MX28, + }, {}, +}; + +static struct platform_driver gpmi_nand_driver = { + .driver = { + .name = "gpmi-nand", + }, + .probe = gpmi_nand_probe, + .remove = __exit_p(gpmi_nand_remove), + .id_table = gpmi_ids, +}; + +static int __init gpmi_nand_init(void) +{ + int err; + + err = platform_driver_register(&gpmi_nand_driver); + if (err == 0) + printk(KERN_INFO "GPMI NAND driver registered. (IMX)\n"); + else + pr_err("i.MX GPMI NAND driver registration failed\n"); + return err; +} + +static void __exit gpmi_nand_exit(void) +{ + platform_driver_unregister(&gpmi_nand_driver); +} + +module_init(gpmi_nand_init); +module_exit(gpmi_nand_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("i.MX GPMI NAND Flash Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h new file mode 100644 index 000000000000..e023bccb7781 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -0,0 +1,273 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * 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. + */ +#ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H +#define __DRIVERS_MTD_NAND_GPMI_NAND_H + +#include <linux/mtd/nand.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <mach/dma.h> + +struct resources { + void *gpmi_regs; + void *bch_regs; + unsigned int bch_low_interrupt; + unsigned int bch_high_interrupt; + unsigned int dma_low_channel; + unsigned int dma_high_channel; + struct clk *clock; +}; + +/** + * struct bch_geometry - BCH geometry description. + * @gf_len: The length of Galois Field. (e.g., 13 or 14) + * @ecc_strength: A number that describes the strength of the ECC + * algorithm. + * @page_size: The size, in bytes, of a physical page, including + * both data and OOB. + * @metadata_size: The size, in bytes, of the metadata. + * @ecc_chunk_size: The size, in bytes, of a single ECC chunk. Note + * the first chunk in the page includes both data and + * metadata, so it's a bit larger than this value. + * @ecc_chunk_count: The number of ECC chunks in the page, + * @payload_size: The size, in bytes, of the payload buffer. + * @auxiliary_size: The size, in bytes, of the auxiliary buffer. + * @auxiliary_status_offset: The offset into the auxiliary buffer at which + * the ECC status appears. + * @block_mark_byte_offset: The byte offset in the ECC-based page view at + * which the underlying physical block mark appears. + * @block_mark_bit_offset: The bit offset into the ECC-based page view at + * which the underlying physical block mark appears. + */ +struct bch_geometry { + unsigned int gf_len; + unsigned int ecc_strength; + unsigned int page_size; + unsigned int metadata_size; + unsigned int ecc_chunk_size; + unsigned int ecc_chunk_count; + unsigned int payload_size; + unsigned int auxiliary_size; + unsigned int auxiliary_status_offset; + unsigned int block_mark_byte_offset; + unsigned int block_mark_bit_offset; +}; + +/** + * struct boot_rom_geometry - Boot ROM geometry description. + * @stride_size_in_pages: The size of a boot block stride, in pages. + * @search_area_stride_exponent: The logarithm to base 2 of the size of a + * search area in boot block strides. + */ +struct boot_rom_geometry { + unsigned int stride_size_in_pages; + unsigned int search_area_stride_exponent; +}; + +/* DMA operations types */ +enum dma_ops_type { + DMA_FOR_COMMAND = 1, + DMA_FOR_READ_DATA, + DMA_FOR_WRITE_DATA, + DMA_FOR_READ_ECC_PAGE, + DMA_FOR_WRITE_ECC_PAGE +}; + +/** + * struct nand_timing - Fundamental timing attributes for NAND. + * @data_setup_in_ns: The data setup time, in nanoseconds. Usually the + * maximum of tDS and tWP. A negative value + * indicates this characteristic isn't known. + * @data_hold_in_ns: The data hold time, in nanoseconds. Usually the + * maximum of tDH, tWH and tREH. A negative value + * indicates this characteristic isn't known. + * @address_setup_in_ns: The address setup time, in nanoseconds. Usually + * the maximum of tCLS, tCS and tALS. A negative + * value indicates this characteristic isn't known. + * @gpmi_sample_delay_in_ns: A GPMI-specific timing parameter. A negative value + * indicates this characteristic isn't known. + * @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic isn't + * known. + * @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic isn't + * known. + * @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic isn't + * known. + */ +struct nand_timing { + int8_t data_setup_in_ns; + int8_t data_hold_in_ns; + int8_t address_setup_in_ns; + int8_t gpmi_sample_delay_in_ns; + int8_t tREA_in_ns; + int8_t tRLOH_in_ns; + int8_t tRHOH_in_ns; +}; + +struct gpmi_nand_data { + /* System Interface */ + struct device *dev; + struct platform_device *pdev; + struct gpmi_nand_platform_data *pdata; + + /* Resources */ + struct resources resources; + + /* Flash Hardware */ + struct nand_timing timing; + + /* BCH */ + struct bch_geometry bch_geometry; + struct completion bch_done; + + /* NAND Boot issue */ + bool swap_block_mark; + struct boot_rom_geometry rom_geometry; + + /* MTD / NAND */ + struct nand_chip nand; + struct mtd_info mtd; + + /* General-use Variables */ + int current_chip; + unsigned int command_length; + + /* passed from upper layer */ + uint8_t *upper_buf; + int upper_len; + + /* for DMA operations */ + bool direct_dma_map_ok; + + struct scatterlist cmd_sgl; + char *cmd_buffer; + + struct scatterlist data_sgl; + char *data_buffer_dma; + + void *page_buffer_virt; + dma_addr_t page_buffer_phys; + unsigned int page_buffer_size; + + void *payload_virt; + dma_addr_t payload_phys; + + void *auxiliary_virt; + dma_addr_t auxiliary_phys; + + /* DMA channels */ +#define DMA_CHANS 8 + struct dma_chan *dma_chans[DMA_CHANS]; + struct mxs_dma_data dma_data; + enum dma_ops_type last_dma_type; + enum dma_ops_type dma_type; + struct completion dma_done; + + /* private */ + void *private; +}; + +/** + * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters. + * @data_setup_in_cycles: The data setup time, in cycles. + * @data_hold_in_cycles: The data hold time, in cycles. + * @address_setup_in_cycles: The address setup time, in cycles. + * @use_half_periods: Indicates the clock is running slowly, so the + * NFC DLL should use half-periods. + * @sample_delay_factor: The sample delay factor. + */ +struct gpmi_nfc_hardware_timing { + uint8_t data_setup_in_cycles; + uint8_t data_hold_in_cycles; + uint8_t address_setup_in_cycles; + bool use_half_periods; + uint8_t sample_delay_factor; +}; + +/** + * struct timing_threshod - Timing threshold + * @max_data_setup_cycles: The maximum number of data setup cycles that + * can be expressed in the hardware. + * @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires + * for data read internal setup. In the Reference + * Manual, see the chapter "High-Speed NAND + * Timing" for more details. + * @max_sample_delay_factor: The maximum sample delay factor that can be + * expressed in the hardware. + * @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the + * sample delay DLL hardware can possibly work + * with (the DLL is unusable with longer periods). + * If the full-cycle period is greater than HALF + * this value, the DLL must be configured to use + * half-periods. + * @max_dll_delay_in_ns: The maximum amount of delay, in ns, that the + * DLL can implement. + * @clock_frequency_in_hz: The clock frequency, in Hz, during the current + * I/O transaction. If no I/O transaction is in + * progress, this is the clock frequency during + * the most recent I/O transaction. + */ +struct timing_threshod { + const unsigned int max_chip_count; + const unsigned int max_data_setup_cycles; + const unsigned int internal_data_setup_in_ns; + const unsigned int max_sample_delay_factor; + const unsigned int max_dll_clock_period_in_ns; + const unsigned int max_dll_delay_in_ns; + unsigned long clock_frequency_in_hz; + +}; + +/* Common Services */ +extern int common_nfc_set_geometry(struct gpmi_nand_data *); +extern struct dma_chan *get_dma_chan(struct gpmi_nand_data *); +extern void prepare_data_dma(struct gpmi_nand_data *, + enum dma_data_direction dr); +extern int start_dma_without_bch_irq(struct gpmi_nand_data *, + struct dma_async_tx_descriptor *); +extern int start_dma_with_bch_irq(struct gpmi_nand_data *, + struct dma_async_tx_descriptor *); + +/* GPMI-NAND helper function library */ +extern int gpmi_init(struct gpmi_nand_data *); +extern void gpmi_clear_bch(struct gpmi_nand_data *); +extern void gpmi_dump_info(struct gpmi_nand_data *); +extern int bch_set_geometry(struct gpmi_nand_data *); +extern int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip); +extern int gpmi_send_command(struct gpmi_nand_data *); +extern void gpmi_begin(struct gpmi_nand_data *); +extern void gpmi_end(struct gpmi_nand_data *); +extern int gpmi_read_data(struct gpmi_nand_data *); +extern int gpmi_send_data(struct gpmi_nand_data *); +extern int gpmi_send_page(struct gpmi_nand_data *, + dma_addr_t payload, dma_addr_t auxiliary); +extern int gpmi_read_page(struct gpmi_nand_data *, + dma_addr_t payload, dma_addr_t auxiliary); + +/* BCH : Status Block Completion Codes */ +#define STATUS_GOOD 0x00 +#define STATUS_ERASED 0xff +#define STATUS_UNCORRECTABLE 0xfe + +/* Use the platform_id to distinguish different Archs. */ +#define IS_MX23 0x1 +#define IS_MX28 0x2 +#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23) +#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28) +#endif diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h new file mode 100644 index 000000000000..83431240e2f2 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h @@ -0,0 +1,172 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __GPMI_NAND_GPMI_REGS_H +#define __GPMI_NAND_GPMI_REGS_H + +#define HW_GPMI_CTRL0 0x00000000 +#define HW_GPMI_CTRL0_SET 0x00000004 +#define HW_GPMI_CTRL0_CLR 0x00000008 +#define HW_GPMI_CTRL0_TOG 0x0000000c + +#define BP_GPMI_CTRL0_COMMAND_MODE 24 +#define BM_GPMI_CTRL0_COMMAND_MODE (3 << BP_GPMI_CTRL0_COMMAND_MODE) +#define BF_GPMI_CTRL0_COMMAND_MODE(v) \ + (((v) << BP_GPMI_CTRL0_COMMAND_MODE) & BM_GPMI_CTRL0_COMMAND_MODE) +#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE 0x0 +#define BV_GPMI_CTRL0_COMMAND_MODE__READ 0x1 +#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2 +#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY 0x3 + +#define BM_GPMI_CTRL0_WORD_LENGTH (1 << 23) +#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT 0x0 +#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT 0x1 + +/* + * Difference in LOCK_CS between imx23 and imx28 : + * This bit may impact the _POWER_ consumption. So some chips + * do not set it. + */ +#define MX23_BP_GPMI_CTRL0_LOCK_CS 22 +#define MX28_BP_GPMI_CTRL0_LOCK_CS 27 +#define LOCK_CS_ENABLE 0x1 +#define BF_GPMI_CTRL0_LOCK_CS(v, x) 0x0 + +/* Difference in CS between imx23 and imx28 */ +#define BP_GPMI_CTRL0_CS 20 +#define MX23_BM_GPMI_CTRL0_CS (3 << BP_GPMI_CTRL0_CS) +#define MX28_BM_GPMI_CTRL0_CS (7 << BP_GPMI_CTRL0_CS) +#define BF_GPMI_CTRL0_CS(v, x) (((v) << BP_GPMI_CTRL0_CS) & \ + (GPMI_IS_MX23((x)) \ + ? MX23_BM_GPMI_CTRL0_CS \ + : MX28_BM_GPMI_CTRL0_CS)) + +#define BP_GPMI_CTRL0_ADDRESS 17 +#define BM_GPMI_CTRL0_ADDRESS (3 << BP_GPMI_CTRL0_ADDRESS) +#define BF_GPMI_CTRL0_ADDRESS(v) \ + (((v) << BP_GPMI_CTRL0_ADDRESS) & BM_GPMI_CTRL0_ADDRESS) +#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA 0x0 +#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE 0x1 +#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE 0x2 + +#define BM_GPMI_CTRL0_ADDRESS_INCREMENT (1 << 16) +#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED 0x0 +#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED 0x1 + +#define BP_GPMI_CTRL0_XFER_COUNT 0 +#define BM_GPMI_CTRL0_XFER_COUNT (0xffff << BP_GPMI_CTRL0_XFER_COUNT) +#define BF_GPMI_CTRL0_XFER_COUNT(v) \ + (((v) << BP_GPMI_CTRL0_XFER_COUNT) & BM_GPMI_CTRL0_XFER_COUNT) + +#define HW_GPMI_COMPARE 0x00000010 + +#define HW_GPMI_ECCCTRL 0x00000020 +#define HW_GPMI_ECCCTRL_SET 0x00000024 +#define HW_GPMI_ECCCTRL_CLR 0x00000028 +#define HW_GPMI_ECCCTRL_TOG 0x0000002c + +#define BP_GPMI_ECCCTRL_ECC_CMD 13 +#define BM_GPMI_ECCCTRL_ECC_CMD (3 << BP_GPMI_ECCCTRL_ECC_CMD) +#define BF_GPMI_ECCCTRL_ECC_CMD(v) \ + (((v) << BP_GPMI_ECCCTRL_ECC_CMD) & BM_GPMI_ECCCTRL_ECC_CMD) +#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE 0x0 +#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE 0x1 + +#define BM_GPMI_ECCCTRL_ENABLE_ECC (1 << 12) +#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE 0x1 +#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE 0x0 + +#define BP_GPMI_ECCCTRL_BUFFER_MASK 0 +#define BM_GPMI_ECCCTRL_BUFFER_MASK (0x1ff << BP_GPMI_ECCCTRL_BUFFER_MASK) +#define BF_GPMI_ECCCTRL_BUFFER_MASK(v) \ + (((v) << BP_GPMI_ECCCTRL_BUFFER_MASK) & BM_GPMI_ECCCTRL_BUFFER_MASK) +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY 0x100 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE 0x1FF + +#define HW_GPMI_ECCCOUNT 0x00000030 +#define HW_GPMI_PAYLOAD 0x00000040 +#define HW_GPMI_AUXILIARY 0x00000050 +#define HW_GPMI_CTRL1 0x00000060 +#define HW_GPMI_CTRL1_SET 0x00000064 +#define HW_GPMI_CTRL1_CLR 0x00000068 +#define HW_GPMI_CTRL1_TOG 0x0000006c + +#define BM_GPMI_CTRL1_BCH_MODE (1 << 18) + +#define BP_GPMI_CTRL1_DLL_ENABLE 17 +#define BM_GPMI_CTRL1_DLL_ENABLE (1 << BP_GPMI_CTRL1_DLL_ENABLE) + +#define BP_GPMI_CTRL1_HALF_PERIOD 16 +#define BM_GPMI_CTRL1_HALF_PERIOD (1 << BP_GPMI_CTRL1_HALF_PERIOD) + +#define BP_GPMI_CTRL1_RDN_DELAY 12 +#define BM_GPMI_CTRL1_RDN_DELAY (0xf << BP_GPMI_CTRL1_RDN_DELAY) +#define BF_GPMI_CTRL1_RDN_DELAY(v) \ + (((v) << BP_GPMI_CTRL1_RDN_DELAY) & BM_GPMI_CTRL1_RDN_DELAY) + +#define BM_GPMI_CTRL1_DEV_RESET (1 << 3) +#define BV_GPMI_CTRL1_DEV_RESET__ENABLED 0x0 +#define BV_GPMI_CTRL1_DEV_RESET__DISABLED 0x1 + +#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY (1 << 2) +#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW 0x0 +#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH 0x1 + +#define BM_GPMI_CTRL1_CAMERA_MODE (1 << 1) +#define BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0 +#define BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1 + +#define BM_GPMI_CTRL1_GPMI_MODE (1 << 0) + +#define HW_GPMI_TIMING0 0x00000070 + +#define BP_GPMI_TIMING0_ADDRESS_SETUP 16 +#define BM_GPMI_TIMING0_ADDRESS_SETUP (0xff << BP_GPMI_TIMING0_ADDRESS_SETUP) +#define BF_GPMI_TIMING0_ADDRESS_SETUP(v) \ + (((v) << BP_GPMI_TIMING0_ADDRESS_SETUP) & BM_GPMI_TIMING0_ADDRESS_SETUP) + +#define BP_GPMI_TIMING0_DATA_HOLD 8 +#define BM_GPMI_TIMING0_DATA_HOLD (0xff << BP_GPMI_TIMING0_DATA_HOLD) +#define BF_GPMI_TIMING0_DATA_HOLD(v) \ + (((v) << BP_GPMI_TIMING0_DATA_HOLD) & BM_GPMI_TIMING0_DATA_HOLD) + +#define BP_GPMI_TIMING0_DATA_SETUP 0 +#define BM_GPMI_TIMING0_DATA_SETUP (0xff << BP_GPMI_TIMING0_DATA_SETUP) +#define BF_GPMI_TIMING0_DATA_SETUP(v) \ + (((v) << BP_GPMI_TIMING0_DATA_SETUP) & BM_GPMI_TIMING0_DATA_SETUP) + +#define HW_GPMI_TIMING1 0x00000080 +#define BP_GPMI_TIMING1_BUSY_TIMEOUT 16 + +#define HW_GPMI_TIMING2 0x00000090 +#define HW_GPMI_DATA 0x000000a0 + +/* MX28 uses this to detect READY. */ +#define HW_GPMI_STAT 0x000000b0 +#define MX28_BP_GPMI_STAT_READY_BUSY 24 +#define MX28_BM_GPMI_STAT_READY_BUSY (0xff << MX28_BP_GPMI_STAT_READY_BUSY) +#define MX28_BF_GPMI_STAT_READY_BUSY(v) \ + (((v) << MX28_BP_GPMI_STAT_READY_BUSY) & MX28_BM_GPMI_STAT_READY_BUSY) + +/* MX23 uses this to detect READY. */ +#define HW_GPMI_DEBUG 0x000000c0 +#define MX23_BP_GPMI_DEBUG_READY0 28 +#define MX23_BM_GPMI_DEBUG_READY0 (1 << MX23_BP_GPMI_DEBUG_READY0) +#endif diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 02a03e67109c..5dc6f0d92f1a 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -81,9 +81,6 @@ static int h1910_device_ready(struct mtd_info *mtd) static int __init h1910_init(void) { struct nand_chip *this; - const char *part_type = 0; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; void __iomem *nandaddr; if (!machine_is_h1900()) @@ -136,22 +133,10 @@ static int __init h1910_init(void) iounmap((void *)nandaddr); return -ENXIO; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, "h1910-nand"); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; -#endif - if (mtd_parts_nb == 0) { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(h1910_nand_mtd, mtd_parts, mtd_parts_nb); + mtd_device_parse_register(h1910_nand_mtd, NULL, 0, + partition_info, NUM_PARTITIONS); /* Return happy */ return 0; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 6e813daed068..e2664073a89b 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -251,10 +251,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, return 0; } -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = {"cmdline", NULL}; -#endif - static int jz_nand_ioremap_resource(struct platform_device *pdev, const char *name, struct resource **res, void __iomem **base) { @@ -299,8 +295,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) struct nand_chip *chip; struct mtd_info *mtd; struct jz_nand_platform_data *pdata = pdev->dev.platform_data; - struct mtd_partition *partition_info; - int num_partitions = 0; nand = kzalloc(sizeof(*nand), GFP_KERNEL); if (!nand) { @@ -373,15 +367,9 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) goto err_gpio_free; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partition_info, 0); -#endif - if (num_partitions <= 0 && pdata) { - num_partitions = pdata->num_partitions; - partition_info = pdata->partitions; - } - ret = mtd_device_register(mtd, partition_info, num_partitions); + ret = mtd_device_parse_register(mtd, NULL, 0, + pdata ? pdata->partitions : NULL, + pdata ? pdata->num_partitions : 0); if (ret) { dev_err(&pdev->dev, "Failed to add mtd device\n"); diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index eb1fbac63eb6..5ede64706346 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -131,8 +131,6 @@ struct mpc5121_nfc_prv { static void mpc5121_nfc_done(struct mtd_info *mtd); -static const char *mpc5121_nfc_pprobes[] = { "cmdlinepart", NULL }; - /* Read NFC register */ static inline u16 nfc_read(struct mtd_info *mtd, uint reg) { @@ -656,13 +654,13 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) struct mpc5121_nfc_prv *prv; struct resource res; struct mtd_info *mtd; - struct mtd_partition *parts; struct nand_chip *chip; unsigned long regs_paddr, regs_size; const __be32 *chips_no; int resettime = 0; int retval = 0; int rev, len; + struct mtd_part_parser_data ppdata; /* * Check SoC revision. This driver supports only NFC @@ -727,6 +725,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) } mtd->name = "MPC5121 NAND"; + ppdata.of_node = dn; chip->dev_ready = mpc5121_nfc_dev_ready; chip->cmdfunc = mpc5121_nfc_command; chip->read_byte = mpc5121_nfc_read_byte; @@ -735,7 +734,8 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) chip->write_buf = mpc5121_nfc_write_buf; chip->verify_buf = mpc5121_nfc_verify_buf; chip->select_chip = mpc5121_nfc_select_chip; - chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT; + chip->options = NAND_NO_AUTOINCR; + chip->bbt_options = NAND_BBT_USE_FLASH; chip->ecc.mode = NAND_ECC_SOFT; /* Support external chip-select logic on ADS5121 board */ @@ -837,19 +837,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) dev_set_drvdata(dev, mtd); /* Register device in MTD */ - retval = parse_mtd_partitions(mtd, mpc5121_nfc_pprobes, &parts, 0); -#ifdef CONFIG_MTD_OF_PARTS - if (retval == 0) - retval = of_mtd_parse_partitions(dev, dn, &parts); -#endif - if (retval < 0) { - dev_err(dev, "Error parsing MTD partitions!\n"); - devm_free_irq(dev, prv->irq, mtd); - retval = -EINVAL; - goto error; - } - - retval = mtd_device_register(mtd, parts, retval); + retval = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (retval) { dev_err(dev, "Error adding MTD device!\n"); devm_free_irq(dev, prv->irq, mtd); diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 90df34c4d26c..74a43b818d0e 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -41,7 +41,7 @@ #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) -#define nfc_is_v3_2() cpu_is_mx51() +#define nfc_is_v3_2() (cpu_is_mx51() || cpu_is_mx53()) #define nfc_is_v3() nfc_is_v3_2() /* Addresses for NFC registers */ @@ -143,7 +143,6 @@ struct mxc_nand_host { struct mtd_info mtd; struct nand_chip nand; - struct mtd_partition *parts; struct device *dev; void *spare0; @@ -350,8 +349,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) udelay(1); } if (max_retries < 0) - DEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n", - __func__); + pr_debug("%s: INT not set\n", __func__); } } @@ -371,7 +369,7 @@ static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) * waits for completion. */ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) { - DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq); + pr_debug("send_cmd(host, 0x%x, %d)\n", cmd, useirq); writew(cmd, NFC_V1_V2_FLASH_CMD); writew(NFC_CMD, NFC_V1_V2_CONFIG2); @@ -387,8 +385,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) udelay(1); } if (max_retries < 0) - DEBUG(MTD_DEBUG_LEVEL0, "%s: RESET failed\n", - __func__); + pr_debug("%s: RESET failed\n", __func__); } else { /* Wait for operation to complete */ wait_op_done(host, useirq); @@ -411,7 +408,7 @@ static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast) * a NAND command. */ static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast) { - DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); + pr_debug("send_addr(host, 0x%x %d)\n", addr, islast); writew(addr, NFC_V1_V2_FLASH_ADDR); writew(NFC_ADDR, NFC_V1_V2_CONFIG2); @@ -561,8 +558,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, uint16_t ecc_status = readw(NFC_V1_V2_ECC_STATUS_RESULT); if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { - DEBUG(MTD_DEBUG_LEVEL0, - "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); + pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); return -1; } @@ -849,7 +845,7 @@ static void preset_v1_v2(struct mtd_info *mtd) writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3); } else if (nfc_is_v1()) { writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR); - writew(0x4000, NFC_V1_UNLOCKEND_BLKADDR); + writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR); } else BUG(); @@ -932,8 +928,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; - DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", + pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", command, column, page_addr); /* Reset command state information */ @@ -1044,7 +1039,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; struct mxc_nand_host *host; struct resource *res; - int err = 0, __maybe_unused nr_parts = 0; + int err = 0; struct nand_ecclayout *oob_smallpage, *oob_largepage; /* Allocate memory for MTD device structure and private data */ @@ -1179,7 +1174,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; /* update flash based bbt */ - this->options |= NAND_USE_FLASH_BBT; + this->bbt_options |= NAND_BBT_USE_FLASH; } init_completion(&host->op_completion); @@ -1231,16 +1226,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) } /* Register the partitions */ - nr_parts = - parse_mtd_partitions(mtd, part_probes, &host->parts, 0); - if (nr_parts > 0) - mtd_device_register(mtd, host->parts, nr_parts); - else if (pdata->parts) - mtd_device_register(mtd, pdata->parts, pdata->nr_parts); - else { - pr_info("Registering %s as whole device\n", mtd->name); - mtd_device_register(mtd, NULL, 0); - } + mtd_device_parse_register(mtd, part_probes, 0, + pdata->parts, pdata->nr_parts); platform_set_drvdata(pdev, host); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a46e9bb847bd..3ed9c5e4d34e 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -21,7 +21,7 @@ * TODO: * Enable cached programming for 2k page size chips * Check, if mtd->ecctype should be set to MTD_ECC_HW - * if we have HW ecc support. + * if we have HW ECC support. * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * BBT table is not serialized, has to be fixed @@ -113,21 +113,19 @@ static int check_offs_len(struct mtd_info *mtd, /* Start address must align on block boundary */ if (ofs & ((1 << chip->phys_erase_shift) - 1)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Unaligned address\n", __func__); + pr_debug("%s: unaligned address\n", __func__); ret = -EINVAL; } /* Length must align on block boundary */ if (len & ((1 << chip->phys_erase_shift) - 1)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Length not block aligned\n", - __func__); + pr_debug("%s: length not block aligned\n", __func__); ret = -EINVAL; } /* Do not allow past end of device */ if (ofs + len > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Past end of device\n", - __func__); + pr_debug("%s: past end of device\n", __func__); ret = -EINVAL; } @@ -136,9 +134,9 @@ static int check_offs_len(struct mtd_info *mtd, /** * nand_release_device - [GENERIC] release chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Deselect, release chip lock and wake up anyone waiting on the device + * Deselect, release chip lock and wake up anyone waiting on the device. */ static void nand_release_device(struct mtd_info *mtd) { @@ -157,9 +155,9 @@ static void nand_release_device(struct mtd_info *mtd) /** * nand_read_byte - [DEFAULT] read one byte from the chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Default read function for 8bit buswith + * Default read function for 8bit buswidth */ static uint8_t nand_read_byte(struct mtd_info *mtd) { @@ -169,10 +167,11 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) /** * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip - * @mtd: MTD device structure + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip + * @mtd: MTD device structure + * + * Default read function for 16bit buswidth with endianness conversion. * - * Default read function for 16bit buswith with - * endianess conversion */ static uint8_t nand_read_byte16(struct mtd_info *mtd) { @@ -182,10 +181,9 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd) /** * nand_read_word - [DEFAULT] read one word from the chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Default read function for 16bit buswith without - * endianess conversion + * Default read function for 16bit buswidth without endianness conversion. */ static u16 nand_read_word(struct mtd_info *mtd) { @@ -195,8 +193,8 @@ static u16 nand_read_word(struct mtd_info *mtd) /** * nand_select_chip - [DEFAULT] control CE line - * @mtd: MTD device structure - * @chipnr: chipnumber to select, -1 for deselect + * @mtd: MTD device structure + * @chipnr: chipnumber to select, -1 for deselect * * Default select function for 1 chip devices. */ @@ -218,11 +216,11 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr) /** * nand_write_buf - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write * - * Default write function for 8bit buswith + * Default write function for 8bit buswidth. */ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -235,11 +233,11 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_read_buf - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read * - * Default read function for 8bit buswith + * Default read function for 8bit buswidth. */ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { @@ -252,11 +250,11 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) /** * nand_verify_buf - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare * - * Default verify function for 8bit buswith + * Default verify function for 8bit buswidth. */ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -271,11 +269,11 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_write_buf16 - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write * - * Default write function for 16bit buswith + * Default write function for 16bit buswidth. */ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -291,11 +289,11 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_read_buf16 - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read * - * Default read function for 16bit buswith + * Default read function for 16bit buswidth. */ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) { @@ -310,11 +308,11 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) /** * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare * - * Default verify function for 16bit buswith + * Default verify function for 16bit buswidth. */ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -332,9 +330,9 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_block_bad - [DEFAULT] Read bad block marker from the chip - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected * * Check, if the block is bad. */ @@ -344,7 +342,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) struct nand_chip *chip = mtd->priv; u16 bad; - if (chip->options & NAND_BBT_SCANLASTPAGE) + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ofs += mtd->erasesize - mtd->writesize; page = (int)(ofs >> chip->page_shift) & chip->pagemask; @@ -384,11 +382,11 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) /** * nand_default_block_markbad - [DEFAULT] mark a block bad - * @mtd: MTD device structure - * @ofs: offset from device start + * @mtd: MTD device structure + * @ofs: offset from device start * - * This is the default implementation, which can be overridden by - * a hardware specific driver. + * This is the default implementation, which can be overridden by a hardware + * specific driver. */ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) { @@ -396,7 +394,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) uint8_t buf[2] = { 0, 0 }; int block, ret, i = 0; - if (chip->options & NAND_BBT_SCANLASTPAGE) + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ofs += mtd->erasesize - mtd->writesize; /* Get block number */ @@ -404,33 +402,31 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) if (chip->bbt) chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); - /* Do we have a flash based bad block table ? */ - if (chip->options & NAND_USE_FLASH_BBT) + /* Do we have a flash based bad block table? */ + if (chip->bbt_options & NAND_BBT_USE_FLASH) ret = nand_update_bbt(mtd, ofs); else { + struct mtd_oob_ops ops; + nand_get_device(chip, mtd, FL_WRITING); - /* Write to first two pages and to byte 1 and 6 if necessary. - * If we write to more than one location, the first error - * encountered quits the procedure. We write two bytes per - * location, so we dont have to mess with 16 bit access. + /* + * Write to first two pages if necessary. If we write to more + * than one location, the first error encountered quits the + * procedure. We write two bytes per location, so we dont have + * to mess with 16 bit access. */ + ops.len = ops.ooblen = 2; + ops.datbuf = NULL; + ops.oobbuf = buf; + ops.ooboffs = chip->badblockpos & ~0x01; + ops.mode = MTD_OPS_PLACE_OOB; do { - chip->ops.len = chip->ops.ooblen = 2; - chip->ops.datbuf = NULL; - chip->ops.oobbuf = buf; - chip->ops.ooboffs = chip->badblockpos & ~0x01; - - ret = nand_do_write_oob(mtd, ofs, &chip->ops); + ret = nand_do_write_oob(mtd, ofs, &ops); - if (!ret && (chip->options & NAND_BBT_SCANBYTE1AND6)) { - chip->ops.ooboffs = NAND_SMALL_BADBLOCK_POS - & ~0x01; - ret = nand_do_write_oob(mtd, ofs, &chip->ops); - } i++; ofs += mtd->writesize; - } while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) && + } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); nand_release_device(mtd); @@ -443,16 +439,16 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /** * nand_check_wp - [GENERIC] check if the chip is write protected - * @mtd: MTD device structure - * Check, if the device is write protected + * @mtd: MTD device structure * - * The function expects, that the device is already selected + * Check, if the device is write protected. The function expects, that the + * device is already selected. */ static int nand_check_wp(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - /* broken xD cards report WP despite being writable */ + /* Broken xD cards report WP despite being writable */ if (chip->options & NAND_BROKEN_XD) return 0; @@ -463,10 +459,10 @@ static int nand_check_wp(struct mtd_info *mtd) /** * nand_block_checkbad - [GENERIC] Check if a block is marked bad - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected - * @allowbbt: 1, if its allowed to access the bbt area + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected + * @allowbbt: 1, if its allowed to access the bbt area * * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. @@ -485,8 +481,8 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, /** * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands. - * @mtd: MTD device structure - * @timeo: Timeout + * @mtd: MTD device structure + * @timeo: Timeout * * Helper function for nand_wait_ready used when needing to wait in interrupt * context. @@ -505,10 +501,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) } } -/* - * Wait for the ready pin, after a command - * The timeout is catched later. - */ +/* Wait for the ready pin, after a command. The timeout is caught later. */ void nand_wait_ready(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; @@ -519,7 +512,7 @@ void nand_wait_ready(struct mtd_info *mtd) return panic_nand_wait_ready(mtd, 400); led_trigger_event(nand_led_trigger, LED_FULL); - /* wait until command is processed or timeout occures */ + /* Wait until command is processed or timeout occurs */ do { if (chip->dev_ready(mtd)) break; @@ -531,13 +524,13 @@ EXPORT_SYMBOL_GPL(nand_wait_ready); /** * nand_command - [DEFAULT] Send command to NAND device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none * - * Send command to NAND device. This function is used for small page - * devices (256/512 Bytes per page) + * Send command to NAND device. This function is used for small page devices + * (256/512 Bytes per page). */ static void nand_command(struct mtd_info *mtd, unsigned int command, int column, int page_addr) @@ -545,9 +538,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, register struct nand_chip *chip = mtd->priv; int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; - /* - * Write out the command to the device. - */ + /* Write out the command to the device */ if (command == NAND_CMD_SEQIN) { int readcmd; @@ -567,9 +558,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, } chip->cmd_ctrl(mtd, command, ctrl); - /* - * Address cycle, when necessary - */ + /* Address cycle, when necessary */ ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; /* Serially input address */ if (column != -1) { @@ -590,8 +579,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* - * program and erase have their own busy handlers - * status and sequential in needs no delay + * Program and erase have their own busy handlers status and sequential + * in needs no delay */ switch (command) { @@ -625,8 +614,10 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, return; } } - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ ndelay(100); nand_wait_ready(mtd); @@ -634,14 +625,14 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, /** * nand_command_lp - [DEFAULT] Send command to NAND large page device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page - * devices We dont have the separate regions as we have in the small page - * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. + * devices. We don't have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. */ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, int column, int page_addr) @@ -683,8 +674,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* - * program and erase have their own busy handlers - * status, sequential in, and deplete1 need no delay + * Program and erase have their own busy handlers status, sequential + * in, and deplete1 need no delay. */ switch (command) { @@ -698,14 +689,12 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, case NAND_CMD_DEPLETE1: return; - /* - * read error status commands require only a short delay - */ case NAND_CMD_STATUS_ERROR: case NAND_CMD_STATUS_ERROR0: case NAND_CMD_STATUS_ERROR1: case NAND_CMD_STATUS_ERROR2: case NAND_CMD_STATUS_ERROR3: + /* Read error status commands require only a short delay */ udelay(chip->chip_delay); return; @@ -739,7 +728,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, default: /* * If we don't have access to the busy pin, we apply the given - * command delay + * command delay. */ if (!chip->dev_ready) { udelay(chip->chip_delay); @@ -747,8 +736,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, } } - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ ndelay(100); nand_wait_ready(mtd); @@ -756,25 +747,25 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, /** * panic_nand_get_device - [GENERIC] Get chip for selected access - * @chip: the nand chip descriptor - * @mtd: MTD device structure - * @new_state: the state which is requested + * @chip: the nand chip descriptor + * @mtd: MTD device structure + * @new_state: the state which is requested * * Used when in panic, no locks are taken. */ static void panic_nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) { - /* Hardware controller shared among independend devices */ + /* Hardware controller shared among independent devices */ chip->controller->active = chip; chip->state = new_state; } /** * nand_get_device - [GENERIC] Get chip for selected access - * @chip: the nand chip descriptor - * @mtd: MTD device structure - * @new_state: the state which is requested + * @chip: the nand chip descriptor + * @mtd: MTD device structure + * @new_state: the state which is requested * * Get the device and lock it for exclusive access */ @@ -812,10 +803,10 @@ retry: } /** - * panic_nand_wait - [GENERIC] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure - * @timeo: Timeout + * panic_nand_wait - [GENERIC] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure + * @timeo: timeout * * Wait for command done. This is a helper function for nand_wait used when * we are in interrupt context. May happen when in panic and trying to write @@ -838,13 +829,13 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_wait - [DEFAULT] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure + * nand_wait - [DEFAULT] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure * - * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to - * general NAND and SmartMedia specs + * Wait for command done. This applies to erase and program only. Erase can + * take up to 400ms and program up to 20ms according to general NAND and + * SmartMedia specs. */ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) { @@ -859,8 +850,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) led_trigger_event(nand_led_trigger, LED_FULL); - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in any + * case on any machine. + */ ndelay(100); if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) @@ -890,16 +883,15 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) /** * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * * @mtd: mtd info * @ofs: offset to start unlock from * @len: length to unlock - * @invert: when = 0, unlock the range of blocks within the lower and - * upper boundary address - * when = 1, unlock the range of blocks outside the boundaries - * of the lower and upper boundary address + * @invert: when = 0, unlock the range of blocks within the lower and + * upper boundary address + * when = 1, unlock the range of blocks outside the boundaries + * of the lower and upper boundary address * - * return - unlock status + * Returs unlock status. */ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len, int invert) @@ -919,10 +911,9 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, /* Call wait ready function */ status = chip->waitfunc(mtd, chip); - udelay(1000); /* See if device thinks it succeeded */ if (status & 0x01) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", + pr_debug("%s: error status = 0x%08x\n", __func__, status); ret = -EIO; } @@ -932,12 +923,11 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, /** * nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * * @mtd: mtd info * @ofs: offset to start unlock from * @len: length to unlock * - * return - unlock status + * Returns unlock status. */ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { @@ -945,7 +935,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) int chipnr; struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", + pr_debug("%s: start = 0x%012llx, len = %llu\n", __func__, (unsigned long long)ofs, len); if (check_offs_len(mtd, ofs, len)) @@ -964,7 +954,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", + pr_debug("%s: device is write protected!\n", __func__); ret = -EIO; goto out; @@ -981,18 +971,16 @@ EXPORT_SYMBOL(nand_unlock); /** * nand_lock - [REPLACEABLE] locks all blocks present in the device - * * @mtd: mtd info * @ofs: offset to start unlock from * @len: length to unlock * - * return - lock status + * This feature is not supported in many NAND parts. 'Micron' NAND parts do + * have this feature, but it allows only to lock all blocks, not for specified + * range for block. Implementing 'lock' feature by making use of 'unlock', for + * now. * - * This feature is not supported in many NAND parts. 'Micron' NAND parts - * do have this feature, but it allows only to lock all blocks, not for - * specified range for block. - * - * Implementing 'lock' feature by making use of 'unlock', for now. + * Returns lock status. */ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { @@ -1000,7 +988,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) int chipnr, status, page; struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", + pr_debug("%s: start = 0x%012llx, len = %llu\n", __func__, (unsigned long long)ofs, len); if (check_offs_len(mtd, ofs, len)) @@ -1015,7 +1003,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", + pr_debug("%s: device is write protected!\n", __func__); status = MTD_ERASE_FAILED; ret = -EIO; @@ -1028,10 +1016,9 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Call wait ready function */ status = chip->waitfunc(mtd, chip); - udelay(1000); /* See if device thinks it succeeded */ if (status & 0x01) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", + pr_debug("%s: error status = 0x%08x\n", __func__, status); ret = -EIO; goto out; @@ -1047,13 +1034,13 @@ out: EXPORT_SYMBOL(nand_lock); /** - * nand_read_page_raw - [Intern] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_raw - [INTERN] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ECC controllers, which use a special oob layout. */ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1064,11 +1051,11 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * * We need a special oob layout and handling even when OOB isn't used. */ @@ -1107,11 +1094,11 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, } /** - * nand_read_page_swecc - [REPLACABLE] software ecc based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read */ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1148,12 +1135,12 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @data_offs: offset of requested data within the page - * @readlen: data length - * @bufpoi: buffer to store read data + * nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @data_offs: offset of requested data within the page + * @readlen: data length + * @bufpoi: buffer to store read data */ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) @@ -1166,12 +1153,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; int index = 0; - /* Column address wihin the page aligned to ECC size (256bytes). */ + /* Column address within the page aligned to ECC size (256bytes) */ start_step = data_offs / chip->ecc.size; end_step = (data_offs + readlen - 1) / chip->ecc.size; num_steps = end_step - start_step + 1; - /* Data size aligned to ECC ecc.size*/ + /* Data size aligned to ECC ecc.size */ datafrag_len = num_steps * chip->ecc.size; eccfrag_len = num_steps * chip->ecc.bytes; @@ -1183,13 +1170,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, p = bufpoi + data_col_addr; chip->read_buf(mtd, p, datafrag_len); - /* Calculate ECC */ + /* Calculate ECC */ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); - /* The performance is faster if to position offsets - according to ecc.pos. Let make sure here that - there are no gaps in ecc positions */ + /* + * The performance is faster if we position offsets according to + * ecc.pos. Let's make sure that there are no gaps in ECC positions. + */ for (i = 0; i < eccfrag_len - 1; i++) { if (eccpos[i + start_step * chip->ecc.bytes] + 1 != eccpos[i + start_step * chip->ecc.bytes + 1]) { @@ -1201,8 +1189,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); } else { - /* send the command to read the particular ecc bytes */ - /* take care about buswidth alignment in read_buf */ + /* + * Send the command to read the particular ECC bytes take care + * about buswidth alignment in read_buf. + */ index = start_step * chip->ecc.bytes; aligned_pos = eccpos[index] & ~(busw - 1); @@ -1235,13 +1225,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * Not for syndrome calculating ecc controllers which need a special oob layout + * Not for syndrome calculating ECC controllers which need a special oob layout. */ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1280,18 +1270,17 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * Hardware ECC for large page chips, require OOB to be read first. - * For this ECC mode, the write_page method is re-used from ECC_HW. - * These methods read/write ECC from the OOB area, unlike the - * ECC_HW_SYNDROME support with multiple ECC steps, follows the - * "infix ECC" scheme and reads/writes ECC from the data area, by - * overwriting the NAND manufacturer bad block markings. + * Hardware ECC for large page chips, require OOB to be read first. For this + * ECC mode, the write_page method is re-used from ECC_HW. These methods + * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with + * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from + * the data area, by overwriting the NAND manufacturer bad block markings. */ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1329,14 +1318,14 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, } /** - * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling. */ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1384,29 +1373,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_transfer_oob - [Internal] Transfer oob to client buffer - * @chip: nand chip structure - * @oob: oob destination address - * @ops: oob ops structure - * @len: size of oob to transfer + * nand_transfer_oob - [INTERN] Transfer oob to client buffer + * @chip: nand chip structure + * @oob: oob destination address + * @ops: oob ops structure + * @len: size of oob to transfer */ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops, size_t len) { switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: memcpy(oob, chip->oob_poi + ops->ooboffs, len); return oob + len; - case MTD_OOB_AUTO: { + case MTD_OPS_AUTO_OOB: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, roffs = ops->ooboffs; size_t bytes = 0; for (; free->length && len; free++, len -= bytes) { - /* Read request not from offset 0 ? */ + /* Read request not from offset 0? */ if (unlikely(roffs)) { if (roffs >= free->length) { roffs -= free->length; @@ -1432,11 +1421,10 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, } /** - * nand_do_read_ops - [Internal] Read data with ECC - * - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob ops structure + * nand_do_read_ops - [INTERN] Read data with ECC + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob ops structure * * Internal function. Called with chip held. */ @@ -1451,7 +1439,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, int ret = 0; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; - uint32_t max_oobsize = ops->mode == MTD_OOB_AUTO ? + uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; uint8_t *bufpoi, *oob, *buf; @@ -1473,7 +1461,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, bytes = min(mtd->writesize - col, readlen); aligned = (bytes == mtd->writesize); - /* Is the current page in the buffer ? */ + /* Is the current page in the buffer? */ if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; @@ -1483,7 +1471,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, } /* Now read the page into the buffer */ - if (unlikely(ops->mode == MTD_OOB_RAW)) + if (unlikely(ops->mode == MTD_OPS_RAW)) ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, page); else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) @@ -1492,14 +1480,22 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, else ret = chip->ecc.read_page(mtd, chip, bufpoi, page); - if (ret < 0) + if (ret < 0) { + if (!aligned) + /* Invalidate page cache */ + chip->pagebuf = -1; break; + } /* Transfer not aligned data */ if (!aligned) { if (!NAND_SUBPAGE_READ(chip) && !oob && - !(mtd->ecc_stats.failed - stats.failed)) + !(mtd->ecc_stats.failed - stats.failed) && + (ops->mode != MTD_OPS_RAW)) chip->pagebuf = realpage; + else + /* Invalidate page cache */ + chip->pagebuf = -1; memcpy(buf, chip->buffers->databuf + col, bytes); } @@ -1539,7 +1535,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (!readlen) break; - /* For subsequent reads align to page boundary. */ + /* For subsequent reads align to page boundary */ col = 0; /* Increment page address */ realpage++; @@ -1552,8 +1548,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, chipnr); } - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. + /* + * Check, if the chip supports auto page increment or if we + * have hit a block boundary. */ if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) sndcmd = 1; @@ -1574,18 +1571,19 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /** * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc - * @mtd: MTD device structure - * @from: offset to read from - * @len: number of bytes to read - * @retlen: pointer to variable to store the number of read bytes - * @buf: the databuffer to put data + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data * - * Get hold of the chip and call nand_do_read + * Get hold of the chip and call nand_do_read. */ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; /* Do not allow reads past end of device */ @@ -1596,13 +1594,14 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, nand_get_device(chip, mtd, FL_READING); - chip->ops.len = len; - chip->ops.datbuf = buf; - chip->ops.oobbuf = NULL; + ops.len = len; + ops.datbuf = buf; + ops.oobbuf = NULL; + ops.mode = 0; - ret = nand_do_read_ops(mtd, from, &chip->ops); + ret = nand_do_read_ops(mtd, from, &ops); - *retlen = chip->ops.retlen; + *retlen = ops.retlen; nand_release_device(mtd); @@ -1610,11 +1609,11 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, } /** - * nand_read_oob_std - [REPLACABLE] the most common OOB data read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * @sndcmd: flag whether to issue read command or not + * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not */ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) @@ -1628,12 +1627,12 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC + * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC * with syndromes - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * @sndcmd: flag whether to issue read command or not + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not */ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) @@ -1667,10 +1666,10 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_oob_std - [REPLACABLE] the most common OOB data write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write + * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write */ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page) @@ -1690,11 +1689,11 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC - * with syndrome - only for large page flash ! - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write + * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC + * with syndrome - only for large page flash + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write */ static int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page) @@ -1749,34 +1748,37 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, } /** - * nand_do_read_oob - [Intern] NAND read out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operations description structure + * nand_do_read_oob - [INTERN] NAND read out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operations description structure * - * NAND read out-of-band data from the spare area + * NAND read out-of-band data from the spare area. */ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { int page, realpage, chipnr, sndcmd = 1; struct nand_chip *chip = mtd->priv; + struct mtd_ecc_stats stats; int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; int readlen = ops->ooblen; int len; uint8_t *buf = ops->oobbuf; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", + pr_debug("%s: from = 0x%08Lx, len = %i\n", __func__, (unsigned long long)from, readlen); - if (ops->mode == MTD_OOB_AUTO) + stats = mtd->ecc_stats; + + if (ops->mode == MTD_OPS_AUTO_OOB) len = chip->ecc.layout->oobavail; else len = mtd->oobsize; if (unlikely(ops->ooboffs >= len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read " - "outside oob\n", __func__); + pr_debug("%s: attempt to start read outside oob\n", + __func__); return -EINVAL; } @@ -1784,8 +1786,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, if (unlikely(from >= mtd->size || ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - (from >> chip->page_shift)) * len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end " - "of device\n", __func__); + pr_debug("%s: attempt to read beyond end of device\n", + __func__); return -EINVAL; } @@ -1797,7 +1799,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, page = realpage & chip->pagemask; while (1) { - sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); + if (ops->mode == MTD_OPS_RAW) + sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd); + else + sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); len = min(len, readlen); buf = nand_transfer_oob(chip, buf, ops, len); @@ -1830,24 +1835,29 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, chipnr); } - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. + /* + * Check, if the chip supports auto page increment or if we + * have hit a block boundary. */ if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) sndcmd = 1; } ops->oobretlen = ops->ooblen; - return 0; + + if (mtd->ecc_stats.failed - stats.failed) + return -EBADMSG; + + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } /** * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operation description structure + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure * - * NAND read data and/or out-of-band data + * NAND read data and/or out-of-band data. */ static int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) @@ -1859,17 +1869,17 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, /* Do not allow reads past end of device */ if (ops->datbuf && (from + ops->len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read " - "beyond end of device\n", __func__); + pr_debug("%s: attempt to read beyond end of device\n", + __func__); return -EINVAL; } nand_get_device(chip, mtd, FL_READING); switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: break; default: @@ -1888,12 +1898,12 @@ out: /** - * nand_write_page_raw - [Intern] raw page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_raw - [INTERN] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ECC controllers, which use a special oob layout. */ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -1903,10 +1913,10 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_raw_syndrome - [Intern] raw page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_raw_syndrome - [INTERN] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer * * We need a special oob layout and handling even when ECC isn't checked. */ @@ -1942,10 +1952,10 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, chip->write_buf(mtd, oob, size); } /** - * nand_write_page_swecc - [REPLACABLE] software ecc based page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer */ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -1957,7 +1967,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; - /* Software ecc calculation */ + /* Software ECC calculation */ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); @@ -1968,10 +1978,10 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer */ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -1996,13 +2006,13 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling. */ static void nand_write_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -2041,12 +2051,12 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, /** * nand_write_page - [REPLACEABLE] write one page - * @mtd: MTD device structure - * @chip: NAND chip descriptor - * @buf: the data to write - * @page: page number to write - * @cached: cached programming - * @raw: use _raw version of write_page + * @mtd: MTD device structure + * @chip: NAND chip descriptor + * @buf: the data to write + * @page: page number to write + * @cached: cached programming + * @raw: use _raw version of write_page */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int page, int cached, int raw) @@ -2061,8 +2071,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, chip->ecc.write_page(mtd, chip, buf); /* - * Cached progamming disabled for now, Not sure if its worth the - * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) + * Cached progamming disabled for now. Not sure if it's worth the + * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s). */ cached = 0; @@ -2072,7 +2082,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, status = chip->waitfunc(mtd, chip); /* * See if operation failed and additional status checks are - * available + * available. */ if ((status & NAND_STATUS_FAIL) && (chip->errstat)) status = chip->errstat(mtd, chip, FL_WRITING, status, @@ -2096,29 +2106,37 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_fill_oob - [Internal] Transfer client buffer to oob - * @chip: nand chip structure - * @oob: oob data buffer - * @len: oob data write length - * @ops: oob ops structure + * nand_fill_oob - [INTERN] Transfer client buffer to oob + * @mtd: MTD device structure + * @oob: oob data buffer + * @len: oob data write length + * @ops: oob ops structure */ -static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, - struct mtd_oob_ops *ops) +static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, + struct mtd_oob_ops *ops) { + struct nand_chip *chip = mtd->priv; + + /* + * Initialise to all 0xFF, to avoid the possibility of left over OOB + * data from a previous OOB read. + */ + memset(chip->oob_poi, 0xff, mtd->oobsize); + switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: memcpy(chip->oob_poi + ops->ooboffs, oob, len); return oob + len; - case MTD_OOB_AUTO: { + case MTD_OPS_AUTO_OOB: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, woffs = ops->ooboffs; size_t bytes = 0; for (; free->length && len; free++, len -= bytes) { - /* Write request not from offset 0 ? */ + /* Write request not from offset 0? */ if (unlikely(woffs)) { if (woffs >= free->length) { woffs -= free->length; @@ -2146,12 +2164,12 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, #define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) /** - * nand_do_write_ops - [Internal] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operations description structure + * nand_do_write_ops - [INTERN] NAND write with ECC + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operations description structure * - * NAND write with ECC + * NAND write with ECC. */ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2161,7 +2179,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, uint32_t writelen = ops->len; uint32_t oobwritelen = ops->ooblen; - uint32_t oobmaxlen = ops->mode == MTD_OOB_AUTO ? + uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; uint8_t *oob = ops->oobbuf; @@ -2172,10 +2190,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (!writelen) return 0; - /* reject writes, which are not page aligned */ + /* Reject writes, which are not page aligned */ if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { - printk(KERN_NOTICE "%s: Attempt to write not " - "page aligned data\n", __func__); + pr_notice("%s: attempt to write non page aligned data\n", + __func__); return -EINVAL; } @@ -2201,10 +2219,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, (chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; - /* If we're not given explicit OOB data, let it be 0xFF */ - if (likely(!oob)) - memset(chip->oob_poi, 0xff, mtd->oobsize); - /* Don't allow multipage oob writes with offset */ if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) return -EINVAL; @@ -2214,7 +2228,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, int cached = writelen > bytes && page != blockmask; uint8_t *wbuf = buf; - /* Partial page write ? */ + /* Partial page write? */ if (unlikely(column || writelen < (mtd->writesize - 1))) { cached = 0; bytes = min_t(int, bytes - column, (int) writelen); @@ -2226,12 +2240,15 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (unlikely(oob)) { size_t len = min(oobwritelen, oobmaxlen); - oob = nand_fill_oob(chip, oob, len, ops); + oob = nand_fill_oob(mtd, oob, len, ops); oobwritelen -= len; + } else { + /* We still need to erase leftover OOB data */ + memset(chip->oob_poi, 0xff, mtd->oobsize); } ret = chip->write_page(mtd, chip, wbuf, page, cached, - (ops->mode == MTD_OOB_RAW)); + (ops->mode == MTD_OPS_RAW)); if (ret) break; @@ -2260,11 +2277,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, /** * panic_nand_write - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write * * NAND write with ECC. Used when performing writes in interrupt context, this * may for example be called by mtdoops when writing an oops while in panic. @@ -2273,6 +2290,7 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; /* Do not allow reads past end of device */ @@ -2281,36 +2299,38 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, if (!len) return 0; - /* Wait for the device to get ready. */ + /* Wait for the device to get ready */ panic_nand_wait(mtd, chip, 400); - /* Grab the device. */ + /* Grab the device */ panic_nand_get_device(chip, mtd, FL_WRITING); - chip->ops.len = len; - chip->ops.datbuf = (uint8_t *)buf; - chip->ops.oobbuf = NULL; + ops.len = len; + ops.datbuf = (uint8_t *)buf; + ops.oobbuf = NULL; + ops.mode = 0; - ret = nand_do_write_ops(mtd, to, &chip->ops); + ret = nand_do_write_ops(mtd, to, &ops); - *retlen = chip->ops.retlen; + *retlen = ops.retlen; return ret; } /** * nand_write - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write * - * NAND write with ECC + * NAND write with ECC. */ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; /* Do not allow reads past end of device */ @@ -2321,13 +2341,14 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, nand_get_device(chip, mtd, FL_WRITING); - chip->ops.len = len; - chip->ops.datbuf = (uint8_t *)buf; - chip->ops.oobbuf = NULL; + ops.len = len; + ops.datbuf = (uint8_t *)buf; + ops.oobbuf = NULL; + ops.mode = 0; - ret = nand_do_write_ops(mtd, to, &chip->ops); + ret = nand_do_write_ops(mtd, to, &ops); - *retlen = chip->ops.retlen; + *retlen = ops.retlen; nand_release_device(mtd); @@ -2336,11 +2357,11 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, /** * nand_do_write_oob - [MTD Interface] NAND write out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure * - * NAND write out-of-band + * NAND write out-of-band. */ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2348,24 +2369,24 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, int chipnr, page, status, len; struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, (int)ops->ooblen); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) len = chip->ecc.layout->oobavail; else len = mtd->oobsize; /* Do not allow write past end of page */ if ((ops->ooboffs + ops->ooblen) > len) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to write " - "past end of page\n", __func__); + pr_debug("%s: attempt to write past end of page\n", + __func__); return -EINVAL; } if (unlikely(ops->ooboffs >= len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start " - "write outside oob\n", __func__); + pr_debug("%s: attempt to start write outside oob\n", + __func__); return -EINVAL; } @@ -2374,8 +2395,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, ops->ooboffs + ops->ooblen > ((mtd->size >> chip->page_shift) - (to >> chip->page_shift)) * len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " - "end of device\n", __func__); + pr_debug("%s: attempt to write beyond end of device\n", + __func__); return -EINVAL; } @@ -2401,10 +2422,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, if (page == chip->pagebuf) chip->pagebuf = -1; - memset(chip->oob_poi, 0xff, mtd->oobsize); - nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); - status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); - memset(chip->oob_poi, 0xff, mtd->oobsize); + nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); + + if (ops->mode == MTD_OPS_RAW) + status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask); + else + status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); if (status) return status; @@ -2416,9 +2439,9 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, /** * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure */ static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2430,17 +2453,17 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, /* Do not allow writes past end of device */ if (ops->datbuf && (to + ops->len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " - "end of device\n", __func__); + pr_debug("%s: attempt to write beyond end of device\n", + __func__); return -EINVAL; } nand_get_device(chip, mtd, FL_WRITING); switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: break; default: @@ -2458,11 +2481,11 @@ out: } /** - * single_erease_cmd - [GENERIC] NAND standard block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased + * single_erase_cmd - [GENERIC] NAND standard block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased * - * Standard erase command for NAND chips + * Standard erase command for NAND chips. */ static void single_erase_cmd(struct mtd_info *mtd, int page) { @@ -2473,12 +2496,11 @@ static void single_erase_cmd(struct mtd_info *mtd, int page) } /** - * multi_erease_cmd - [GENERIC] AND specific block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased + * multi_erase_cmd - [GENERIC] AND specific block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased * - * AND multi block erase command function - * Erase 4 consecutive blocks + * AND multi block erase command function. Erase 4 consecutive blocks. */ static void multi_erase_cmd(struct mtd_info *mtd, int page) { @@ -2493,10 +2515,10 @@ static void multi_erase_cmd(struct mtd_info *mtd, int page) /** * nand_erase - [MTD Interface] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction + * @mtd: MTD device structure + * @instr: erase instruction * - * Erase one ore more blocks + * Erase one ore more blocks. */ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) { @@ -2505,12 +2527,12 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) #define BBT_PAGE_MASK 0xffffff3f /** - * nand_erase_nand - [Internal] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction - * @allowbbt: allow erasing the bbt area + * nand_erase_nand - [INTERN] erase block(s) + * @mtd: MTD device structure + * @instr: erase instruction + * @allowbbt: allow erasing the bbt area * - * Erase one ore more blocks + * Erase one ore more blocks. */ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt) @@ -2521,9 +2543,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, unsigned int bbt_masked_page = 0xffffffff; loff_t len; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", - __func__, (unsigned long long)instr->addr, - (unsigned long long)instr->len); + pr_debug("%s: start = 0x%012llx, len = %llu\n", + __func__, (unsigned long long)instr->addr, + (unsigned long long)instr->len); if (check_offs_len(mtd, instr->addr, instr->len)) return -EINVAL; @@ -2545,8 +2567,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", - __func__); + pr_debug("%s: device is write protected!\n", + __func__); instr->state = MTD_ERASE_FAILED; goto erase_exit; } @@ -2555,7 +2577,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, * If BBT requires refresh, set the BBT page mask to see if the BBT * should be rewritten. Otherwise the mask is set to 0xffffffff which * can not be matched. This is also done when the bbt is actually - * erased to avoid recusrsive updates + * erased to avoid recursive updates. */ if (chip->options & BBT_AUTO_REFRESH && !allowbbt) bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK; @@ -2566,20 +2588,18 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, instr->state = MTD_ERASING; while (len) { - /* - * heck if we have a bad block, we do not erase bad blocks ! - */ + /* Heck if we have a bad block, we do not erase bad blocks! */ if (nand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, 0, allowbbt)) { - printk(KERN_WARNING "%s: attempt to erase a bad block " - "at page 0x%08x\n", __func__, page); + pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", + __func__, page); instr->state = MTD_ERASE_FAILED; goto erase_exit; } /* * Invalidate the page cache, if we erase the block which - * contains the current cached page + * contains the current cached page. */ if (page <= chip->pagebuf && chip->pagebuf < (page + pages_per_block)) @@ -2599,8 +2619,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* See if block erase succeeded */ if (status & NAND_STATUS_FAIL) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed erase, " - "page 0x%08x\n", __func__, page); + pr_debug("%s: failed erase, page 0x%08x\n", + __func__, page); instr->state = MTD_ERASE_FAILED; instr->fail_addr = ((loff_t)page << chip->page_shift); @@ -2609,7 +2629,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* * If BBT requires refresh, set the BBT rewrite flag to the - * page being erased + * page being erased. */ if (bbt_masked_page != 0xffffffff && (page & BBT_PAGE_MASK) == bbt_masked_page) @@ -2628,7 +2648,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* * If BBT requires refresh and BBT-PERCHIP, set the BBT - * page mask to see if this BBT should be rewritten + * page mask to see if this BBT should be rewritten. */ if (bbt_masked_page != 0xffffffff && (chip->bbt_td->options & NAND_BBT_PERCHIP)) @@ -2651,7 +2671,7 @@ erase_exit: /* * If BBT requires refresh and erase was successful, rewrite any - * selected bad block tables + * selected bad block tables. */ if (bbt_masked_page == 0xffffffff || ret) return ret; @@ -2659,10 +2679,10 @@ erase_exit: for (chipnr = 0; chipnr < chip->numchips; chipnr++) { if (!rewrite_bbt[chipnr]) continue; - /* update the BBT for chip */ - DEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt " - "(%d:0x%0llx 0x%0x)\n", __func__, chipnr, - rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); + /* Update the BBT for chip */ + pr_debug("%s: nand_update_bbt (%d:0x%0llx 0x%0x)\n", + __func__, chipnr, rewrite_bbt[chipnr], + chip->bbt_td->pages[chipnr]); nand_update_bbt(mtd, rewrite_bbt[chipnr]); } @@ -2672,15 +2692,15 @@ erase_exit: /** * nand_sync - [MTD Interface] sync - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Sync is actually a wait for chip ready function + * Sync is actually a wait for chip ready function. */ static void nand_sync(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); + pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ nand_get_device(chip, mtd, FL_SYNCING); @@ -2690,8 +2710,8 @@ static void nand_sync(struct mtd_info *mtd) /** * nand_block_isbad - [MTD Interface] Check if block at offset is bad - * @mtd: MTD device structure - * @offs: offset relative to mtd start + * @mtd: MTD device structure + * @offs: offset relative to mtd start */ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) { @@ -2704,8 +2724,8 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) /** * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad - * @mtd: MTD device structure - * @ofs: offset relative to mtd start + * @mtd: MTD device structure + * @ofs: offset relative to mtd start */ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) { @@ -2714,7 +2734,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) ret = nand_block_isbad(mtd, ofs); if (ret) { - /* If it was bad already, return success and do nothing. */ + /* If it was bad already, return success and do nothing */ if (ret > 0) return 0; return ret; @@ -2725,7 +2745,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) /** * nand_suspend - [MTD Interface] Suspend the NAND flash - * @mtd: MTD device structure + * @mtd: MTD device structure */ static int nand_suspend(struct mtd_info *mtd) { @@ -2736,7 +2756,7 @@ static int nand_suspend(struct mtd_info *mtd) /** * nand_resume - [MTD Interface] Resume the NAND flash - * @mtd: MTD device structure + * @mtd: MTD device structure */ static void nand_resume(struct mtd_info *mtd) { @@ -2745,13 +2765,11 @@ static void nand_resume(struct mtd_info *mtd) if (chip->state == FL_PM_SUSPENDED) nand_release_device(mtd); else - printk(KERN_ERR "%s called for a chip which is not " - "in suspended state\n", __func__); + pr_err("%s called for a chip which is not in suspended state\n", + __func__); } -/* - * Set default functions - */ +/* Set default functions */ static void nand_set_defaults(struct nand_chip *chip, int busw) { /* check for proper chip_delay setup, set 20us if not */ @@ -2793,23 +2811,21 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) } -/* - * sanitize ONFI strings so we can safely print them - */ +/* Sanitize ONFI strings so we can safely print them */ static void sanitize_string(uint8_t *s, size_t len) { ssize_t i; - /* null terminate */ + /* Null terminate */ s[len - 1] = 0; - /* remove non printable chars */ + /* Remove non printable chars */ for (i = 0; i < len - 1; i++) { if (s[i] < ' ' || s[i] > 127) s[i] = '?'; } - /* remove trailing spaces */ + /* Remove trailing spaces */ strim(s); } @@ -2826,28 +2842,28 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) } /* - * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, - int busw) + int *busw) { struct nand_onfi_params *p = &chip->onfi_params; int i; int val; - /* try ONFI for unknow chip or LP */ + /* Try ONFI for unknown chip or LP */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') return 0; - printk(KERN_INFO "ONFI flash detected\n"); + pr_info("ONFI flash detected\n"); chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); for (i = 0; i < 3; i++) { chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { - printk(KERN_INFO "ONFI param page %d valid\n", i); + pr_info("ONFI param page %d valid\n", i); break; } } @@ -2855,7 +2871,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, if (i == 3) return 0; - /* check version */ + /* Check version */ val = le16_to_cpu(p->revision); if (val & (1 << 5)) chip->onfi_version = 23; @@ -2871,8 +2887,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->onfi_version = 0; if (!chip->onfi_version) { - printk(KERN_INFO "%s: unsupported ONFI version: %d\n", - __func__, val); + pr_info("%s: unsupported ONFI version: %d\n", __func__, val); return 0; } @@ -2884,9 +2899,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; - busw = 0; + *busw = 0; if (le16_to_cpu(p->features) & 1) - busw = NAND_BUSWIDTH_16; + *busw = NAND_BUSWIDTH_16; chip->options &= ~NAND_CHIPOPTIONS_MSK; chip->options |= (NAND_NO_READRDY | @@ -2896,7 +2911,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, } /* - * Get the flash and manufacturer id and lookup if the type is supported + * Get the flash and manufacturer id and lookup if the type is supported. */ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, @@ -2913,7 +2928,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) - * after power-up + * after power-up. */ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); @@ -2924,7 +2939,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, *maf_id = chip->read_byte(mtd); *dev_id = chip->read_byte(mtd); - /* Try again to make sure, as some systems the bus-hold or other + /* + * Try again to make sure, as some systems the bus-hold or other * interface concerns can cause random data which looks like a * possibly credible NAND flash to appear. If the two results do * not match, ignore the device completely. @@ -2936,9 +2952,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, id_data[i] = chip->read_byte(mtd); if (id_data[0] != *maf_id || id_data[1] != *dev_id) { - printk(KERN_INFO "%s: second ID read did not match " - "%02x,%02x against %02x,%02x\n", __func__, - *maf_id, *dev_id, id_data[0], id_data[1]); + pr_info("%s: second ID read did not match " + "%02x,%02x against %02x,%02x\n", __func__, + *maf_id, *dev_id, id_data[0], id_data[1]); return ERR_PTR(-ENODEV); } @@ -2952,7 +2968,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->onfi_version = 0; if (!type->name || !type->pagesize) { /* Check is chip is ONFI compliant */ - ret = nand_flash_detect_onfi(mtd, chip, busw); + ret = nand_flash_detect_onfi(mtd, chip, &busw); if (ret) goto ident_done; } @@ -2973,7 +2989,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chipsize = (uint64_t)type->chipsize << 20; if (!type->pagesize && chip->init_size) { - /* set the pagesize, oobsize, erasesize by the driver*/ + /* Set the pagesize, oobsize, erasesize by the driver */ busw = chip->init_size(mtd, chip, id_data); } else if (!type->pagesize) { int extid; @@ -3033,7 +3049,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, } } else { /* - * Old devices have chip data hardcoded in the device id table + * Old devices have chip data hardcoded in the device id table. */ mtd->erasesize = type->erasesize; mtd->writesize = type->pagesize; @@ -3043,7 +3059,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* * Check for Spansion/AMD ID + repeating 5th, 6th byte since * some Spansion chips have erasesize that conflicts with size - * listed in nand_ids table + * listed in nand_ids table. * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) */ if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && @@ -3057,15 +3073,16 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->options &= ~NAND_CHIPOPTIONS_MSK; chip->options |= type->options & NAND_CHIPOPTIONS_MSK; - /* Check if chip is a not a samsung device. Do not clear the - * options for chips which are not having an extended id. + /* + * Check if chip is not a Samsung device. Do not clear the + * options for chips which do not have an extended id. */ if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; ident_done: /* - * Set chip as a default. Board drivers can override it, if necessary + * Set chip as a default. Board drivers can override it, if necessary. */ chip->options |= NAND_NO_AUTOINCR; @@ -3077,21 +3094,21 @@ ident_done: /* * Check, if buswidth is correct. Hardware drivers should set - * chip correct ! + * chip correct! */ if (busw != (chip->options & NAND_BUSWIDTH_16)) { - printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); - printk(KERN_WARNING "NAND bus width %d instead %d bit\n", - (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, - busw ? 16 : 8); + pr_info("NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, + *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); + pr_warn("NAND bus width %d instead %d bit\n", + (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, + busw ? 16 : 8); return ERR_PTR(-EINVAL); } /* Calculate the address shift from the page size */ chip->page_shift = ffs(mtd->writesize) - 1; - /* Convert chipsize to number of pages per chip -1. */ + /* Convert chipsize to number of pages per chip -1 */ chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; chip->bbt_erase_shift = chip->phys_erase_shift = @@ -3121,7 +3138,7 @@ ident_done: if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || *maf_id == NAND_MFR_HYNIX)) - chip->options |= NAND_BBT_SCANLASTPAGE; + chip->bbt_options |= NAND_BBT_SCANLASTPAGE; else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || *maf_id == NAND_MFR_HYNIX || @@ -3129,17 +3146,7 @@ ident_done: *maf_id == NAND_MFR_AMD)) || (mtd->writesize == 2048 && *maf_id == NAND_MFR_MICRON)) - chip->options |= NAND_BBT_SCAN2NDPAGE; - - /* - * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6 - */ - if (!(busw & NAND_BUSWIDTH_16) && - *maf_id == NAND_MFR_STMICRO && - mtd->writesize == 2048) { - chip->options |= NAND_BBT_SCANBYTE1AND6; - chip->badblockpos = 0; - } + chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; /* Check for AND chips with 4 page planes */ if (chip->options & NAND_4PAGE_ARRAY) @@ -3147,12 +3154,11 @@ ident_done: else chip->erase_cmd = single_erase_cmd; - /* Do not replace user supplied command function ! */ + /* Do not replace user supplied command function! */ if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - /* TODO onfi flash name */ - printk(KERN_INFO "NAND device: Manufacturer ID:" + pr_info("NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, chip->onfi_version ? chip->onfi_params.model : type->name); @@ -3162,12 +3168,12 @@ ident_done: /** * nand_scan_ident - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * @table: Alternative NAND ID table + * @mtd: MTD device structure + * @maxchips: number of chips to scan for + * @table: alternative NAND ID table * - * This is the first phase of the normal nand_scan() function. It - * reads the flash ID and sets up MTD fields accordingly. + * This is the first phase of the normal nand_scan() function. It reads the + * flash ID and sets up MTD fields accordingly. * * The mtd->owner field must be set to the module of the caller. */ @@ -3189,7 +3195,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, if (IS_ERR(type)) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) - printk(KERN_WARNING "No NAND device found.\n"); + pr_warn("No NAND device found\n"); chip->select_chip(mtd, -1); return PTR_ERR(type); } @@ -3207,7 +3213,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, break; } if (i > 1) - printk(KERN_INFO "%d NAND chips detected\n", i); + pr_info("%d NAND chips detected\n", i); /* Store the number of chips and calc total size for mtd */ chip->numchips = i; @@ -3220,11 +3226,11 @@ EXPORT_SYMBOL(nand_scan_ident); /** * nand_scan_tail - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure + * @mtd: MTD device structure * - * This is the second phase of the normal nand_scan() function. It - * fills out all the uninitialized function pointers with the defaults - * and scans for a bad block table if appropriate. + * This is the second phase of the normal nand_scan() function. It fills out + * all the uninitialized function pointers with the defaults and scans for a + * bad block table if appropriate. */ int nand_scan_tail(struct mtd_info *mtd) { @@ -3240,7 +3246,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->oob_poi = chip->buffers->databuf + mtd->writesize; /* - * If no default placement scheme is given, select an appropriate one + * If no default placement scheme is given, select an appropriate one. */ if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) { switch (mtd->oobsize) { @@ -3257,8 +3263,8 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.layout = &nand_oob_128; break; default: - printk(KERN_WARNING "No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); + pr_warn("No oob scheme defined for oobsize %d\n", + mtd->oobsize); BUG(); } } @@ -3267,7 +3273,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->write_page = nand_write_page; /* - * check ECC mode, default to software if 3byte/512byte hardware ECC is + * Check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */ @@ -3276,15 +3282,15 @@ int nand_scan_tail(struct mtd_info *mtd) /* Similar to NAND_ECC_HW, but a separate read_page handle */ if (!chip->ecc.calculate || !chip->ecc.correct || !chip->ecc.hwctl) { - printk(KERN_WARNING "No ECC functions supplied; " - "Hardware ECC not possible\n"); + pr_warn("No ECC functions supplied; " + "hardware ECC not possible\n"); BUG(); } if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_hwecc_oob_first; case NAND_ECC_HW: - /* Use standard hwecc read page function ? */ + /* Use standard hwecc read page function? */ if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_hwecc; if (!chip->ecc.write_page) @@ -3305,11 +3311,11 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.read_page == nand_read_page_hwecc || !chip->ecc.write_page || chip->ecc.write_page == nand_write_page_hwecc)) { - printk(KERN_WARNING "No ECC functions supplied; " - "Hardware ECC not possible\n"); + pr_warn("No ECC functions supplied; " + "hardware ECC not possible\n"); BUG(); } - /* Use standard syndrome read/write page function ? */ + /* Use standard syndrome read/write page function? */ if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_syndrome; if (!chip->ecc.write_page) @@ -3325,9 +3331,9 @@ int nand_scan_tail(struct mtd_info *mtd) if (mtd->writesize >= chip->ecc.size) break; - printk(KERN_WARNING "%d byte HW ECC not possible on " - "%d byte page size, fallback to SW ECC\n", - chip->ecc.size, mtd->writesize); + pr_warn("%d byte HW ECC not possible on " + "%d byte page size, fallback to SW ECC\n", + chip->ecc.size, mtd->writesize); chip->ecc.mode = NAND_ECC_SOFT; case NAND_ECC_SOFT: @@ -3347,7 +3353,7 @@ int nand_scan_tail(struct mtd_info *mtd) case NAND_ECC_SOFT_BCH: if (!mtd_nand_has_bch()) { - printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n"); + pr_warn("CONFIG_MTD_ECC_BCH not enabled\n"); BUG(); } chip->ecc.calculate = nand_bch_calculate_ecc; @@ -3362,8 +3368,8 @@ int nand_scan_tail(struct mtd_info *mtd) /* * Board driver should supply ecc.size and ecc.bytes values to * select how many bits are correctable; see nand_bch_init() - * for details. - * Otherwise, default to 4 bits for large page devices + * for details. Otherwise, default to 4 bits for large page + * devices. */ if (!chip->ecc.size && (mtd->oobsize >= 64)) { chip->ecc.size = 512; @@ -3374,14 +3380,14 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.bytes, &chip->ecc.layout); if (!chip->ecc.priv) { - printk(KERN_WARNING "BCH ECC initialization failed!\n"); + pr_warn("BCH ECC initialization failed!\n"); BUG(); } break; case NAND_ECC_NONE: - printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " - "This is not recommended !!\n"); + pr_warn("NAND_ECC_NONE selected by board driver. " + "This is not recommended!\n"); chip->ecc.read_page = nand_read_page_raw; chip->ecc.write_page = nand_write_page_raw; chip->ecc.read_oob = nand_read_oob_std; @@ -3393,14 +3399,19 @@ int nand_scan_tail(struct mtd_info *mtd) break; default: - printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", - chip->ecc.mode); + pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); BUG(); } + /* For many systems, the standard OOB write also works for raw */ + if (!chip->ecc.read_oob_raw) + chip->ecc.read_oob_raw = chip->ecc.read_oob; + if (!chip->ecc.write_oob_raw) + chip->ecc.write_oob_raw = chip->ecc.write_oob; + /* * The number of bytes available for a client to place data into - * the out of band area + * the out of band area. */ chip->ecc.layout->oobavail = 0; for (i = 0; chip->ecc.layout->oobfree[i].length @@ -3411,19 +3422,16 @@ int nand_scan_tail(struct mtd_info *mtd) /* * Set the number of read / write steps for one page depending on ECC - * mode + * mode. */ chip->ecc.steps = mtd->writesize / chip->ecc.size; if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { - printk(KERN_WARNING "Invalid ecc parameters\n"); + pr_warn("Invalid ECC parameters\n"); BUG(); } chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; - /* - * Allow subpage writes up to ecc.steps. Not possible for MLC - * FLASH. - */ + /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { switch (chip->ecc.steps) { @@ -3481,9 +3489,11 @@ int nand_scan_tail(struct mtd_info *mtd) } EXPORT_SYMBOL(nand_scan_tail); -/* is_module_text_address() isn't exported, and it's mostly a pointless +/* + * is_module_text_address() isn't exported, and it's mostly a pointless * test if this is a module _anyway_ -- they'd have to try _really_ hard - * to call us from in-kernel code if the core NAND support is modular. */ + * to call us from in-kernel code if the core NAND support is modular. + */ #ifdef MODULE #define caller_is_module() (1) #else @@ -3493,15 +3503,13 @@ EXPORT_SYMBOL(nand_scan_tail); /** * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * - * This fills out all the uninitialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. - * The mtd->owner field must be set to the module of the caller + * @mtd: MTD device structure + * @maxchips: number of chips to scan for * + * This fills out all the uninitialized function pointers with the defaults. + * The flash ID is read and the mtd/chip structures are filled with the + * appropriate values. The mtd->owner field must be set to the module of the + * caller. */ int nand_scan(struct mtd_info *mtd, int maxchips) { @@ -3509,8 +3517,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips) /* Many callers got this wrong, so check for it for a while... */ if (!mtd->owner && caller_is_module()) { - printk(KERN_CRIT "%s called with NULL mtd->owner!\n", - __func__); + pr_crit("%s called with NULL mtd->owner!\n", __func__); BUG(); } @@ -3523,8 +3530,8 @@ EXPORT_SYMBOL(nand_scan); /** * nand_release - [NAND Interface] Free resources held by the NAND device - * @mtd: MTD device structure -*/ + * @mtd: MTD device structure + */ void nand_release(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ccbeaa1e4a8e..69148ae3bf58 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -14,7 +14,7 @@ * * When nand_scan_bbt is called, then it tries to find the bad block table * depending on the options in the BBT descriptor(s). If no flash based BBT - * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory + * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory * marked good / bad blocks. This information is used to create a memory BBT. * Once a new bad block is discovered then the "factory" information is updated * on the device. @@ -36,9 +36,9 @@ * The table is marked in the OOB area with an ident pattern and a version * number which indicates which of both tables is more up to date. If the NAND * controller needs the complete OOB area for the ECC information then the - * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern - * and the version byte into the data area and the OOB area will remain - * untouched. + * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of + * course): it moves the ident pattern and the version byte into the data area + * and the OOB area will remain untouched. * * The table uses 2 bits per block * 11b: block is good @@ -67,6 +67,7 @@ #include <linux/bitops.h> #include <linux/delay.h> #include <linux/vmalloc.h> +#include <linux/export.h> static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) { @@ -80,17 +81,15 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) /** * check_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @len: the length of buffer to search - * @paglen: the pagelength - * @td: search pattern descriptor + * @buf: the buffer to search + * @len: the length of buffer to search + * @paglen: the pagelength + * @td: search pattern descriptor * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. - * If the SCAN_EMPTY option is set then check, if all bytes except the - * pattern area contain 0xff - * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if + * all bytes except the pattern area contain 0xff. + */ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) { int i, end = 0; @@ -109,32 +108,8 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc p += end; /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[i] != td->pattern[i]) - return -1; - } - - /* Check both positions 1 and 6 for pattern? */ - if (td->options & NAND_BBT_SCANBYTE1AND6) { - if (td->options & NAND_BBT_SCANEMPTY) { - p += td->len; - end += NAND_SMALL_BADBLOCK_POS - td->offs; - /* Check region between positions 1 and 6 */ - for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len; - i++) { - if (*p++ != 0xff) - return -1; - } - } - else { - p += NAND_SMALL_BADBLOCK_POS - td->offs; - } - /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[i] != td->pattern[i]) - return -1; - } - } + if (memcmp(p, td->pattern, td->len)) + return -1; if (td->options & NAND_BBT_SCANEMPTY) { p += td->len; @@ -149,14 +124,13 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc /** * check_short_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @td: search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. Same as check_pattern, but - * no optional empty check + * @buf: the buffer to search + * @td: search pattern descriptor * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. Same as check_pattern, but no optional empty + * check. + */ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) { int i; @@ -167,21 +141,14 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) if (p[td->offs + i] != td->pattern[i]) return -1; } - /* Need to check location 1 AND 6? */ - if (td->options & NAND_BBT_SCANBYTE1AND6) { - for (i = 0; i < td->len; i++) { - if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i]) - return -1; - } - } return 0; } /** * add_marker_len - compute the length of the marker in data area - * @td: BBT descriptor used for computation + * @td: BBT descriptor used for computation * - * The length will be 0 if the markeris located in OOB area. + * The length will be 0 if the marker is located in OOB area. */ static u32 add_marker_len(struct nand_bbt_descr *td) { @@ -198,34 +165,33 @@ static u32 add_marker_len(struct nand_bbt_descr *td) /** * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd: MTD device structure - * @buf: temporary buffer - * @page: the starting page - * @num: the number of bbt descriptors to read - * @td: the bbt describtion table - * @offs: offset in the memory table + * @mtd: MTD device structure + * @buf: temporary buffer + * @page: the starting page + * @num: the number of bbt descriptors to read + * @td: the bbt describtion table + * @offs: offset in the memory table * * Read the bad block table starting from page. - * */ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, struct nand_bbt_descr *td, int offs) { - int res, i, j, act = 0; + int res, ret = 0, i, j, act = 0; struct nand_chip *this = mtd->priv; size_t retlen, len, totlen; loff_t from; int bits = td->options & NAND_BBT_NRBITS_MSK; - uint8_t msk = (uint8_t) ((1 << bits) - 1); + uint8_t msk = (uint8_t)((1 << bits) - 1); u32 marker_len; int reserved_block_code = td->reserved_block_code; totlen = (num * bits) >> 3; marker_len = add_marker_len(td); - from = ((loff_t) page) << this->page_shift; + from = ((loff_t)page) << this->page_shift; while (totlen) { - len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); + len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); if (marker_len) { /* * In case the BBT marker is not in the OOB area it @@ -237,11 +203,18 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, } res = mtd->read(mtd, from, len, &retlen, buf); if (res < 0) { - if (retlen != len) { - printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); + if (mtd_is_eccerr(res)) { + pr_info("nand_bbt: ECC error in BBT at " + "0x%012llx\n", from & ~mtd->writesize); + return res; + } else if (mtd_is_bitflip(res)) { + pr_info("nand_bbt: corrected error in BBT at " + "0x%012llx\n", from & ~mtd->writesize); + ret = res; + } else { + pr_info("nand_bbt: error reading BBT\n"); return res; } - printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); } /* Analyse data */ @@ -252,17 +225,19 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, if (tmp == msk) continue; if (reserved_block_code && (tmp == reserved_block_code)) { - printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + pr_info("nand_read_bbt: reserved block at 0x%012llx\n", + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); mtd->ecc_stats.bbtblocks++; continue; } - /* Leave it for now, if its matured we can move this - * message to MTD_DEBUG_LEVEL0 */ - printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); - /* Factory marked bad or worn out ? */ + /* + * Leave it for now, if it's matured we can + * move this message to pr_debug. + */ + pr_info("nand_read_bbt: bad block at 0x%012llx\n", + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + /* Factory marked bad or worn out? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); else @@ -273,20 +248,20 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, totlen -= len; from += len; } - return 0; + return ret; } /** * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @chip: read the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @chip: read the table for a specific chip, -1 read all chips; applies only if + * NAND_BBT_PERCHIP option is set * - * Read the bad block table for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. -*/ + * Read the bad block table for all chips starting at a given page. We assume + * that the bbt bits are in consecutive order. + */ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) { struct nand_chip *this = mtd->priv; @@ -312,9 +287,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc return 0; } -/* - * BBT marker is in the first page, no OOB. - */ +/* BBT marker is in the first page, no OOB */ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, struct nand_bbt_descr *td) { @@ -328,35 +301,26 @@ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, return mtd->read(mtd, offs, len, &retlen, buf); } -/* - * Scan read raw data from flash - */ +/* Scan read raw data from flash */ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, size_t len) { struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; - while (len > 0) { - if (len <= mtd->writesize) { - ops.oobbuf = buf + len; - ops.datbuf = buf; - ops.len = len; - return mtd->read_oob(mtd, offs, &ops); - } else { - ops.oobbuf = buf + mtd->writesize; - ops.datbuf = buf; - ops.len = mtd->writesize; - res = mtd->read_oob(mtd, offs, &ops); + ops.datbuf = buf; + ops.len = min(len, (size_t)mtd->writesize); + ops.oobbuf = buf + ops.len; - if (res) - return res; - } + res = mtd->read_oob(mtd, offs, &ops); + + if (res) + return res; buf += mtd->oobsize + mtd->writesize; len -= mtd->writesize; @@ -373,15 +337,13 @@ static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, return scan_read_raw_oob(mtd, buf, offs, len); } -/* - * Scan write data with oob to flash - */ +/* Scan write data with oob to flash */ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, uint8_t *buf, uint8_t *oob) { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; ops.datbuf = buf; @@ -402,15 +364,14 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror * - * Read the bad block table(s) for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. - * -*/ + * Read the bad block table(s) for all chips starting at a given page. We + * assume that the bbt bits are in consecutive order. + */ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { @@ -421,8 +382,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, mtd->writesize, td); td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; - printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", - td->pages[0], td->version[0]); + pr_info("Bad block table at page %d, version 0x%02X\n", + td->pages[0], td->version[0]); } /* Read the mirror version, if available */ @@ -430,15 +391,13 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, mtd->writesize, td); md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; - printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", - md->pages[0], md->version[0]); + pr_info("Bad block table at page %d, version 0x%02X\n", + md->pages[0], md->version[0]); } return 1; } -/* - * Scan a given block full - */ +/* Scan a given block full */ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, loff_t offs, uint8_t *buf, size_t readlen, int scanlen, int len) @@ -446,7 +405,8 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, int ret, j; ret = scan_read_raw_oob(mtd, buf, offs, readlen); - if (ret) + /* Ignore ECC errors when checking for BBM */ + if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; for (j = 0; j < len; j++, buf += scanlen) { @@ -456,9 +416,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, return 0; } -/* - * Scan a given block partially - */ +/* Scan a given block partially */ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, loff_t offs, uint8_t *buf, int len) { @@ -469,16 +427,16 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, ops.oobbuf = buf; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; for (j = 0; j < len; j++) { /* - * Read the full oob until read_oob is fixed to - * handle single byte reads for 16 bit - * buswidth + * Read the full oob until read_oob is fixed to handle single + * byte reads for 16 bit buswidth. */ ret = mtd->read_oob(mtd, offs, &ops); - if (ret) + /* Ignore ECC errors when checking for BBM */ + if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; if (check_short_pattern(buf, bd)) @@ -491,14 +449,14 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, /** * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern - * @chip: create the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * @chip: create the table for a specific chip, -1 read all chips; applies only + * if NAND_BBT_PERCHIP option is set * - * Create a bad block table by scanning the device - * for the given good/bad block identify pattern + * Create a bad block table by scanning the device for the given good/bad block + * identify pattern. */ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) @@ -509,7 +467,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, loff_t from; size_t readlen; - printk(KERN_INFO "Scanning device for bad blocks\n"); + pr_info("Scanning device for bad blocks\n"); if (bd->options & NAND_BBT_SCANALLPAGES) len = 1 << (this->bbt_erase_shift - this->page_shift); @@ -529,14 +487,16 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, } if (chip == -1) { - /* Note that numblocks is 2 * (real numblocks) here, see i+=2 - * below as it makes shifting and masking less painful */ + /* + * Note that numblocks is 2 * (real numblocks) here, see i+=2 + * below as it makes shifting and masking less painful + */ numblocks = mtd->size >> (this->bbt_erase_shift - 1); startblock = 0; from = 0; } else { if (chip >= this->numchips) { - printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", + pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n", chip + 1, this->numchips); return -EINVAL; } @@ -546,7 +506,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, from = (loff_t)startblock << (this->bbt_erase_shift - 1); } - if (this->options & NAND_BBT_SCANLASTPAGE) + if (this->bbt_options & NAND_BBT_SCANLASTPAGE) from += mtd->erasesize - (mtd->writesize * len); for (i = startblock; i < numblocks;) { @@ -565,8 +525,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, if (ret) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk(KERN_WARNING "Bad eraseblock %d at 0x%012llx\n", - i >> 1, (unsigned long long)from); + pr_warn("Bad eraseblock %d at 0x%012llx\n", + i >> 1, (unsigned long long)from); mtd->ecc_stats.badblocks++; } @@ -578,20 +538,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, /** * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table * - * Read the bad block table by searching for a given ident pattern. - * Search is preformed either from the beginning up or from the end of - * the device downwards. The search starts always at the start of a - * block. - * If the option NAND_BBT_PERCHIP is given, each chip is searched - * for a bbt, which contains the bad block information of this chip. - * This is necessary to provide support for certain DOC devices. + * Read the bad block table by searching for a given ident pattern. Search is + * preformed either from the beginning up or from the end of the device + * downwards. The search starts always at the start of a block. If the option + * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains + * the bad block information of this chip. This is necessary to provide support + * for certain DOC devices. * - * The bbt ident pattern resides in the oob area of the first page - * in a block. + * The bbt ident pattern resides in the oob area of the first page in a block. */ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) { @@ -602,7 +560,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr int bbtblocks; int blocktopage = this->bbt_erase_shift - this->page_shift; - /* Search direction top -> down ? */ + /* Search direction top -> down? */ if (td->options & NAND_BBT_LASTBLOCK) { startblock = (mtd->size >> this->bbt_erase_shift) - 1; dir = -1; @@ -611,7 +569,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr dir = 1; } - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; bbtblocks = this->chipsize >> this->bbt_erase_shift; @@ -650,23 +608,23 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /* Check, if we found a bbt for each requested chip */ for (i = 0; i < chips; i++) { if (td->pages[i] == -1) - printk(KERN_WARNING "Bad block table not found for chip %d\n", i); + pr_warn("Bad block table not found for chip %d\n", i); else - printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], - td->version[i]); + pr_info("Bad block table found at page %d, version " + "0x%02X\n", td->pages[i], td->version[i]); } return 0; } /** * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror * - * Search and read the bad block table(s) -*/ + * Search and read the bad block table(s). + */ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { /* Search the primary table */ @@ -682,16 +640,14 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt /** * write_bbt - [GENERIC] (Re)write the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * @chipsel: selector for a specific chip, -1 for all * - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * @chipsel: selector for a specific chip, -1 for all - * - * (Re)write the bad block table - * -*/ + * (Re)write the bad block table. + */ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) @@ -710,14 +666,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ops.ooblen = mtd->oobsize; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; if (!rcode) rcode = 0xff; - /* Write bad block table per chip rather than per device ? */ + /* Write bad block table per chip rather than per device? */ if (td->options & NAND_BBT_PERCHIP) { numblocks = (int)(this->chipsize >> this->bbt_erase_shift); - /* Full device write or specific chip ? */ + /* Full device write or specific chip? */ if (chipsel == -1) { nrchips = this->numchips; } else { @@ -731,8 +687,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, /* Loop through the chips */ for (; chip < nrchips; chip++) { - - /* There was already a version of the table, reuse the page + /* + * There was already a version of the table, reuse the page * This applies for absolute placement too, as we have the * page nr. in td->pages. */ @@ -741,8 +697,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, goto write; } - /* Automatic placement of the bad block table */ - /* Search direction top -> down ? */ + /* + * Automatic placement of the bad block table. Search direction + * top -> down? + */ if (td->options & NAND_BBT_LASTBLOCK) { startblock = numblocks * (chip + 1) - 1; dir = -1; @@ -766,7 +724,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (!md || md->pages[chip] != page) goto write; } - printk(KERN_ERR "No space left to write bad block table\n"); + pr_err("No space left to write bad block table\n"); return -ENOSPC; write: @@ -791,24 +749,22 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, bbtoffs = chip * (numblocks >> 2); - to = ((loff_t) page) << this->page_shift; + to = ((loff_t)page) << this->page_shift; - /* Must we save the block contents ? */ + /* Must we save the block contents? */ if (td->options & NAND_BBT_SAVECONTENT) { /* Make it block aligned */ - to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); + to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1)); len = 1 << this->bbt_erase_shift; res = mtd->read(mtd, to, len, &retlen, buf); if (res < 0) { if (retlen != len) { - printk(KERN_INFO "nand_bbt: Error " - "reading block for writing " - "the bad block table\n"); + pr_info("nand_bbt: error reading block " + "for writing the bad block table\n"); return res; } - printk(KERN_WARNING "nand_bbt: ECC error " - "while reading block for writing " - "bad block table\n"); + pr_warn("nand_bbt: ECC error while reading " + "block for writing bad block table\n"); } /* Read oob data */ ops.ooblen = (len >> this->page_shift) * mtd->oobsize; @@ -821,19 +777,19 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, pageoffs = page - (int)(to >> this->page_shift); offs = pageoffs << this->page_shift; /* Preset the bbt area with 0xff */ - memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); + memset(&buf[offs], 0xff, (size_t)(numblocks >> sft)); ooboffs = len + (pageoffs * mtd->oobsize); } else if (td->options & NAND_BBT_NO_OOB) { ooboffs = 0; offs = td->len; - /* the version byte */ + /* The version byte */ if (td->options & NAND_BBT_VERSION) offs++; /* Calc length */ - len = (size_t) (numblocks >> sft); + len = (size_t)(numblocks >> sft); len += offs; - /* Make it page aligned ! */ + /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ memset(buf, 0xff, len); @@ -841,8 +797,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, memcpy(buf, td->pattern, td->len); } else { /* Calc length */ - len = (size_t) (numblocks >> sft); - /* Make it page aligned ! */ + len = (size_t)(numblocks >> sft); + /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ memset(buf, 0xff, len + @@ -856,13 +812,13 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (td->options & NAND_BBT_VERSION) buf[ooboffs + td->veroffs] = td->version[chip]; - /* walk through the memory table */ + /* Walk through the memory table */ for (i = 0; i < numblocks;) { uint8_t dat; dat = this->bbt[bbtoffs + (i >> 2)]; for (j = 0; j < 4; j++, i++) { int sftcnt = (i << (3 - sft)) & sftmsk; - /* Do not store the reserved bbt blocks ! */ + /* Do not store the reserved bbt blocks! */ buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); dat >>= 2; @@ -883,8 +839,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (res < 0) goto outerr; - printk(KERN_DEBUG "Bad block table written to 0x%012llx, version " - "0x%02X\n", (unsigned long long)to, td->version[chip]); + pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", + (unsigned long long)to, td->version[chip]); /* Mark it as used */ td->pages[chip] = page; @@ -892,19 +848,18 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, return 0; outerr: - printk(KERN_WARNING - "nand_bbt: Error while writing bad block table %d\n", res); + pr_warn("nand_bbt: error while writing bad block table %d\n", res); return res; } /** * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern * - * The function creates a memory based bbt by scanning the device - * for manufacturer / software marked good / bad blocks -*/ + * The function creates a memory based bbt by scanning the device for + * manufacturer / software marked good / bad blocks. + */ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; @@ -915,25 +870,24 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b /** * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern * - * The function checks the results of the previous call to read_bbt - * and creates / updates the bbt(s) if necessary - * Creation is necessary if no bbt was found for the chip/device - * Update is necessary if one of the tables is missing or the - * version nr. of one table is less than the other -*/ + * The function checks the results of the previous call to read_bbt and creates + * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found + * for the chip/device. Update is necessary if one of the tables is missing or + * the version nr. of one table is less than the other. + */ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) { - int i, chips, writeops, chipsel, res; + int i, chips, writeops, create, chipsel, res, res2; struct nand_chip *this = mtd->priv; struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; struct nand_bbt_descr *rd, *rd2; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) chips = this->numchips; else @@ -941,86 +895,98 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc for (i = 0; i < chips; i++) { writeops = 0; + create = 0; rd = NULL; rd2 = NULL; - /* Per chip or per device ? */ + res = res2 = 0; + /* Per chip or per device? */ chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; - /* Mirrored table available ? */ + /* Mirrored table available? */ if (md) { if (td->pages[i] == -1 && md->pages[i] == -1) { + create = 1; writeops = 0x03; - goto create; - } - - if (td->pages[i] == -1) { + } else if (td->pages[i] == -1) { rd = md; - td->version[i] = md->version[i]; - writeops = 1; - goto writecheck; - } - - if (md->pages[i] == -1) { + writeops = 0x01; + } else if (md->pages[i] == -1) { rd = td; - md->version[i] = td->version[i]; - writeops = 2; - goto writecheck; - } - - if (td->version[i] == md->version[i]) { + writeops = 0x02; + } else if (td->version[i] == md->version[i]) { rd = td; if (!(td->options & NAND_BBT_VERSION)) rd2 = md; - goto writecheck; - } - - if (((int8_t) (td->version[i] - md->version[i])) > 0) { + } else if (((int8_t)(td->version[i] - md->version[i])) > 0) { rd = td; - md->version[i] = td->version[i]; - writeops = 2; + writeops = 0x02; } else { rd = md; - td->version[i] = md->version[i]; - writeops = 1; + writeops = 0x01; } - - goto writecheck; - } else { if (td->pages[i] == -1) { + create = 1; writeops = 0x01; - goto create; + } else { + rd = td; } - rd = td; - goto writecheck; } - create: - /* Create the bad block table by scanning the device ? */ - if (!(td->options & NAND_BBT_CREATE)) - continue; - /* Create the table in memory by scanning the chip(s) */ - if (!(this->options & NAND_CREATE_EMPTY_BBT)) - create_bbt(mtd, buf, bd, chipsel); - - td->version[i] = 1; - if (md) - md->version[i] = 1; - writecheck: - /* read back first ? */ - if (rd) - read_abs_bbt(mtd, buf, rd, chipsel); - /* If they weren't versioned, read both. */ - if (rd2) - read_abs_bbt(mtd, buf, rd2, chipsel); - - /* Write the bad block table to the device ? */ + if (create) { + /* Create the bad block table by scanning the device? */ + if (!(td->options & NAND_BBT_CREATE)) + continue; + + /* Create the table in memory by scanning the chip(s) */ + if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) + create_bbt(mtd, buf, bd, chipsel); + + td->version[i] = 1; + if (md) + md->version[i] = 1; + } + + /* Read back first? */ + if (rd) { + res = read_abs_bbt(mtd, buf, rd, chipsel); + if (mtd_is_eccerr(res)) { + /* Mark table as invalid */ + rd->pages[i] = -1; + rd->version[i] = 0; + i--; + continue; + } + } + /* If they weren't versioned, read both */ + if (rd2) { + res2 = read_abs_bbt(mtd, buf, rd2, chipsel); + if (mtd_is_eccerr(res2)) { + /* Mark table as invalid */ + rd2->pages[i] = -1; + rd2->version[i] = 0; + i--; + continue; + } + } + + /* Scrub the flash table(s)? */ + if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) + writeops = 0x03; + + /* Update version numbers before writing */ + if (md) { + td->version[i] = max(td->version[i], md->version[i]); + md->version[i] = td->version[i]; + } + + /* Write the bad block table to the device? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) return res; } - /* Write the mirror bad block table to the device ? */ + /* Write the mirror bad block table to the device? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, md, td, chipsel); if (res < 0) @@ -1032,20 +998,19 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /** * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd: MTD device structure - * @td: bad block table descriptor + * @mtd: MTD device structure + * @td: bad block table descriptor * - * The bad block table regions are marked as "bad" to prevent - * accidental erasures / writes. The regions are identified by - * the mark 0x02. -*/ + * The bad block table regions are marked as "bad" to prevent accidental + * erasures / writes. The regions are identified by the mark 0x02. + */ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) { struct nand_chip *this = mtd->priv; int i, j, chips, block, nrblocks, update; uint8_t oldval, newval; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); @@ -1082,9 +1047,11 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) update = 1; block += 2; } - /* If we want reserved blocks to be recorded to flash, and some - new ones have been marked, then we need to update the stored - bbts. This should only happen once. */ + /* + * If we want reserved blocks to be recorded to flash, and some + * new ones have been marked, then we need to update the stored + * bbts. This should only happen once. + */ if (update && td->reserved_block_code) nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); } @@ -1092,8 +1059,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * verify_bbt_descr - verify the bad block description - * @mtd: MTD device structure - * @bd: the table to verify + * @mtd: MTD device structure + * @bd: the table to verify * * This functions performs a few sanity checks on the bad block description * table. @@ -1111,16 +1078,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) pattern_len = bd->len; bits = bd->options & NAND_BBT_NRBITS_MSK; - BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && - !(this->options & NAND_USE_FLASH_BBT)); + BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && + !(this->bbt_options & NAND_BBT_USE_FLASH)); BUG_ON(!bits); if (bd->options & NAND_BBT_VERSION) pattern_len++; if (bd->options & NAND_BBT_NO_OOB) { - BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); - BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); + BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); + BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); BUG_ON(bd->offs); if (bd->options & NAND_BBT_VERSION) BUG_ON(bd->veroffs != bd->len); @@ -1140,18 +1107,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) /** * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern - * - * The function checks, if a bad block table(s) is/are already - * available. If not it scans the device for manufacturer - * marked good / bad blocks and writes the bad block table(s) to - * the selected place. + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern * - * The bad block table memory is allocated here. It must be freed - * by calling the nand_free_bbt function. + * The function checks, if a bad block table(s) is/are already available. If + * not it scans the device for manufacturer marked good / bad blocks and writes + * the bad block table(s) to the selected place. * -*/ + * The bad block table memory is allocated here. It must be freed by calling + * the nand_free_bbt function. + */ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; @@ -1161,19 +1126,21 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) struct nand_bbt_descr *md = this->bbt_md; len = mtd->size >> (this->bbt_erase_shift + 2); - /* Allocate memory (2bit per block) and clear the memory bad block table */ + /* + * Allocate memory (2bit per block) and clear the memory bad block + * table. + */ this->bbt = kzalloc(len, GFP_KERNEL); - if (!this->bbt) { - printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); + if (!this->bbt) return -ENOMEM; - } - /* If no primary table decriptor is given, scan the device - * to build a memory based bad block table + /* + * If no primary table decriptor is given, scan the device to build a + * memory based bad block table. */ if (!td) { if ((res = nand_memory_bbt(mtd, bd))) { - printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); + pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); kfree(this->bbt); this->bbt = NULL; } @@ -1187,13 +1154,12 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) len += (len >> this->page_shift) * mtd->oobsize; buf = vmalloc(len); if (!buf) { - printk(KERN_ERR "nand_bbt: Out of memory\n"); kfree(this->bbt); this->bbt = NULL; return -ENOMEM; } - /* Is the bbt at a given page ? */ + /* Is the bbt at a given page? */ if (td->options & NAND_BBT_ABSPAGE) { res = read_abs_bbts(mtd, buf, td, md); } else { @@ -1215,15 +1181,15 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) /** * nand_update_bbt - [NAND Interface] update bad block table(s) - * @mtd: MTD device structure - * @offs: the offset of the newly marked block + * @mtd: MTD device structure + * @offs: the offset of the newly marked block * - * The function updates the bad block table(s) -*/ + * The function updates the bad block table(s). + */ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) { struct nand_chip *this = mtd->priv; - int len, res = 0, writeops = 0; + int len, res = 0; int chip, chipsel; uint8_t *buf; struct nand_bbt_descr *td = this->bbt_td; @@ -1236,14 +1202,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; buf = kmalloc(len, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "nand_update_bbt: Out of memory\n"); + if (!buf) return -ENOMEM; - } - - writeops = md != NULL ? 0x03 : 0x01; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chip = (int)(offs >> this->chip_shift); chipsel = chip; @@ -1256,14 +1218,14 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) if (md) md->version[chip]++; - /* Write the bad block table to the device ? */ - if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { + /* Write the bad block table to the device? */ + if (td->options & NAND_BBT_WRITE) { res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) goto out; } - /* Write the mirror bad block table to the device ? */ - if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { + /* Write the mirror bad block table to the device? */ + if (md && (md->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, md, td, chipsel); } @@ -1272,8 +1234,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) return res; } -/* Define some generic bad / good block scan pattern which are used - * while scanning a device for factory marked good / bad blocks. */ +/* + * Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. + */ static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 }; @@ -1285,8 +1249,7 @@ static struct nand_bbt_descr agand_flashbased = { .pattern = scan_agand_pattern }; -/* Generic flash bbt decriptors -*/ +/* Generic flash bbt descriptors */ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; @@ -1330,31 +1293,27 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { .pattern = mirror_pattern }; -#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ - NAND_BBT_SCANBYTE1AND6) +#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB) /** - * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure - * @this: NAND chip to create descriptor for + * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure + * @this: NAND chip to create descriptor for * * This function allocates and initializes a nand_bbt_descr for BBM detection - * based on the properties of "this". The new descriptor is stored in + * based on the properties of @this. The new descriptor is stored in * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when * passed to this function. - * */ -static int nand_create_default_bbt_descr(struct nand_chip *this) +static int nand_create_badblock_pattern(struct nand_chip *this) { struct nand_bbt_descr *bd; if (this->badblock_pattern) { - printk(KERN_WARNING "BBT descr already allocated; not replacing.\n"); + pr_warn("Bad block pattern already allocated; not replacing\n"); return -EINVAL; } bd = kzalloc(sizeof(*bd), GFP_KERNEL); - if (!bd) { - printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); + if (!bd) return -ENOMEM; - } - bd->options = this->options & BBT_SCAN_OPTIONS; + bd->options = this->bbt_options & BADBLOCK_SCAN_MASK; bd->offs = this->badblockpos; bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; bd->pattern = scan_ff_pattern; @@ -1365,22 +1324,20 @@ static int nand_create_default_bbt_descr(struct nand_chip *this) /** * nand_default_bbt - [NAND Interface] Select a default bad block table for the device - * @mtd: MTD device structure - * - * This function selects the default bad block table - * support for the device and calls the nand_scan_bbt function + * @mtd: MTD device structure * -*/ + * This function selects the default bad block table support for the device and + * calls the nand_scan_bbt function. + */ int nand_default_bbt(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - /* Default for AG-AND. We must use a flash based - * bad block table as the devices have factory marked - * _good_ blocks. Erasing those blocks leads to loss - * of the good / bad information, so we _must_ store - * this information in a good / bad table during - * startup + /* + * Default for AG-AND. We must use a flash based bad block table as the + * devices have factory marked _good_ blocks. Erasing those blocks + * leads to loss of the good / bad information, so we _must_ store this + * information in a good / bad table during startup. */ if (this->options & NAND_IS_AND) { /* Use the default pattern descriptors */ @@ -1388,15 +1345,15 @@ int nand_default_bbt(struct mtd_info *mtd) this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; } - this->options |= NAND_USE_FLASH_BBT; + this->bbt_options |= NAND_BBT_USE_FLASH; return nand_scan_bbt(mtd, &agand_flashbased); } - /* Is a flash based bad block table requested ? */ - if (this->options & NAND_USE_FLASH_BBT) { + /* Is a flash based bad block table requested? */ + if (this->bbt_options & NAND_BBT_USE_FLASH) { /* Use the default pattern descriptors */ if (!this->bbt_td) { - if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { + if (this->bbt_options & NAND_BBT_NO_OOB) { this->bbt_td = &bbt_main_no_bbt_descr; this->bbt_md = &bbt_mirror_no_bbt_descr; } else { @@ -1410,18 +1367,17 @@ int nand_default_bbt(struct mtd_info *mtd) } if (!this->badblock_pattern) - nand_create_default_bbt_descr(this); + nand_create_badblock_pattern(this); return nand_scan_bbt(mtd, this->badblock_pattern); } /** * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd: MTD device structure - * @offs: offset in the device - * @allowbbt: allow access to bad block table region - * -*/ + * @mtd: MTD device structure + * @offs: offset in the device + * @allowbbt: allow access to bad block table region + */ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) { struct nand_chip *this = mtd->priv; @@ -1432,8 +1388,9 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) block = (int)(offs >> (this->bbt_erase_shift - 1)); res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, block >> 1, res); + pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: " + "(block %d) 0x%02x\n", + (unsigned int)offs, block >> 1, res); switch ((int)res) { case 0x00: diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c index 0f931e757116..3803e0bba23b 100644 --- a/drivers/mtd/nand/nand_bch.c +++ b/drivers/mtd/nand/nand_bch.c @@ -93,8 +93,8 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); /* else error in ecc, no action needed */ - DEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n", - __func__, errloc[i]); + pr_debug("%s: corrected bitflip %u\n", __func__, + errloc[i]); } } else if (count < 0) { printk(KERN_ERR "ecc unrecoverable error\n"); diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 271b8e735e8f..b7cfe0d37121 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -110,7 +110,7 @@ static const char bitsperbyte[256] = { /* * addressbits is a lookup table to filter out the bits from the xor-ed - * ecc data that identify the faulty location. + * ECC data that identify the faulty location. * this is only used for repairing parity * see the comments in nand_correct_data for more details */ @@ -153,7 +153,7 @@ static const char addressbits[256] = { * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte * block * @buf: input buffer with raw data - * @eccsize: data bytes per ecc step (256 or 512) + * @eccsize: data bytes per ECC step (256 or 512) * @code: output buffer with ECC */ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, @@ -348,7 +348,7 @@ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, rp17 = (par ^ rp16) & 0xff; /* - * Finally calculate the ecc bits. + * Finally calculate the ECC bits. * Again here it might seem that there are performance optimisations * possible, but benchmarks showed that on the system this is developed * the code below is the fastest @@ -436,7 +436,7 @@ EXPORT_SYMBOL(nand_calculate_ecc); * @buf: raw data read from the chip * @read_ecc: ECC from the chip * @calc_ecc: the ECC calculated from raw data - * @eccsize: data bytes per ecc step (256 or 512) + * @eccsize: data bytes per ECC step (256 or 512) * * Detect and correct a 1 bit error for eccsize byte block */ @@ -505,7 +505,7 @@ int __nand_correct_data(unsigned char *buf, } /* count nr of bits; use table lookup, faster than calculating it */ if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) - return 1; /* error in ecc data; no action needed */ + return 1; /* error in ECC data; no action needed */ printk(KERN_ERR "uncorrectable error : "); return -1; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 357e8c5252a8..34c03be77301 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -2273,9 +2273,9 @@ static int __init ns_init_module(void) switch (bbt) { case 2: - chip->options |= NAND_USE_FLASH_BBT_NO_OOB; + chip->bbt_options |= NAND_BBT_NO_OOB; case 1: - chip->options |= NAND_USE_FLASH_BBT; + chip->bbt_options |= NAND_BBT_USE_FLASH; case 0: break; default: diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index ea2dea8a9c88..ee1713907b92 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -42,7 +42,6 @@ struct ndfc_controller { struct nand_chip chip; int chip_select; struct nand_hw_control ndfc_control; - struct mtd_partition *parts; }; static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS]; @@ -159,13 +158,9 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) static int ndfc_chip_init(struct ndfc_controller *ndfc, struct device_node *node) { -#ifdef CONFIG_MTD_CMDLINE_PARTS - static const char *part_types[] = { "cmdlinepart", NULL }; -#else - static const char *part_types[] = { NULL }; -#endif struct device_node *flash_np; struct nand_chip *chip = &ndfc->chip; + struct mtd_part_parser_data ppdata; int ret; chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; @@ -193,6 +188,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, if (!flash_np) return -ENODEV; + ppdata->of_node = flash_np; ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev), flash_np->name); if (!ndfc->mtd.name) { @@ -204,18 +200,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, if (ret) goto err; - ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0); - if (ret < 0) - goto err; - - if (ret == 0) { - ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np, - &ndfc->parts); - if (ret < 0) - goto err; - } - - ret = mtd_device_register(&ndfc->mtd, ndfc->parts, ret); + ret = mtd_device_parse_register(&ndfc->mtd, NULL, &ppdata, NULL, 0); err: of_node_put(flash_np); @@ -288,6 +273,7 @@ static int __devexit ndfc_remove(struct platform_device *ofdev) struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); nand_release(&ndfc->mtd); + kfree(ndfc->mtd.name); return 0; } diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c index b6a5c86ab31e..b463ecfb4c1a 100644 --- a/drivers/mtd/nand/nomadik_nand.c +++ b/drivers/mtd/nand/nomadik_nand.c @@ -187,6 +187,7 @@ static int nomadik_nand_remove(struct platform_device *pdev) pdata->exit(); if (host) { + nand_release(&host->mtd); iounmap(host->cmd_va); iounmap(host->data_va); iounmap(host->addr_va); diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 9c30a0b03171..fa8faedfad6e 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -339,6 +339,7 @@ static int __devexit nuc900_nand_remove(struct platform_device *pdev) struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); struct resource *res; + nand_release(&nuc900_nand->mtd); iounmap(nuc900_nand->reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 0db2c0e7656a..f745f00f3167 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -11,6 +11,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/sched.h> @@ -94,8 +95,6 @@ #define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) #define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) -static const char *part_probes[] = { "cmdlinepart", NULL }; - /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; /* Define some generic bad / good block scan pattern which are used @@ -114,7 +113,6 @@ struct omap_nand_info { struct nand_hw_control controller; struct omap_nand_platform_data *pdata; struct mtd_info mtd; - struct mtd_partition *parts; struct nand_chip nand; struct platform_device *pdev; @@ -744,12 +742,12 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ case 1: /* Uncorrectable error */ - DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n"); + pr_debug("ECC UNCORRECTED_ERROR 1\n"); return -1; case 11: /* UN-Correctable error */ - DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR B\n"); + pr_debug("ECC UNCORRECTED_ERROR B\n"); return -1; case 12: @@ -766,8 +764,8 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1]; - DEBUG(MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at " - "offset: %d, bit: %d\n", find_byte, find_bit); + pr_debug("Correcting single bit ECC error at offset: " + "%d, bit: %d\n", find_byte, find_bit); page_data[find_byte] ^= (1 << find_bit); @@ -779,7 +777,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ ecc_data2[2] == 0) return 0; } - DEBUG(MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n"); + pr_debug("UNCORRECTED_ERROR default\n"); return -1; } } @@ -1103,13 +1101,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) goto out_release_mem_region; } - err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); - if (err > 0) - mtd_device_register(&info->mtd, info->parts, err); - else if (pdata->parts) - mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts); - else - mtd_device_register(&info->mtd, NULL, 0); + mtd_device_parse_register(&info->mtd, NULL, 0, + pdata->parts, pdata->nr_parts); platform_set_drvdata(pdev, &info->mtd); diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 7794d0680f91..29f505adaf84 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -21,8 +21,6 @@ #include <mach/hardware.h> #include <plat/orion_nand.h> -static const char *part_probes[] = { "cmdlinepart", NULL }; - static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *nc = mtd->priv; @@ -81,8 +79,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) struct resource *res; void __iomem *io_base; int ret = 0; - struct mtd_partition *partitions = NULL; - int num_part = 0; nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL); if (!nc) { @@ -132,17 +128,9 @@ static int __init orion_nand_probe(struct platform_device *pdev) goto no_dev; } -#ifdef CONFIG_MTD_CMDLINE_PARTS mtd->name = "orion_nand"; - num_part = parse_mtd_partitions(mtd, part_probes, &partitions, 0); -#endif - /* If cmdline partitions have been passed, let them be used */ - if (num_part <= 0) { - num_part = board->nr_parts; - partitions = board->parts; - } - - ret = mtd_device_register(mtd, partitions, num_part); + ret = mtd_device_parse_register(mtd, NULL, 0, + board->parts, board->nr_parts); if (ret) { nand_release(mtd); goto no_dev; diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index b1aa41b8a4eb..a97264ececdb 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -155,7 +155,8 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev) chip->ecc.mode = NAND_ECC_SOFT; /* Enable the following for a flash based bad block table */ - chip->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; + chip->options = NAND_NO_AUTOINCR; + chip->bbt_options = NAND_BBT_USE_FLASH; /* Scan to find existence of the device */ if (nand_scan(pasemi_nand_mtd, 1)) { diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 633c04bf76f6..ea8e1234e0e2 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -21,8 +21,6 @@ struct plat_nand_data { struct nand_chip chip; struct mtd_info mtd; void __iomem *io_base; - int nr_parts; - struct mtd_partition *parts; }; /* @@ -79,6 +77,7 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) data->chip.read_buf = pdata->ctrl.read_buf; data->chip.chip_delay = pdata->chip.chip_delay; data->chip.options |= pdata->chip.options; + data->chip.bbt_options |= pdata->chip.bbt_options; data->chip.ecc.hwctl = pdata->ctrl.hwcontrol; data->chip.ecc.layout = pdata->chip.ecclayout; @@ -99,23 +98,9 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) goto out; } - if (pdata->chip.part_probe_types) { - err = parse_mtd_partitions(&data->mtd, - pdata->chip.part_probe_types, - &data->parts, 0); - if (err > 0) { - mtd_device_register(&data->mtd, data->parts, err); - return 0; - } - } - if (pdata->chip.set_parts) - pdata->chip.set_parts(data->mtd.size, &pdata->chip); - if (pdata->chip.partitions) { - data->parts = pdata->chip.partitions; - err = mtd_device_register(&data->mtd, data->parts, - pdata->chip.nr_partitions); - } else - err = mtd_device_register(&data->mtd, NULL, 0); + err = mtd_device_parse_register(&data->mtd, + pdata->chip.part_probe_types, 0, + pdata->chip.partitions, pdata->chip.nr_partitions); if (!err) return err; @@ -145,8 +130,6 @@ static int __devexit plat_nand_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nand_release(&data->mtd); - if (data->parts && data->parts != pdata->chip.partitions) - kfree(data->parts); if (pdata->ctrl.remove) pdata->ctrl.remove(pdev); iounmap(data->io_base); diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 3bbb796b451c..7e52af51a198 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -99,8 +99,6 @@ static struct mtd_partition partition_info_evb[] = { #define NUM_PARTITIONS 1 -extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, const char *mtd_id); - /* * hardware specific access to control-lines */ @@ -187,18 +185,12 @@ static int ppchameleonevb_device_ready(struct mtd_info *minfo) } #endif -const char *part_probes[] = { "cmdlinepart", NULL }; -const char *part_probes_evb[] = { "cmdlinepart", NULL }; - /* * Main initialization routine */ static int __init ppchameleonevb_init(void) { struct nand_chip *this; - const char *part_type = 0; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; void __iomem *ppchameleon_fio_base; void __iomem *ppchameleonevb_fio_base; @@ -281,24 +273,13 @@ static int __init ppchameleonevb_init(void) #endif ppchameleon_mtd->name = "ppchameleon-nand"; - mtd_parts_nb = parse_mtd_partitions(ppchameleon_mtd, part_probes, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - - if (mtd_parts_nb == 0) { - if (ppchameleon_mtd->size == NAND_SMALL_SIZE) - mtd_parts = partition_info_me; - else - mtd_parts = partition_info_hi; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(ppchameleon_mtd, mtd_parts, mtd_parts_nb); + mtd_device_parse_register(ppchameleon_mtd, NULL, 0, + ppchameleon_mtd->size == NAND_SMALL_SIZE ? + partition_info_me : + partition_info_hi, + NUM_PARTITIONS); nand_evb_init: /**************************** @@ -382,21 +363,13 @@ static int __init ppchameleonevb_init(void) } ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME; - mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, part_probes_evb, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - - if (mtd_parts_nb == 0) { - mtd_parts = partition_info_evb; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(ppchameleonevb_mtd, mtd_parts, mtd_parts_nb); + mtd_device_parse_register(ppchameleonevb_mtd, NULL, 0, + ppchameleon_mtd->size == NAND_SMALL_SIZE ? + partition_info_me : + partition_info_hi, + NUM_PARTITIONS); /* Return happy */ return 0; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 1fb3b3a80581..9eb7f879969e 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -110,6 +110,7 @@ enum { enum { STATE_IDLE = 0, + STATE_PREPARED, STATE_CMD_HANDLE, STATE_DMA_READING, STATE_DMA_WRITING, @@ -120,21 +121,40 @@ enum { STATE_READY, }; -struct pxa3xx_nand_info { - struct nand_chip nand_chip; +struct pxa3xx_nand_host { + struct nand_chip chip; + struct pxa3xx_nand_cmdset *cmdset; + struct mtd_info *mtd; + void *info_data; + + /* page size of attached chip */ + unsigned int page_size; + int use_ecc; + int cs; + /* calculated from pxa3xx_nand_flash data */ + unsigned int col_addr_cycles; + unsigned int row_addr_cycles; + size_t read_id_bytes; + + /* cached register value */ + uint32_t reg_ndcr; + uint32_t ndtr0cs0; + uint32_t ndtr1cs0; +}; + +struct pxa3xx_nand_info { struct nand_hw_control controller; struct platform_device *pdev; - struct pxa3xx_nand_cmdset *cmdset; struct clk *clk; void __iomem *mmio_base; unsigned long mmio_phys; + struct completion cmd_complete; unsigned int buf_start; unsigned int buf_count; - struct mtd_info *mtd; /* DMA information */ int drcmr_dat; int drcmr_cmd; @@ -142,44 +162,27 @@ struct pxa3xx_nand_info { unsigned char *data_buff; unsigned char *oob_buff; dma_addr_t data_buff_phys; - size_t data_buff_size; int data_dma_ch; struct pxa_dma_desc *data_desc; dma_addr_t data_desc_addr; - uint32_t reg_ndcr; - - /* saved column/page_addr during CMD_SEQIN */ - int seqin_column; - int seqin_page_addr; - - /* relate to the command */ + struct pxa3xx_nand_host *host[NUM_CHIP_SELECT]; unsigned int state; + int cs; int use_ecc; /* use HW ECC ? */ int use_dma; /* use DMA ? */ int is_ready; unsigned int page_size; /* page size of attached chip */ unsigned int data_size; /* data size in FIFO */ + unsigned int oob_size; int retcode; - struct completion cmd_complete; /* generated NDCBx register values */ uint32_t ndcb0; uint32_t ndcb1; uint32_t ndcb2; - - /* timing calcuted from setting */ - uint32_t ndtr0cs0; - uint32_t ndtr1cs0; - - /* calculated from pxa3xx_nand_flash data */ - size_t oob_size; - size_t read_id_bytes; - - unsigned int col_addr_cycles; - unsigned int row_addr_cycles; }; static int use_dma = 1; @@ -225,7 +228,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { /* Define a default flash type setting serve as flash detecting only */ #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) -const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; +const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL}; #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) @@ -241,9 +244,10 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; /* convert nano-seconds to nand flash controller clock cycles */ #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) -static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, +static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, const struct pxa3xx_nand_timing *t) { + struct pxa3xx_nand_info *info = host->info_data; unsigned long nand_clk = clk_get_rate(info->clk); uint32_t ndtr0, ndtr1; @@ -258,23 +262,24 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); - info->ndtr0cs0 = ndtr0; - info->ndtr1cs0 = ndtr1; + host->ndtr0cs0 = ndtr0; + host->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1); } static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) { - int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; + struct pxa3xx_nand_host *host = info->host[info->cs]; + int oob_enable = host->reg_ndcr & NDCR_SPARE_EN; - info->data_size = info->page_size; + info->data_size = host->page_size; if (!oob_enable) { info->oob_size = 0; return; } - switch (info->page_size) { + switch (host->page_size) { case 2048: info->oob_size = (info->use_ecc) ? 40 : 64; break; @@ -292,9 +297,10 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) */ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) { + struct pxa3xx_nand_host *host = info->host[info->cs]; uint32_t ndcr; - ndcr = info->reg_ndcr; + ndcr = host->reg_ndcr; ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; ndcr |= info->use_dma ? NDCR_DMA_EN : 0; ndcr |= NDCR_ND_RUN; @@ -359,7 +365,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) DIV_ROUND_UP(info->oob_size, 4)); break; default: - printk(KERN_ERR "%s: invalid state %d\n", __func__, + dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } @@ -385,7 +391,7 @@ static void start_data_dma(struct pxa3xx_nand_info *info) desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC; break; default: - printk(KERN_ERR "%s: invalid state %d\n", __func__, + dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } @@ -416,6 +422,15 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) { struct pxa3xx_nand_info *info = devid; unsigned int status, is_completed = 0; + unsigned int ready, cmd_done; + + if (info->cs == 0) { + ready = NDSR_FLASH_RDY; + cmd_done = NDSR_CS0_CMDD; + } else { + ready = NDSR_RDY; + cmd_done = NDSR_CS1_CMDD; + } status = nand_readl(info, NDSR); @@ -437,11 +452,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) handle_data_pio(info); } } - if (status & NDSR_CS0_CMDD) { + if (status & cmd_done) { info->state = STATE_CMD_DONE; is_completed = 1; } - if (status & NDSR_FLASH_RDY) { + if (status & ready) { info->is_ready = 1; info->state = STATE_READY; } @@ -463,12 +478,6 @@ NORMAL_IRQ_EXIT: return IRQ_HANDLED; } -static int pxa3xx_nand_dev_ready(struct mtd_info *mtd) -{ - struct pxa3xx_nand_info *info = mtd->priv; - return (nand_readl(info, NDSR) & NDSR_RDY) ? 1 : 0; -} - static inline int is_buf_blank(uint8_t *buf, size_t len) { for (; len > 0; len--) @@ -481,10 +490,12 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, uint16_t column, int page_addr) { uint16_t cmd; - int addr_cycle, exec_cmd, ndcb0; - struct mtd_info *mtd = info->mtd; + int addr_cycle, exec_cmd; + struct pxa3xx_nand_host *host; + struct mtd_info *mtd; - ndcb0 = 0; + host = info->host[info->cs]; + mtd = host->mtd; addr_cycle = 0; exec_cmd = 1; @@ -495,6 +506,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->use_ecc = 0; info->is_ready = 0; info->retcode = ERR_NONE; + if (info->cs != 0) + info->ndcb0 = NDCB0_CSEL; + else + info->ndcb0 = 0; switch (command) { case NAND_CMD_READ0: @@ -512,20 +527,19 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; } - info->ndcb0 = ndcb0; - addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles - + info->col_addr_cycles); + addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles + + host->col_addr_cycles); switch (command) { case NAND_CMD_READOOB: case NAND_CMD_READ0: - cmd = info->cmdset->read1; + cmd = host->cmdset->read1; if (command == NAND_CMD_READOOB) info->buf_start = mtd->writesize + column; else info->buf_start = column; - if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) + if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) info->ndcb0 |= NDCB0_CMD_TYPE(0) | addr_cycle | (cmd & NDCB0_CMD1_MASK); @@ -537,7 +551,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, case NAND_CMD_SEQIN: /* small page addr setting */ - if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) { + if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) { info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) | (column & 0xFF); @@ -564,7 +578,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; } - cmd = info->cmdset->program; + cmd = host->cmdset->program; info->ndcb0 |= NDCB0_CMD_TYPE(0x1) | NDCB0_AUTO_RS | NDCB0_ST_ROW_EN @@ -574,8 +588,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; case NAND_CMD_READID: - cmd = info->cmdset->read_id; - info->buf_count = info->read_id_bytes; + cmd = host->cmdset->read_id; + info->buf_count = host->read_id_bytes; info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1) | cmd; @@ -583,7 +597,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->data_size = 8; break; case NAND_CMD_STATUS: - cmd = info->cmdset->read_status; + cmd = host->cmdset->read_status; info->buf_count = 1; info->ndcb0 |= NDCB0_CMD_TYPE(4) | NDCB0_ADDR_CYC(1) @@ -593,7 +607,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; case NAND_CMD_ERASE1: - cmd = info->cmdset->erase; + cmd = host->cmdset->erase; info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3) @@ -604,7 +618,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; case NAND_CMD_RESET: - cmd = info->cmdset->reset; + cmd = host->cmdset->reset; info->ndcb0 |= NDCB0_CMD_TYPE(5) | cmd; @@ -616,8 +630,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, default: exec_cmd = 0; - printk(KERN_ERR "pxa3xx-nand: non-supported" - " command %x\n", command); + dev_err(&info->pdev->dev, "non-supported command %x\n", + command); break; } @@ -627,7 +641,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; int ret, exec_cmd; /* @@ -635,9 +650,21 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, * "byte" address into a "word" address appropriate * for indexing a word-oriented device */ - if (info->reg_ndcr & NDCR_DWIDTH_M) + if (host->reg_ndcr & NDCR_DWIDTH_M) column /= 2; + /* + * There may be different NAND chip hooked to + * different chip select, so check whether + * chip select has been changed, if yes, reset the timing + */ + if (info->cs != host->cs) { + info->cs = host->cs; + nand_writel(info, NDTR0CS0, host->ndtr0cs0); + nand_writel(info, NDTR1CS0, host->ndtr1cs0); + } + + info->state = STATE_PREPARED; exec_cmd = prepare_command_pool(info, command, column, page_addr); if (exec_cmd) { init_completion(&info->cmd_complete); @@ -646,12 +673,12 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, ret = wait_for_completion_timeout(&info->cmd_complete, CHIP_DELAY_TIMEOUT); if (!ret) { - printk(KERN_ERR "Wait time out!!!\n"); + dev_err(&info->pdev->dev, "Wait time out!!!\n"); /* Stop State Machine for next command cycle */ pxa3xx_nand_stop(info); } - info->state = STATE_IDLE; } + info->state = STATE_IDLE; } static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, @@ -664,7 +691,8 @@ static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -685,6 +713,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, * OOB, ignore such double bit errors */ if (is_buf_blank(buf, mtd->writesize)) + info->retcode = ERR_NONE; + else mtd->ecc_stats.failed++; } @@ -693,7 +723,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; char retval = 0xFF; if (info->buf_start < info->buf_count) @@ -705,7 +736,8 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; u16 retval = 0xFFFF; if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) { @@ -717,7 +749,8 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; int real_len = min_t(size_t, len, info->buf_count - info->buf_start); memcpy(buf, info->data_buff + info->buf_start, real_len); @@ -727,7 +760,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) static void pxa3xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; int real_len = min_t(size_t, len, info->buf_count - info->buf_start); memcpy(info->data_buff + info->buf_start, buf, real_len); @@ -747,7 +781,8 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip) static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; /* pxa3xx_nand_send_command has waited for command complete */ if (this->state == FL_WRITING || this->state == FL_ERASING) { @@ -770,54 +805,70 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, { struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; + struct pxa3xx_nand_host *host = info->host[info->cs]; uint32_t ndcr = 0x0; /* enable all interrupts */ - if (f->page_size != 2048 && f->page_size != 512) + if (f->page_size != 2048 && f->page_size != 512) { + dev_err(&pdev->dev, "Current only support 2048 and 512 size\n"); return -EINVAL; + } - if (f->flash_width != 16 && f->flash_width != 8) + if (f->flash_width != 16 && f->flash_width != 8) { + dev_err(&pdev->dev, "Only support 8bit and 16 bit!\n"); return -EINVAL; + } /* calculate flash information */ - info->cmdset = &default_cmdset; - info->page_size = f->page_size; - info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; + host->cmdset = &default_cmdset; + host->page_size = f->page_size; + host->read_id_bytes = (f->page_size == 2048) ? 4 : 2; /* calculate addressing information */ - info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; + host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; if (f->num_blocks * f->page_per_block > 65536) - info->row_addr_cycles = 3; + host->row_addr_cycles = 3; else - info->row_addr_cycles = 2; + host->row_addr_cycles = 2; ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; - ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0; + ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0; ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0; ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; - ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes); + ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes); ndcr |= NDCR_SPARE_EN; /* enable spare by default */ - info->reg_ndcr = ndcr; + host->reg_ndcr = ndcr; - pxa3xx_nand_set_timing(info, f->timing); + pxa3xx_nand_set_timing(host, f->timing); return 0; } static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { + /* + * We set 0 by hard coding here, for we don't support keep_config + * when there is more than one chip attached to the controller + */ + struct pxa3xx_nand_host *host = info->host[0]; uint32_t ndcr = nand_readl(info, NDCR); - info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; - /* set info fields needed to read id */ - info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; - info->reg_ndcr = ndcr; - info->cmdset = &default_cmdset; - info->ndtr0cs0 = nand_readl(info, NDTR0CS0); - info->ndtr1cs0 = nand_readl(info, NDTR1CS0); + if (ndcr & NDCR_PAGE_SZ) { + host->page_size = 2048; + host->read_id_bytes = 4; + } else { + host->page_size = 512; + host->read_id_bytes = 2; + } + + host->reg_ndcr = ndcr & ~NDCR_INT_MASK; + host->cmdset = &default_cmdset; + + host->ndtr0cs0 = nand_readl(info, NDTR0CS0); + host->ndtr1cs0 = nand_readl(info, NDTR1CS0); return 0; } @@ -847,7 +898,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) return -ENOMEM; } - info->data_buff_size = MAX_BUFF_SIZE; info->data_desc = (void *)info->data_buff + data_desc_offset; info->data_desc_addr = info->data_buff_phys + data_desc_offset; @@ -855,7 +905,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) pxa3xx_nand_data_dma_irq, info); if (info->data_dma_ch < 0) { dev_err(&pdev->dev, "failed to request data dma\n"); - dma_free_coherent(&pdev->dev, info->data_buff_size, + dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); return info->data_dma_ch; } @@ -865,24 +915,28 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) { - struct mtd_info *mtd = info->mtd; - struct nand_chip *chip = mtd->priv; - + struct mtd_info *mtd; + int ret; + mtd = info->host[info->cs]->mtd; /* use the common timing to make a try */ - pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); - chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); + ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); + if (ret) + return ret; + + pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0); if (info->is_ready) - return 1; - else return 0; + + return -ENODEV; } static int pxa3xx_nand_scan(struct mtd_info *mtd) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; - struct nand_flash_dev pxa3xx_flash_ids[2] = { {NULL,}, {NULL,} }; + struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL; const struct pxa3xx_nand_flash *f = NULL; struct nand_chip *chip = mtd->priv; uint32_t id = -1; @@ -893,22 +947,20 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) goto KEEP_CONFIG; ret = pxa3xx_nand_sensing(info); - if (!ret) { - kfree(mtd); - info->mtd = NULL; - printk(KERN_INFO "There is no nand chip on cs 0!\n"); + if (ret) { + dev_info(&info->pdev->dev, "There is no chip on cs %d!\n", + info->cs); - return -EINVAL; + return ret; } chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0); id = *((uint16_t *)(info->data_buff)); if (id != 0) - printk(KERN_INFO "Detect a flash id %x\n", id); + dev_info(&info->pdev->dev, "Detect a flash id %x\n", id); else { - kfree(mtd); - info->mtd = NULL; - printk(KERN_WARNING "Read out ID 0, potential timing set wrong!!\n"); + dev_warn(&info->pdev->dev, + "Read out ID 0, potential timing set wrong!!\n"); return -EINVAL; } @@ -926,14 +978,17 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) } if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) { - kfree(mtd); - info->mtd = NULL; - printk(KERN_ERR "ERROR!! flash not defined!!!\n"); + dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n"); return -EINVAL; } - pxa3xx_nand_config_flash(info, f); + ret = pxa3xx_nand_config_flash(info, f); + if (ret) { + dev_err(&info->pdev->dev, "ERROR! Configure failed\n"); + return ret; + } + pxa3xx_flash_ids[0].name = f->name; pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff; pxa3xx_flash_ids[0].pagesize = f->page_size; @@ -942,62 +997,78 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) pxa3xx_flash_ids[0].erasesize = f->page_size * f->page_per_block; if (f->flash_width == 16) pxa3xx_flash_ids[0].options = NAND_BUSWIDTH_16; + pxa3xx_flash_ids[1].name = NULL; + def = pxa3xx_flash_ids; KEEP_CONFIG: - if (nand_scan_ident(mtd, 1, pxa3xx_flash_ids)) + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = host->page_size; + + chip->options = NAND_NO_AUTOINCR; + chip->options |= NAND_NO_READRDY; + if (host->reg_ndcr & NDCR_DWIDTH_M) + chip->options |= NAND_BUSWIDTH_16; + + if (nand_scan_ident(mtd, 1, def)) return -ENODEV; /* calculate addressing information */ - info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; + if (mtd->writesize >= 2048) + host->col_addr_cycles = 2; + else + host->col_addr_cycles = 1; + info->oob_buff = info->data_buff + mtd->writesize; if ((mtd->size >> chip->page_shift) > 65536) - info->row_addr_cycles = 3; + host->row_addr_cycles = 3; else - info->row_addr_cycles = 2; - mtd->name = mtd_names[0]; - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = f->page_size; - - chip->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16 : 0; - chip->options |= NAND_NO_AUTOINCR; - chip->options |= NAND_NO_READRDY; + host->row_addr_cycles = 2; + mtd->name = mtd_names[0]; return nand_scan_tail(mtd); } -static -struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) +static int alloc_nand_resource(struct platform_device *pdev) { + struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info; + struct pxa3xx_nand_host *host; struct nand_chip *chip; struct mtd_info *mtd; struct resource *r; - int ret, irq; + int ret, irq, cs; - mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info), - GFP_KERNEL); - if (!mtd) { + pdata = pdev->dev.platform_data; + info = kzalloc(sizeof(*info) + (sizeof(*mtd) + + sizeof(*host)) * pdata->num_cs, GFP_KERNEL); + if (!info) { dev_err(&pdev->dev, "failed to allocate memory\n"); - return NULL; + return -ENOMEM; } - info = (struct pxa3xx_nand_info *)(&mtd[1]); - chip = (struct nand_chip *)(&mtd[1]); info->pdev = pdev; - info->mtd = mtd; - mtd->priv = info; - mtd->owner = THIS_MODULE; - - chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; - chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; - chip->controller = &info->controller; - chip->waitfunc = pxa3xx_nand_waitfunc; - chip->select_chip = pxa3xx_nand_select_chip; - chip->dev_ready = pxa3xx_nand_dev_ready; - chip->cmdfunc = pxa3xx_nand_cmdfunc; - chip->read_word = pxa3xx_nand_read_word; - chip->read_byte = pxa3xx_nand_read_byte; - chip->read_buf = pxa3xx_nand_read_buf; - chip->write_buf = pxa3xx_nand_write_buf; - chip->verify_buf = pxa3xx_nand_verify_buf; + for (cs = 0; cs < pdata->num_cs; cs++) { + mtd = (struct mtd_info *)((unsigned int)&info[1] + + (sizeof(*mtd) + sizeof(*host)) * cs); + chip = (struct nand_chip *)(&mtd[1]); + host = (struct pxa3xx_nand_host *)chip; + info->host[cs] = host; + host->mtd = mtd; + host->cs = cs; + host->info_data = info; + mtd->priv = host; + mtd->owner = THIS_MODULE; + + chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; + chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; + chip->controller = &info->controller; + chip->waitfunc = pxa3xx_nand_waitfunc; + chip->select_chip = pxa3xx_nand_select_chip; + chip->cmdfunc = pxa3xx_nand_cmdfunc; + chip->read_word = pxa3xx_nand_read_word; + chip->read_byte = pxa3xx_nand_read_byte; + chip->read_buf = pxa3xx_nand_read_buf; + chip->write_buf = pxa3xx_nand_write_buf; + chip->verify_buf = pxa3xx_nand_verify_buf; + } spin_lock_init(&chip->controller->lock); init_waitqueue_head(&chip->controller->wq); @@ -1070,13 +1141,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) platform_set_drvdata(pdev, info); - return info; + return 0; fail_free_buf: free_irq(irq, info); if (use_dma) { pxa_free_dma(info->data_dma_ch); - dma_free_coherent(&pdev->dev, info->data_buff_size, + dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); } else kfree(info->data_buff); @@ -1088,17 +1159,21 @@ fail_put_clk: clk_disable(info->clk); clk_put(info->clk); fail_free_mtd: - kfree(mtd); - return NULL; + kfree(info); + return ret; } static int pxa3xx_nand_remove(struct platform_device *pdev) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; + struct pxa3xx_nand_platform_data *pdata; struct resource *r; - int irq; + int irq, cs; + if (!info) + return 0; + + pdata = pdev->dev.platform_data; platform_set_drvdata(pdev, NULL); irq = platform_get_irq(pdev, 0); @@ -1106,7 +1181,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) free_irq(irq, info); if (use_dma) { pxa_free_dma(info->data_dma_ch); - dma_free_writecombine(&pdev->dev, info->data_buff_size, + dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); } else kfree(info->data_buff); @@ -1118,10 +1193,9 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) clk_disable(info->clk); clk_put(info->clk); - if (mtd) { - mtd_device_unregister(mtd); - kfree(mtd); - } + for (cs = 0; cs < pdata->num_cs; cs++) + nand_release(info->host[cs]->mtd); + kfree(info); return 0; } @@ -1129,6 +1203,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) { struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info; + int ret, cs, probe_success; pdata = pdev->dev.platform_data; if (!pdata) { @@ -1136,52 +1211,88 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) return -ENODEV; } - info = alloc_nand_resource(pdev); - if (info == NULL) - return -ENOMEM; - - if (pxa3xx_nand_scan(info->mtd)) { - dev_err(&pdev->dev, "failed to scan nand\n"); - pxa3xx_nand_remove(pdev); - return -ENODEV; + ret = alloc_nand_resource(pdev); + if (ret) { + dev_err(&pdev->dev, "alloc nand resource failed\n"); + return ret; } - if (mtd_has_cmdlinepart()) { - const char *probes[] = { "cmdlinepart", NULL }; - struct mtd_partition *parts; - int nr_parts; + info = platform_get_drvdata(pdev); + probe_success = 0; + for (cs = 0; cs < pdata->num_cs; cs++) { + info->cs = cs; + ret = pxa3xx_nand_scan(info->host[cs]->mtd); + if (ret) { + dev_warn(&pdev->dev, "failed to scan nand at cs %d\n", + cs); + continue; + } - nr_parts = parse_mtd_partitions(info->mtd, probes, &parts, 0); + ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0, + pdata->parts[cs], pdata->nr_parts[cs]); + if (!ret) + probe_success = 1; + } - if (nr_parts) - return mtd_device_register(info->mtd, parts, nr_parts); + if (!probe_success) { + pxa3xx_nand_remove(pdev); + return -ENODEV; } - return mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); + return 0; } #ifdef CONFIG_PM static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; + struct pxa3xx_nand_platform_data *pdata; + struct mtd_info *mtd; + int cs; + pdata = pdev->dev.platform_data; if (info->state) { dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); return -EAGAIN; } + for (cs = 0; cs < pdata->num_cs; cs++) { + mtd = info->host[cs]->mtd; + mtd->suspend(mtd); + } + return 0; } static int pxa3xx_nand_resume(struct platform_device *pdev) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; + struct pxa3xx_nand_platform_data *pdata; + struct mtd_info *mtd; + int cs; - nand_writel(info, NDTR0CS0, info->ndtr0cs0); - nand_writel(info, NDTR1CS0, info->ndtr1cs0); - clk_enable(info->clk); + pdata = pdev->dev.platform_data; + /* We don't want to handle interrupt without calling mtd routine */ + disable_int(info, NDCR_INT_MASK); + + /* + * Directly set the chip select to a invalid value, + * then the driver would reset the timing according + * to current chip select at the beginning of cmdfunc + */ + info->cs = 0xff; + + /* + * As the spec says, the NDSR would be updated to 0x1800 when + * doing the nand_clk disable/enable. + * To prevent it damaging state machine of the driver, clear + * all status before resume + */ + nand_writel(info, NDSR, NDSR_MASK); + for (cs = 0; cs < pdata->num_cs; cs++) { + mtd = info->host[cs]->mtd; + mtd->resume(mtd); + } return 0; } diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index cae2e013c986..f20f393bfda6 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -1027,7 +1027,7 @@ void r852_shutdown(struct pci_dev *pci_dev) } #ifdef CONFIG_PM -int r852_suspend(struct device *device) +static int r852_suspend(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); @@ -1048,7 +1048,7 @@ int r852_suspend(struct device *device) return 0; } -int r852_resume(struct device *device) +static int r852_resume(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); @@ -1092,7 +1092,7 @@ static const struct pci_device_id r852_pci_id_tbl[] = { MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl); -SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); +static SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); static struct pci_driver r852_pci_driver = { .name = DRV_NAME, diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index c9f9127ff770..f309addc2fa0 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -351,7 +351,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha return 0; } - /* Read the syndrom pattern from the FPGA and correct the bitorder */ + /* Read the syndrome pattern from the FPGA and correct the bitorder */ rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC); for (i = 0; i < 8; i++) { ecc[i] = bitrev8(*rs_ecc); @@ -380,7 +380,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha /* Let the library code do its magic. */ res = decode_rs8(rs_decoder, (uint8_t *) buf, par, 512, syn, 0, NULL, 0xff, NULL); if (res > 0) { - DEBUG(MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); + pr_debug("rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); } return res; } @@ -444,7 +444,6 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, len = mtd->writesize; buf = kmalloc(len, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n"); er_stat = 1; goto out; } diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 4405468f196b..868685db6712 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -723,7 +723,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) /* free the common resources */ - if (info->clk != NULL && !IS_ERR(info->clk)) { + if (!IS_ERR(info->clk)) { s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); clk_put(info->clk); } @@ -744,26 +744,15 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) return 0; } -const char *part_probes[] = { "cmdlinepart", NULL }; static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *mtd, struct s3c2410_nand_set *set) { - struct mtd_partition *part_info; - int nr_part = 0; + if (set) + mtd->mtd.name = set->name; - if (set == NULL) - return mtd_device_register(&mtd->mtd, NULL, 0); - - mtd->mtd.name = set->name; - nr_part = parse_mtd_partitions(&mtd->mtd, part_probes, &part_info, 0); - - if (nr_part <= 0 && set->nr_partitions > 0) { - nr_part = set->nr_partitions; - part_info = set->partitions; - } - - return mtd_device_register(&mtd->mtd, part_info, nr_part); + return mtd_device_parse_register(&mtd->mtd, NULL, 0, + set->partitions, set->nr_partitions); } /** @@ -880,8 +869,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, /* If you use u-boot BBT creation code, specifying this flag will * let the kernel fish out the BBT from the NAND, and also skip the * full NAND scan that can take 1/2s or so. Little things... */ - if (set->flash_bbt) - chip->options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; + if (set->flash_bbt) { + chip->bbt_options |= NAND_BBT_USE_FLASH; + chip->options |= NAND_SKIP_BBTSCAN; + } } /** diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 19e24ed089ea..619d2a504788 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -103,16 +103,12 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, return readb(sharpsl->io + ECCCNTR) != 0; } -static const char *part_probes[] = { "cmdlinepart", NULL }; - /* * Main initialization routine */ static int __devinit sharpsl_nand_probe(struct platform_device *pdev) { struct nand_chip *this; - struct mtd_partition *sharpsl_partition_info; - int nr_partitions; struct resource *r; int err = 0; struct sharpsl_nand *sharpsl; @@ -184,14 +180,9 @@ static int __devinit sharpsl_nand_probe(struct platform_device *pdev) /* Register the partitions */ sharpsl->mtd.name = "sharpsl-nand"; - nr_partitions = parse_mtd_partitions(&sharpsl->mtd, part_probes, &sharpsl_partition_info, 0); - if (nr_partitions <= 0) { - nr_partitions = data->nr_partitions; - sharpsl_partition_info = data->partitions; - } - err = mtd_device_register(&sharpsl->mtd, sharpsl_partition_info, - nr_partitions); + err = mtd_device_parse_register(&sharpsl->mtd, NULL, 0, + data->partitions, data->nr_partitions); if (err) goto err_add; diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c index b6332e83b289..32ae5af7444f 100644 --- a/drivers/mtd/nand/sm_common.c +++ b/drivers/mtd/nand/sm_common.c @@ -8,6 +8,7 @@ */ #include <linux/kernel.h> #include <linux/mtd/nand.h> +#include <linux/module.h> #include "sm_common.h" static struct nand_ecclayout nand_oob_sm = { @@ -47,7 +48,7 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) /* As long as this function is called on erase block boundaries it will work correctly for 256 byte nand */ - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; ops.oobbuf = (void *)&oob; diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index ca2d0555729e..0fb24f9c2327 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -155,8 +155,6 @@ static int socrates_nand_device_ready(struct mtd_info *mtd) return 1; } -static const char *part_probes[] = { "cmdlinepart", NULL }; - /* * Probe for the NAND device. */ @@ -166,8 +164,7 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) struct mtd_info *mtd; struct nand_chip *nand_chip; int res; - struct mtd_partition *partitions = NULL; - int num_partitions = 0; + struct mtd_part_parser_data ppdata; /* Allocate memory for the device structure (and zero it) */ host = kzalloc(sizeof(struct socrates_nand_host), GFP_KERNEL); @@ -193,6 +190,7 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) mtd->name = "socrates_nand"; mtd->owner = THIS_MODULE; mtd->dev.parent = &ofdev->dev; + ppdata.of_node = ofdev->dev.of_node; /*should never be accessed directly */ nand_chip->IO_ADDR_R = (void *)0xdeadbeef; @@ -225,30 +223,10 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) goto out; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partitions, 0); - if (num_partitions < 0) { - res = num_partitions; - goto release; - } -#endif - - if (num_partitions == 0) { - num_partitions = of_mtd_parse_partitions(&ofdev->dev, - ofdev->dev.of_node, - &partitions); - if (num_partitions < 0) { - res = num_partitions; - goto release; - } - } - - res = mtd_device_register(mtd, partitions, num_partitions); + res = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (!res) return res; -release: nand_release(mtd); out: diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 11e8371b5683..beebd95f7690 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -121,9 +121,6 @@ struct tmio_nand { #define mtd_to_tmio(m) container_of(m, struct tmio_nand, mtd) -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = { "cmdlinepart", NULL }; -#endif /*--------------------------------------------------------------------------*/ @@ -381,8 +378,6 @@ static int tmio_probe(struct platform_device *dev) struct tmio_nand *tmio; struct mtd_info *mtd; struct nand_chip *nand_chip; - struct mtd_partition *parts; - int nbparts = 0; int retval; if (data == NULL) @@ -461,15 +456,9 @@ static int tmio_probe(struct platform_device *dev) goto err_scan; } /* Register the partitions */ -#ifdef CONFIG_MTD_CMDLINE_PARTS - nbparts = parse_mtd_partitions(mtd, part_probes, &parts, 0); -#endif - if (nbparts <= 0 && data) { - parts = data->partition; - nbparts = data->num_partitions; - } - - retval = mtd_device_register(mtd, parts, nbparts); + retval = mtd_device_parse_register(mtd, NULL, 0, + data ? data->partition : NULL, + data ? data->num_partitions : 0); if (!retval) return retval; diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index bfba4e39a6c5..ace46fdaef58 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -74,7 +74,6 @@ struct txx9ndfmc_drvdata { unsigned char hold; /* in gbusclock */ unsigned char spw; /* in gbusclock */ struct nand_hw_control hw_control; - struct mtd_partition *parts[MAX_TXX9NDFMC_DEV]; }; static struct platform_device *mtd_to_platdev(struct mtd_info *mtd) @@ -287,7 +286,6 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd) static int __init txx9ndfmc_probe(struct platform_device *dev) { struct txx9ndfmc_platform_data *plat = dev->dev.platform_data; - static const char *probes[] = { "cmdlinepart", NULL }; int hold, spw; int i; struct txx9ndfmc_drvdata *drvdata; @@ -333,7 +331,6 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) struct txx9ndfmc_priv *txx9_priv; struct nand_chip *chip; struct mtd_info *mtd; - int nr_parts; if (!(plat->ch_mask & (1 << i))) continue; @@ -393,9 +390,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) } mtd->name = txx9_priv->mtdname; - nr_parts = parse_mtd_partitions(mtd, probes, - &drvdata->parts[i], 0); - mtd_device_register(mtd, drvdata->parts[i], nr_parts); + mtd_device_parse_register(mtd, NULL, 0, NULL, 0); drvdata->mtds[i] = mtd; } @@ -421,7 +416,6 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev) txx9_priv = chip->priv; nand_release(mtd); - kfree(drvdata->parts[i]); kfree(txx9_priv->mtdname); kfree(txx9_priv); } diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index b155666acfbe..cda77b562ad4 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -63,14 +63,12 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; } - DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name); + pr_debug("NFTL: add_mtd for %s\n", mtd->name); nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL); - if (!nftl) { - printk(KERN_WARNING "NFTL: out of memory for data structures\n"); + if (!nftl) return; - } nftl->mbd.mtd = mtd; nftl->mbd.devnum = -1; @@ -132,7 +130,7 @@ static void nftl_remove_dev(struct mtd_blktrans_dev *dev) { struct NFTLrecord *nftl = (void *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum); + pr_debug("NFTL: remove_dev (i=%d)\n", dev->devnum); del_mtd_blktrans_dev(dev); kfree(nftl->ReplUnitTable); @@ -149,7 +147,7 @@ int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & mask; ops.ooblen = len; ops.oobbuf = buf; @@ -170,7 +168,7 @@ int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & mask; ops.ooblen = len; ops.oobbuf = buf; @@ -193,7 +191,7 @@ static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & mask; ops.ooblen = mtd->oobsize; ops.oobbuf = oob; @@ -220,7 +218,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ) /* Normally, we force a fold to happen before we run out of free blocks completely */ if (!desperate && nftl->numfreeEUNs < 2) { - DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n"); + pr_debug("NFTL_findfreeblock: there are too few free EUNs\n"); return BLOCK_NIL; } @@ -291,8 +289,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p if (block == 2) { foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1; if (foldmark == FOLD_MARK_IN_PROGRESS) { - DEBUG(MTD_DEBUG_LEVEL1, - "Write Inhibited on EUN %d\n", thisEUN); + pr_debug("Write Inhibited on EUN %d\n", thisEUN); inplace = 0; } else { /* There's no other reason not to do inplace, @@ -357,7 +354,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p if (BlockLastState[block] != SECTOR_FREE && BlockMap[block] != BLOCK_NIL && BlockMap[block] != targetEUN) { - DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, " + pr_debug("Setting inplace to 0. VUC %d, " "block %d was %x lastEUN, " "and is in EUN %d (%s) %d\n", thisVUC, block, BlockLastState[block], @@ -373,14 +370,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) && BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] != SECTOR_FREE) { - DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. " + pr_debug("Pending write not free in EUN %d. " "Folding out of place.\n", targetEUN); inplace = 0; } } if (!inplace) { - DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. " + pr_debug("Cannot fold Virtual Unit Chain %d in place. " "Trying out-of-place\n", thisVUC); /* We need to find a targetEUN to fold into. */ targetEUN = NFTL_findfreeblock(nftl, 1); @@ -410,7 +407,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p and the Erase Unit into which we are supposed to be copying. Go for it. */ - DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN); + pr_debug("Folding chain %d into unit %d\n", thisVUC, targetEUN); for (block = 0; block < nftl->EraseSize / 512 ; block++) { unsigned char movebuf[512]; int ret; @@ -428,7 +425,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 512, &retlen, movebuf); - if (ret < 0 && ret != -EUCLEAN) { + if (ret < 0 && !mtd_is_bitflip(ret)) { ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 512, &retlen, movebuf); @@ -457,7 +454,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p has duplicate chains, we need to free one of the chains because it's not necessary any more. */ thisEUN = nftl->EUNtable[thisVUC]; - DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n"); + pr_debug("Want to erase\n"); /* For each block in the old chain (except the targetEUN of course), free it and make it available for future use */ @@ -570,7 +567,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) (writeEUN * nftl->EraseSize) + blockofs, 8, &retlen, (char *)&bci); - DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", + pr_debug("Status of block %d in EUN %d is %x\n", block , writeEUN, le16_to_cpu(bci.Status)); status = bci.Status | bci.Status1; @@ -623,7 +620,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) but they are reserved for when we're desperate. Well, now we're desperate. */ - DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC); + pr_debug("Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC); writeEUN = NFTL_findfreeblock(nftl, 1); } if (writeEUN == BLOCK_NIL) { @@ -776,7 +773,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, size_t retlen; int res = mtd->read(mtd, ptr, 512, &retlen, buffer); - if (res < 0 && res != -EUCLEAN) + if (res < 0 && !mtd_is_bitflip(res)) return -EIO; } return 0; diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index e3cd1ffad2f6..ac4092591aea 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -32,7 +32,7 @@ /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the * various device information of the NFTL partition and Bad Unit Table. Update - * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] + * the ReplUnitTable[] table according to the Bad Unit Table. ReplUnitTable[] * is used for management of Erase Unit in other routines in nftl.c and nftlmount.c */ static int find_boot_record(struct NFTLrecord *nftl) @@ -297,7 +297,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int * * Return: 0 when succeed, -1 on error. * - * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * ToDo: 1. Is it necessary to check_free_sector after erasing ?? */ int NFTL_formatblock(struct NFTLrecord *nftl, int block) { @@ -337,7 +337,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block) nb_erases = le32_to_cpu(uci.WearInfo); nb_erases++; - /* wrap (almost impossible with current flashs) or free block */ + /* wrap (almost impossible with current flash) or free block */ if (nb_erases == 0) nb_erases = 1; @@ -363,10 +363,10 @@ fail: * Mark as 'IGNORE' each incorrect sector. This check is only done if the chain * was being folded when NFTL was interrupted. * - * The check_free_sectors in this function is neceressary. There is a possible + * The check_free_sectors in this function is necessary. There is a possible * situation that after writing the Data area, the Block Control Information is * not updated according (due to power failure or something) which leaves the block - * in an umconsistent state. So we have to check if a block is really FREE in this + * in an inconsistent state. So we have to check if a block is really FREE in this * case. */ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block) { @@ -428,7 +428,7 @@ static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block) for (;;) { length++; - /* avoid infinite loops, although this is guaranted not to + /* avoid infinite loops, although this is guaranteed not to happen because of the previous checks */ if (length >= nftl->nb_blocks) { printk("nftl: length too long %d !\n", length); @@ -447,11 +447,11 @@ static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block) /* format_chain: Format an invalid Virtual Unit chain. It frees all the Erase Units in a * Virtual Unit Chain, i.e. all the units are disconnected. * - * It is not stricly correct to begin from the first block of the chain because + * It is not strictly correct to begin from the first block of the chain because * if we stop the code, we may see again a valid chain if there was a first_block * flag in a block inside it. But is it really a problem ? * - * FixMe: Figure out what the last statesment means. What if power failure when we are + * FixMe: Figure out what the last statement means. What if power failure when we are * in the for (;;) loop formatting blocks ?? */ static void format_chain(struct NFTLrecord *nftl, unsigned int first_block) @@ -485,7 +485,7 @@ static void format_chain(struct NFTLrecord *nftl, unsigned int first_block) * totally free (only 0xff). * * Definition: Free Erase Unit -- A properly erased/formatted Free Erase Unit should have meet the - * following critia: + * following criteria: * 1. */ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) { @@ -502,7 +502,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1)); if (erase_mark != ERASE_MARK) { /* if no erase mark, the block must be totally free. This is - possible in two cases : empty filsystem or interrupted erase (very unlikely) */ + possible in two cases : empty filesystem or interrupted erase (very unlikely) */ if (check_free_sectors (nftl, block * nftl->EraseSize, nftl->EraseSize, 1) != 0) return -1; @@ -544,7 +544,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) /* get_fold_mark: Read fold mark from Unit Control Information #2, we use FOLD_MARK_IN_PROGRESS * to indicate that we are in the progression of a Virtual Unit Chain folding. If the UCI #2 * is FOLD_MARK_IN_PROGRESS when mounting the NFTL, the (previous) folding process is interrupted - * for some reason. A clean up/check of the VUC is neceressary in this case. + * for some reason. A clean up/check of the VUC is necessary in this case. * * WARNING: return 0 if read error */ @@ -657,7 +657,7 @@ int NFTL_mount(struct NFTLrecord *s) printk("Block %d: incorrect logical block: %d expected: %d\n", block, logical_block, first_logical_block); /* the chain is incorrect : we must format it, - but we need to read it completly */ + but we need to read it completely */ do_format_chain = 1; } if (is_first_block) { @@ -669,7 +669,7 @@ int NFTL_mount(struct NFTLrecord *s) printk("Block %d: incorrectly marked as first block in chain\n", block); /* the chain is incorrect : we must format it, - but we need to read it completly */ + but we need to read it completely */ do_format_chain = 1; } else { printk("Block %d: folding in progress - ignoring first block flag\n", diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index a996718fa6b0..64be8f0848b0 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -20,14 +20,23 @@ #include <linux/slab.h> #include <linux/mtd/partitions.h> -int __devinit of_mtd_parse_partitions(struct device *dev, - struct device_node *node, - struct mtd_partition **pparts) +static int parse_ofpart_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { + struct device_node *node; const char *partname; struct device_node *pp; int nr_parts, i; + + if (!data) + return 0; + + node = data->of_node; + if (!node) + return 0; + /* First count the subnodes */ pp = NULL; nr_parts = 0; @@ -69,7 +78,7 @@ int __devinit of_mtd_parse_partitions(struct device *dev, if (!i) { of_node_put(pp); - dev_err(dev, "No valid partition found on %s\n", node->full_name); + pr_err("No valid partition found on %s\n", node->full_name); kfree(*pparts); *pparts = NULL; return -EINVAL; @@ -77,6 +86,99 @@ int __devinit of_mtd_parse_partitions(struct device *dev, return nr_parts; } -EXPORT_SYMBOL(of_mtd_parse_partitions); + +static struct mtd_part_parser ofpart_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_ofpart_partitions, + .name = "ofpart", +}; + +static int parse_ofoldpart_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *dp; + int i, plen, nr_parts; + const struct { + __be32 offset, len; + } *part; + const char *names; + + if (!data) + return 0; + + dp = data->of_node; + if (!dp) + return 0; + + part = of_get_property(dp, "partitions", &plen); + if (!part) + return 0; /* No partitions found */ + + pr_warning("Device tree uses obsolete partition map binding: %s\n", + dp->full_name); + + nr_parts = plen / sizeof(part[0]); + + *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL); + if (!pparts) + return -ENOMEM; + + names = of_get_property(dp, "partition-names", &plen); + + for (i = 0; i < nr_parts; i++) { + (*pparts)[i].offset = be32_to_cpu(part->offset); + (*pparts)[i].size = be32_to_cpu(part->len) & ~1; + /* bit 0 set signifies read only partition */ + if (be32_to_cpu(part->len) & 1) + (*pparts)[i].mask_flags = MTD_WRITEABLE; + + if (names && (plen > 0)) { + int len = strlen(names) + 1; + + (*pparts)[i].name = (char *)names; + plen -= len; + names += len; + } else { + (*pparts)[i].name = "unnamed"; + } + + part++; + } + + return nr_parts; +} + +static struct mtd_part_parser ofoldpart_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_ofoldpart_partitions, + .name = "ofoldpart", +}; + +static int __init ofpart_parser_init(void) +{ + int rc; + rc = register_mtd_parser(&ofpart_parser); + if (rc) + goto out; + + rc = register_mtd_parser(&ofoldpart_parser); + if (!rc) + return 0; + + deregister_mtd_parser(&ofoldpart_parser); +out: + return rc; +} + +module_init(ofpart_parser_init); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree"); +MODULE_AUTHOR("Vitaly Wool, David Gibson"); +/* + * When MTD core cannot find the requested parser, it tries to load the module + * with the same name. Since we provide the ofoldpart parser, we should have + * the corresponding alias. + */ +MODULE_ALIAS("ofoldpart"); diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 2d70d354d846..7813095264a5 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -30,11 +30,8 @@ */ #define DRIVER_NAME "onenand-flash" -static const char *part_probes[] = { "cmdlinepart", NULL, }; - struct onenand_info { struct mtd_info mtd; - struct mtd_partition *parts; struct onenand_chip onenand; }; @@ -73,13 +70,9 @@ static int __devinit generic_onenand_probe(struct platform_device *pdev) goto out_iounmap; } - err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); - if (err > 0) - mtd_device_register(&info->mtd, info->parts, err); - else if (err <= 0 && pdata && pdata->parts) - mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts); - else - err = mtd_device_register(&info->mtd, NULL, 0); + err = mtd_device_parse_register(&info->mtd, NULL, 0, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); platform_set_drvdata(pdev, info); @@ -104,7 +97,6 @@ static int __devexit generic_onenand_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (info) { - mtd_device_unregister(&info->mtd); onenand_release(&info->mtd); release_mem_region(res->start, size); iounmap(info->onenand.base); diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 6a1d6d9a2df9..7e9ea6852b67 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -57,7 +57,6 @@ struct omap2_onenand { unsigned long phys_base; int gpio_irq; struct mtd_info mtd; - struct mtd_partition *parts; struct onenand_chip onenand; struct completion irq_done; struct completion dma_done; @@ -67,8 +66,6 @@ struct omap2_onenand { struct regulator *regulator; }; -static const char *part_probes[] = { "cmdlinepart", NULL, }; - static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) { struct omap2_onenand *c = data; @@ -741,6 +738,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) c->regulator = regulator_get(&pdev->dev, "vonenand"); if (IS_ERR(c->regulator)) { dev_err(&pdev->dev, "Failed to get regulator\n"); + r = PTR_ERR(c->regulator); goto err_release_dma; } c->onenand.enable = omap2_onenand_enable; @@ -753,13 +751,9 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) if ((r = onenand_scan(&c->mtd, 1)) < 0) goto err_release_regulator; - r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0); - if (r > 0) - r = mtd_device_register(&c->mtd, c->parts, r); - else if (pdata->parts != NULL) - r = mtd_device_register(&c->mtd, pdata->parts, pdata->nr_parts); - else - r = mtd_device_register(&c->mtd, NULL, 0); + r = mtd_device_parse_register(&c->mtd, NULL, 0, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); if (r) goto err_release_onenand; @@ -786,7 +780,6 @@ err_release_mem_region: err_free_cs: gpmc_cs_free(c->gpmc_cs); err_kfree: - kfree(c->parts); kfree(c); return r; @@ -809,7 +802,6 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) iounmap(c->onenand.base); release_mem_region(c->phys_base, ONENAND_IO_SIZE); gpmc_cs_free(c->gpmc_cs); - kfree(c->parts); kfree(c); return 0; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index ac9e959802a7..a8394730b4b6 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1015,7 +1015,7 @@ static void onenand_release_device(struct mtd_info *mtd) } /** - * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer + * onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer * @param mtd MTD device structure * @param buf destination address * @param column oob offset to read from @@ -1079,7 +1079,7 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status) return status; /* check if we failed due to uncorrectable error */ - if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR) + if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR) return status; /* check if address lies in MLC region */ @@ -1122,10 +1122,10 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, int ret = 0; int writesize = this->writesize; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", - __func__, (unsigned int) from, (int) len); + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, + (int)len); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1159,7 +1159,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, if (unlikely(ret)) ret = onenand_recover_lsb(mtd, from, ret); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; if (ret) break; @@ -1170,7 +1170,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, thisooblen = oobsize - oobcolumn; thisooblen = min_t(int, thisooblen, ooblen - oobread); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); else this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -1226,10 +1226,10 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, int ret = 0, boundary = 0; int writesize = this->writesize; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", - __func__, (unsigned int) from, (int) len); + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, + (int)len); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1255,7 +1255,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, this->command(mtd, ONENAND_CMD_READ, from, writesize); ret = this->wait(mtd, FL_READING); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; } } @@ -1291,7 +1291,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, thisooblen = oobsize - oobcolumn; thisooblen = min_t(int, thisooblen, ooblen - oobread); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); else this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -1315,7 +1315,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, /* Now wait for load */ ret = this->wait(mtd, FL_READING); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; } @@ -1351,19 +1351,19 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, struct mtd_ecc_stats stats; int read = 0, thislen, column, oobsize; size_t len = ops->ooblen; - mtd_oob_mode_t mode = ops->mode; + unsigned int mode = ops->mode; u_char *buf = ops->oobbuf; int ret = 0, readcmd; from += ops->ooboffs; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", - __func__, (unsigned int) from, (int) len); + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, + (int)len); /* Initialize return length value */ ops->oobretlen = 0; - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1403,13 +1403,13 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, if (unlikely(ret)) ret = onenand_recover_lsb(mtd, from, ret); - if (ret && ret != -EBADMSG) { + if (ret && !mtd_is_eccerr(ret)) { printk(KERN_ERR "%s: read failed = 0x%x\n", __func__, ret); break; } - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, buf, column, thislen); else this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); @@ -1487,10 +1487,10 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, int ret; switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: break; - case MTD_OOB_RAW: + case MTD_OPS_RAW: /* Not implemented yet */ default: return -EINVAL; @@ -1576,8 +1576,8 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, size_t len = ops->ooblen; u_char *buf = ops->oobbuf; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %zi\n", - __func__, (unsigned int) from, len); + pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int)from, + len); /* Initialize return value */ ops->oobretlen = 0; @@ -1750,8 +1750,8 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, /* Wait for any existing operation to clear */ onenand_panic_wait(mtd); - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int) to, (int) len); + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, + (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; @@ -1821,7 +1821,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, } /** - * onenand_fill_auto_oob - [Internal] oob auto-placement transfer + * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer * @param mtd MTD device structure * @param oob_buf oob buffer * @param buf source address @@ -1883,8 +1883,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, u_char *oobbuf; int ret = 0, cmd; - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int) to, (int) len); + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, + (int)len); /* Initialize retlen, in case of early exit */ ops->retlen = 0; @@ -1908,7 +1908,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, if (!len) return 0; - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1945,7 +1945,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, /* We send data to spare ram with oobsize * to prevent byte access */ memset(oobbuf, 0xff, mtd->oobsize); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); else memcpy(oobbuf + oobcolumn, oob, thisooblen); @@ -2055,7 +2055,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, /** - * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band + * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write @@ -2074,17 +2074,17 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, u_char *oobbuf; size_t len = ops->ooblen; const u_char *buf = ops->oobbuf; - mtd_oob_mode_t mode = ops->mode; + unsigned int mode = ops->mode; to += ops->ooboffs; - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int) to, (int) len); + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, + (int)len); /* Initialize retlen, in case of early exit */ ops->oobretlen = 0; - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -2128,7 +2128,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, /* We send data to spare ram with oobsize * to prevent byte access */ memset(oobbuf, 0xff, mtd->oobsize); - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen); else memcpy(oobbuf + column, buf, thislen); @@ -2217,10 +2217,10 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, int ret; switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: break; - case MTD_OOB_RAW: + case MTD_OPS_RAW: /* Not implemented yet */ default: return -EINVAL; @@ -2281,7 +2281,7 @@ static int onenand_multiblock_erase_verify(struct mtd_info *mtd, } /** - * onenand_multiblock_erase - [Internal] erase block(s) using multiblock erase + * onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase * @param mtd MTD device structure * @param instr erase instruction * @param region erase region @@ -2397,7 +2397,7 @@ static int onenand_multiblock_erase(struct mtd_info *mtd, /** - * onenand_block_by_block_erase - [Internal] erase block(s) using regular erase + * onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase * @param mtd MTD device structure * @param instr erase instruction * @param region erase region @@ -2489,8 +2489,9 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) struct mtd_erase_region_info *region = NULL; loff_t region_offset = 0; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start=0x%012llx, len=%llu\n", __func__, - (unsigned long long) instr->addr, (unsigned long long) instr->len); + pr_debug("%s: start=0x%012llx, len=%llu\n", __func__, + (unsigned long long)instr->addr, + (unsigned long long)instr->len); /* Do not allow erase past end of device */ if (unlikely((len + addr) > mtd->size)) { @@ -2558,7 +2559,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) */ static void onenand_sync(struct mtd_info *mtd) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); + pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_SYNCING); @@ -2602,7 +2603,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) struct bbm_info *bbm = this->bbm; u_char buf[2] = {0, 0}; struct mtd_oob_ops ops = { - .mode = MTD_OOB_PLACE, + .mode = MTD_OPS_PLACE_OOB, .ooblen = 2, .oobbuf = buf, .ooboffs = 0, @@ -2922,7 +2923,7 @@ static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr, } /** - * onenand_otp_write_oob_nolock - [Internal] OneNAND write out-of-band, specific to OTP + * onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write @@ -3170,7 +3171,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, this->command(mtd, ONENAND_CMD_RESET, 0, 0); this->wait(mtd, FL_RESETING); } else { - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooblen = len; ops.oobbuf = buf; ops.ooboffs = 0; @@ -3429,6 +3430,19 @@ static void onenand_check_features(struct mtd_info *mtd) else if (numbufs == 1) { this->options |= ONENAND_HAS_4KB_PAGE; this->options |= ONENAND_HAS_CACHE_PROGRAM; + /* + * There are two different 4KiB pagesize chips + * and no way to detect it by H/W config values. + * + * To detect the correct NOP for each chips, + * It should check the version ID as workaround. + * + * Now it has as following + * KFM4G16Q4M has NOP 4 with version ID 0x0131 + * KFM4G16Q5M has NOP 1 with versoin ID 0x013e + */ + if ((this->version_id & 0xf) == 0xe) + this->options |= ONENAND_HAS_NOP_1; } case ONENAND_DEVICE_DENSITY_2Gb: @@ -3663,7 +3677,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int int i, ret; int block; struct mtd_oob_ops ops = { - .mode = MTD_OOB_PLACE, + .mode = MTD_OPS_PLACE_OOB, .ooboffs = 0, .ooblen = mtd->oobsize, .datbuf = NULL, @@ -4054,6 +4068,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) this->ecclayout = &onenand_oob_128; mtd->subpage_sft = 2; } + if (ONENAND_IS_NOP_1(this)) + mtd->subpage_sft = 0; break; case 64: this->ecclayout = &onenand_oob_64; diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index fc2c16a0fd1c..66fe3b7e7851 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/onenand.h> +#include <linux/export.h> /** * check_short_pattern - [GENERIC] check if a pattern is in the buffer @@ -80,7 +81,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr startblock = 0; from = 0; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooblen = readlen; ops.oobbuf = buf; ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; @@ -153,7 +154,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) block = (int) (onenand_block(this, offs) << 1); res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG(MTD_DEBUG_LEVEL2, "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", + pr_debug("onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", (unsigned int) offs, block >> 1, res); switch ((int) res) { @@ -188,10 +189,8 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) len = this->chipsize >> (this->erase_shift + 2); /* Allocate memory (2bit per block) and clear the memory bad block table */ bbm->bbt = kzalloc(len, GFP_KERNEL); - if (!bbm->bbt) { - printk(KERN_ERR "onenand_scan_bbt: Out of memory\n"); + if (!bbm->bbt) return -ENOMEM; - } /* Set the bad block position */ bbm->badblockpos = ONENAND_BADBLOCK_POS; diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 3306b5b3c736..5474547eafc2 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -147,7 +147,6 @@ struct s3c_onenand { struct resource *dma_res; unsigned long phys_base; struct completion complete; - struct mtd_partition *parts; }; #define CMD_MAP_00(dev, addr) (dev->cmd_map(MAP_00, ((addr) << 1))) @@ -157,8 +156,6 @@ struct s3c_onenand { static struct s3c_onenand *onenand; -static const char *part_probes[] = { "cmdlinepart", NULL, }; - static inline int s3c_read_reg(int offset) { return readl(onenand->base + offset); @@ -1017,13 +1014,9 @@ static int s3c_onenand_probe(struct platform_device *pdev) if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ) dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n"); - err = parse_mtd_partitions(mtd, part_probes, &onenand->parts, 0); - if (err > 0) - mtd_device_register(mtd, onenand->parts, err); - else if (err <= 0 && pdata && pdata->parts) - mtd_device_register(mtd, pdata->parts, pdata->nr_parts); - else - err = mtd_device_register(mtd, NULL, 0); + err = mtd_device_parse_register(mtd, NULL, 0, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); platform_set_drvdata(pdev, mtd); diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 7a87d07cd79f..e366b1d84ead 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -28,6 +28,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/module.h> struct fis_image_desc { unsigned char name[16]; // Null terminated name @@ -56,8 +57,8 @@ static inline int redboot_checksum(struct fis_image_desc *img) } static int parse_redboot_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - unsigned long fis_origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { int nrparts = 0; struct fis_image_desc *buf; @@ -197,11 +198,10 @@ static int parse_redboot_partitions(struct mtd_info *master, goto out; } new_fl->img = &buf[i]; - if (fis_origin) { - buf[i].flash_base -= fis_origin; - } else { - buf[i].flash_base &= master->size-1; - } + if (data && data->origin) + buf[i].flash_base -= data->origin; + else + buf[i].flash_base &= master->size-1; /* I'm sure the JFFS2 code has done me permanent damage. * I now think the following is _normal_ @@ -297,6 +297,9 @@ static struct mtd_part_parser redboot_parser = { .name = "RedBoot", }; +/* mtd parsers will request the module by parser name */ +MODULE_ALIAS("RedBoot"); + static int __init redboot_parser_init(void) { return register_mtd_parser(&redboot_parser); diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index cc4d1805b864..73ae217a4252 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -18,6 +18,7 @@ #include <linux/vmalloc.h> #include <linux/slab.h> #include <linux/jiffies.h> +#include <linux/module.h> #include <asm/types.h> diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index ed3d6cd2c6dc..fddb714e323c 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -34,7 +34,7 @@ module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level (0-2)"); -/* ------------------- sysfs attributtes ---------------------------------- */ +/* ------------------- sysfs attributes ---------------------------------- */ struct sm_sysfs_attribute { struct device_attribute dev_attr; char *data; @@ -138,7 +138,7 @@ static int sm_get_lba(uint8_t *lba) if ((lba[0] & 0xF8) != 0x10) return -2; - /* check parity - endianess doesn't matter */ + /* check parity - endianness doesn't matter */ if (hweight16(*(uint16_t *)lba) & 1) return -2; @@ -147,7 +147,7 @@ static int sm_get_lba(uint8_t *lba) /* - * Read LBA asscociated with block + * Read LBA associated with block * returns -1, if block is erased * returns -2 if error happens */ @@ -252,11 +252,11 @@ static int sm_read_sector(struct sm_ftl *ftl, return 0; } - /* User might not need the oob, but we do for data vertification */ + /* User might not need the oob, but we do for data verification */ if (!oob) oob = &tmp_oob; - ops.mode = ftl->smallpagenand ? MTD_OOB_RAW : MTD_OOB_PLACE; + ops.mode = ftl->smallpagenand ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = SM_OOB_SIZE; ops.oobbuf = (void *)oob; @@ -276,12 +276,12 @@ again: return ret; } - /* Unfortunelly, oob read will _always_ succeed, + /* Unfortunately, oob read will _always_ succeed, despite card removal..... */ ret = mtd->read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops); /* Test for unknown errors */ - if (ret != 0 && ret != -EUCLEAN && ret != -EBADMSG) { + if (ret != 0 && !mtd_is_bitflip_or_eccerr(ret)) { dbg("read of block %d at zone %d, failed due to error (%d)", block, zone, ret); goto again; @@ -306,7 +306,7 @@ again: } /* Test ECC*/ - if (ret == -EBADMSG || + if (mtd_is_eccerr(ret) || (ftl->smallpagenand && sm_correct_sector(buffer, oob))) { dbg("read of block %d at zone %d, failed due to ECC error", @@ -336,7 +336,7 @@ static int sm_write_sector(struct sm_ftl *ftl, if (ftl->unstable) return -EIO; - ops.mode = ftl->smallpagenand ? MTD_OOB_RAW : MTD_OOB_PLACE; + ops.mode = ftl->smallpagenand ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB; ops.len = SM_SECTOR_SIZE; ops.datbuf = buffer; ops.ooboffs = 0; @@ -447,14 +447,14 @@ static void sm_mark_block_bad(struct sm_ftl *ftl, int zone, int block) /* We aren't checking the return value, because we don't care */ /* This also fails on fake xD cards, but I guess these won't expose - any bad blocks till fail completly */ + any bad blocks till fail completely */ for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE) sm_write_sector(ftl, zone, block, boffset, NULL, &oob); } /* * Erase a block within a zone - * If erase succedes, it updates free block fifo, otherwise marks block as bad + * If erase succeeds, it updates free block fifo, otherwise marks block as bad */ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block, int put_free) @@ -510,7 +510,7 @@ static void sm_erase_callback(struct erase_info *self) complete(&ftl->erase_completion); } -/* Throughtly test that block is valid. */ +/* Thoroughly test that block is valid. */ static int sm_check_block(struct sm_ftl *ftl, int zone, int block) { int boffset; @@ -526,7 +526,7 @@ static int sm_check_block(struct sm_ftl *ftl, int zone, int block) for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE) { - /* This shoudn't happen anyway */ + /* This shouldn't happen anyway */ if (sm_read_sector(ftl, zone, block, boffset, NULL, &oob)) return -2; diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 5cd189793332..976e3d28b962 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -135,8 +135,7 @@ static int get_valid_cis_sector(struct mtd_info *mtd) /* Found */ cis_sector = (int)(offset >> SECTOR_SHIFT); } else { - DEBUG(MTD_DEBUG_LEVEL1, - "SSFDC_RO: CIS/IDI sector not found" + pr_debug("SSFDC_RO: CIS/IDI sector not found" " on %s (mtd%d)\n", mtd->name, mtd->index); } @@ -170,7 +169,7 @@ static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf) struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.ooboffs = 0; ops.ooblen = OOB_SIZE; ops.oobbuf = buf; @@ -221,8 +220,7 @@ static int get_logical_address(uint8_t *oob_buf) block_address >>= 1; if (get_parity(block_address, 10) != parity) { - DEBUG(MTD_DEBUG_LEVEL0, - "SSFDC_RO: logical address field%d" + pr_debug("SSFDC_RO: logical address field%d" "parity error(0x%04X)\n", j+1, block_address); } else { @@ -235,7 +233,7 @@ static int get_logical_address(uint8_t *oob_buf) if (!ok) block_address = -2; - DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n", + pr_debug("SSFDC_RO: get_logical_address() %d\n", block_address); return block_address; @@ -249,7 +247,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc) int ret, block_address, phys_block; struct mtd_info *mtd = ssfdc->mbd.mtd; - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n", + pr_debug("SSFDC_RO: build_block_map() nblks=%d (%luK)\n", ssfdc->map_len, (unsigned long)ssfdc->map_len * ssfdc->erase_size / 1024); @@ -262,8 +260,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc) ret = read_raw_oob(mtd, offset, oob_buf); if (ret < 0) { - DEBUG(MTD_DEBUG_LEVEL0, - "SSFDC_RO: mtd read_oob() failed at %lu\n", + pr_debug("SSFDC_RO: mtd read_oob() failed at %lu\n", offset); return -1; } @@ -279,8 +276,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc) ssfdc->logic_block_map[block_address] = (unsigned short)phys_block; - DEBUG(MTD_DEBUG_LEVEL2, - "SSFDC_RO: build_block_map() phys_block=%d," + pr_debug("SSFDC_RO: build_block_map() phys_block=%d," "logic_block_addr=%d, zone=%d\n", phys_block, block_address, zone_index); } @@ -304,11 +300,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; ssfdc = kzalloc(sizeof(struct ssfdcr_record), GFP_KERNEL); - if (!ssfdc) { - printk(KERN_WARNING - "SSFDC_RO: out of memory for data structures\n"); + if (!ssfdc) return; - } ssfdc->mbd.mtd = mtd; ssfdc->mbd.devnum = -1; @@ -319,8 +312,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->erase_size = mtd->erasesize; ssfdc->map_len = (u32)mtd->size / mtd->erasesize; - DEBUG(MTD_DEBUG_LEVEL1, - "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", + pr_debug("SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len, DIV_ROUND_UP(ssfdc->map_len, MAX_PHYS_BLK_PER_ZONE)); @@ -331,7 +323,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->cylinders = (unsigned short)(((u32)mtd->size >> SECTOR_SHIFT) / ((long)ssfdc->sectors * (long)ssfdc->heads)); - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", + pr_debug("SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", ssfdc->cylinders, ssfdc->heads , ssfdc->sectors, (long)ssfdc->cylinders * (long)ssfdc->heads * (long)ssfdc->sectors); @@ -342,11 +334,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) /* Allocate logical block map */ ssfdc->logic_block_map = kmalloc(sizeof(ssfdc->logic_block_map[0]) * ssfdc->map_len, GFP_KERNEL); - if (!ssfdc->logic_block_map) { - printk(KERN_WARNING - "SSFDC_RO: out of memory for data structures\n"); + if (!ssfdc->logic_block_map) goto out_err; - } memset(ssfdc->logic_block_map, 0xff, sizeof(ssfdc->logic_block_map[0]) * ssfdc->map_len); @@ -371,7 +360,7 @@ static void ssfdcr_remove_dev(struct mtd_blktrans_dev *dev) { struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: remove_dev (i=%d)\n", dev->devnum); + pr_debug("SSFDC_RO: remove_dev (i=%d)\n", dev->devnum); del_mtd_blktrans_dev(dev); kfree(ssfdc->logic_block_map); @@ -387,8 +376,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev, offset = (int)(logic_sect_no % sectors_per_block); block_address = (int)(logic_sect_no / sectors_per_block); - DEBUG(MTD_DEBUG_LEVEL3, - "SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d," + pr_debug("SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d," " block_addr=%d\n", logic_sect_no, sectors_per_block, offset, block_address); @@ -397,8 +385,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev, block_address = ssfdc->logic_block_map[block_address]; - DEBUG(MTD_DEBUG_LEVEL3, - "SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n", + pr_debug("SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n", block_address); if (block_address < 0xffff) { @@ -407,8 +394,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev, sect_no = (unsigned long)block_address * sectors_per_block + offset; - DEBUG(MTD_DEBUG_LEVEL3, - "SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n", + pr_debug("SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n", sect_no); if (read_physical_sector(ssfdc->mbd.mtd, buf, sect_no) < 0) @@ -424,7 +410,7 @@ static int ssfdcr_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) { struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n", + pr_debug("SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n", ssfdc->cylinders, ssfdc->heads, ssfdc->sectors); geo->heads = ssfdc->heads; diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c index dec92ae6111a..933f7e5f32d3 100644 --- a/drivers/mtd/tests/mtd_oobtest.c +++ b/drivers/mtd/tests/mtd_oobtest.c @@ -30,7 +30,7 @@ #define PRINT_PREF KERN_INFO "mtd_oobtest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -131,7 +131,7 @@ static int write_eraseblock(int ebnum) for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { set_random_data(writebuf, use_len); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; @@ -184,7 +184,7 @@ static int verify_eraseblock(int ebnum) for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { set_random_data(writebuf, use_len); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; @@ -211,7 +211,7 @@ static int verify_eraseblock(int ebnum) if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { int k; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; @@ -276,7 +276,7 @@ static int verify_eraseblock_in_one_go(int ebnum) size_t len = mtd->ecclayout->oobavail * pgcnt; set_random_data(writebuf, len); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = len; @@ -366,6 +366,13 @@ static int __init mtd_oobtest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); @@ -507,7 +514,7 @@ static int __init mtd_oobtest_init(void) addr0 += mtd->erasesize; /* Attempt to write off end of OOB */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; @@ -527,7 +534,7 @@ static int __init mtd_oobtest_init(void) } /* Attempt to read off end of OOB */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; @@ -551,7 +558,7 @@ static int __init mtd_oobtest_init(void) "block is bad\n"); else { /* Attempt to write off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; @@ -571,7 +578,7 @@ static int __init mtd_oobtest_init(void) } /* Attempt to read off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; @@ -595,7 +602,7 @@ static int __init mtd_oobtest_init(void) goto out; /* Attempt to write off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; @@ -615,7 +622,7 @@ static int __init mtd_oobtest_init(void) } /* Attempt to read off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; @@ -655,7 +662,7 @@ static int __init mtd_oobtest_init(void) addr = (i + 1) * mtd->erasesize - mtd->writesize; for (pg = 0; pg < cnt; ++pg) { set_random_data(writebuf, sz); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = sz; @@ -683,7 +690,7 @@ static int __init mtd_oobtest_init(void) continue; set_random_data(writebuf, mtd->ecclayout->oobavail * 2); addr = (i + 1) * mtd->erasesize - mtd->writesize; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail * 2; diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c index 00b937e38c1d..afafb6935fd0 100644 --- a/drivers/mtd/tests/mtd_pagetest.c +++ b/drivers/mtd/tests/mtd_pagetest.c @@ -30,7 +30,7 @@ #define PRINT_PREF KERN_INFO "mtd_pagetest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -128,7 +128,7 @@ static int verify_eraseblock(int ebnum) for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) { /* Do a read to set the internal dataRAMs to different data */ err = mtd->read(mtd, addr0, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -136,7 +136,7 @@ static int verify_eraseblock(int ebnum) return err; } err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -146,7 +146,7 @@ static int verify_eraseblock(int ebnum) memset(twopages, 0, bufsize); read = 0; err = mtd->read(mtd, addr, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -164,7 +164,7 @@ static int verify_eraseblock(int ebnum) unsigned long oldnext = next; /* Do a read to set the internal dataRAMs to different data */ err = mtd->read(mtd, addr0, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -172,7 +172,7 @@ static int verify_eraseblock(int ebnum) return err; } err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -182,7 +182,7 @@ static int verify_eraseblock(int ebnum) memset(twopages, 0, bufsize); read = 0; err = mtd->read(mtd, addr, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -231,7 +231,7 @@ static int crosstest(void) read = 0; addr = addrn - pgsize - pgsize; err = mtd->read(mtd, addr, pgsize, &read, pp1); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -244,7 +244,7 @@ static int crosstest(void) read = 0; addr = addrn - pgsize - pgsize - pgsize; err = mtd->read(mtd, addr, pgsize, &read, pp1); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -258,7 +258,7 @@ static int crosstest(void) addr = addr0; printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); err = mtd->read(mtd, addr, pgsize, &read, pp2); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -272,7 +272,7 @@ static int crosstest(void) addr = addrn - pgsize; printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); err = mtd->read(mtd, addr, pgsize, &read, pp3); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -286,7 +286,7 @@ static int crosstest(void) addr = addr0; printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); err = mtd->read(mtd, addr, pgsize, &read, pp4); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -345,7 +345,7 @@ static int erasecrosstest(void) printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtd->read(mtd, addr0, pgsize, &read, readbuf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -383,7 +383,7 @@ static int erasecrosstest(void) printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtd->read(mtd, addr0, pgsize, &read, readbuf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -439,7 +439,7 @@ static int erasetest(void) printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); err = mtd->read(mtd, addr0, pgsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -504,6 +504,13 @@ static int __init mtd_pagetest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c index afe71aa15c4b..550fe51225a7 100644 --- a/drivers/mtd/tests/mtd_readtest.c +++ b/drivers/mtd/tests/mtd_readtest.c @@ -29,7 +29,7 @@ #define PRINT_PREF KERN_INFO "mtd_readtest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -66,7 +66,7 @@ static int read_eraseblock_by_page(int ebnum) if (mtd->oobsize) { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->oobsize; @@ -75,7 +75,8 @@ static int read_eraseblock_by_page(int ebnum) ops.datbuf = NULL; ops.oobbuf = oobbuf; ret = mtd->read_oob(mtd, addr, &ops); - if (ret || ops.oobretlen != mtd->oobsize) { + if ((ret && !mtd_is_bitflip(ret)) || + ops.oobretlen != mtd->oobsize) { printk(PRINT_PREF "error: read oob failed at " "%#llx\n", (long long)addr); if (!err) @@ -169,6 +170,12 @@ static int __init mtd_readtest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 627d4e2466a3..493b367bdd35 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -29,7 +29,7 @@ #define PRINT_PREF KERN_INFO "mtd_speedtest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -216,7 +216,7 @@ static int read_eraseblock(int ebnum) err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != mtd->erasesize) { printk(PRINT_PREF "error: read failed at %#llx\n", addr); @@ -237,7 +237,7 @@ static int read_eraseblock_by_page(int ebnum) for (i = 0; i < pgcnt; i++) { err = mtd->read(mtd, addr, pgsize, &read, buf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -263,7 +263,7 @@ static int read_eraseblock_by_2pages(int ebnum) for (i = 0; i < n; i++) { err = mtd->read(mtd, addr, sz, &read, buf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != sz) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -278,7 +278,7 @@ static int read_eraseblock_by_2pages(int ebnum) if (pgcnt % 2) { err = mtd->read(mtd, addr, pgsize, &read, buf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -361,6 +361,13 @@ static int __init mtd_speedtest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + if (count) printk(PRINT_PREF "MTD device: %d count: %d\n", dev, count); else diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c index 531625fc9259..52ffd9120e0d 100644 --- a/drivers/mtd/tests/mtd_stresstest.c +++ b/drivers/mtd/tests/mtd_stresstest.c @@ -30,7 +30,7 @@ #define PRINT_PREF KERN_INFO "mtd_stresstest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -154,7 +154,7 @@ static int do_read(void) } addr = eb * mtd->erasesize + offs; err = mtd->read(mtd, addr, len, &read, readbuf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (unlikely(err || read != len)) { printk(PRINT_PREF "error: read failed at 0x%llx\n", @@ -250,6 +250,13 @@ static int __init mtd_stresstest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c index 334eae53a3db..1a05bfac4eee 100644 --- a/drivers/mtd/tests/mtd_subpagetest.c +++ b/drivers/mtd/tests/mtd_subpagetest.c @@ -29,7 +29,7 @@ #define PRINT_PREF KERN_INFO "mtd_subpagetest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -198,7 +198,7 @@ static int verify_eraseblock(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { - if (err == -EUCLEAN && read == subpgsize) { + if (mtd_is_bitflip(err) && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -226,7 +226,7 @@ static int verify_eraseblock(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { - if (err == -EUCLEAN && read == subpgsize) { + if (mtd_is_bitflip(err) && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -264,7 +264,7 @@ static int verify_eraseblock2(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf); if (unlikely(err || read != subpgsize * k)) { - if (err == -EUCLEAN && read == subpgsize * k) { + if (mtd_is_bitflip(err) && read == subpgsize * k) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -298,7 +298,7 @@ static int verify_eraseblock_ff(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { - if (err == -EUCLEAN && read == subpgsize) { + if (mtd_is_bitflip(err) && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -379,6 +379,13 @@ static int __init mtd_subpagetest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c index 5c6c3d248901..03ab649a6964 100644 --- a/drivers/mtd/tests/mtd_torturetest.c +++ b/drivers/mtd/tests/mtd_torturetest.c @@ -46,7 +46,7 @@ static int pgcnt; module_param(pgcnt, int, S_IRUGO); MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)"); -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -138,7 +138,7 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf) retry: err = mtd->read(mtd, addr, len, &read, check_buf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) printk(PRINT_PREF "single bit flip occurred at EB %d " "MTD reported that it was fixed.\n", ebnum); else if (err) { @@ -213,6 +213,13 @@ static int __init tort_init(void) printk(KERN_INFO "=================================================\n"); printk(PRINT_PREF "Warning: this program is trying to wear out your " "flash, stop it if this is not wanted.\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n", ebcnt, eb, eb + ebcnt - 1, dev); diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 4be671815014..fb7f19b62d91 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -443,7 +443,7 @@ retry: if (err == UBI_IO_BITFLIPS) { scrub = 1; err = 0; - } else if (err == -EBADMSG) { + } else if (mtd_is_eccerr(err)) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) goto out_unlock; scrub = 1; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 6ba55c235873..f20b6f22f240 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -172,9 +172,9 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, retry: err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); if (err) { - const char *errstr = (err == -EBADMSG) ? " (ECC error)" : ""; + const char *errstr = mtd_is_eccerr(err) ? " (ECC error)" : ""; - if (err == -EUCLEAN) { + if (mtd_is_bitflip(err)) { /* * -EUCLEAN is reported if there was a bit-flip which * was corrected, so this is harmless. @@ -205,7 +205,7 @@ retry: * all the requested data. But some buggy drivers might do * this, so we change it to -EIO. */ - if (read != len && err == -EBADMSG) { + if (read != len && mtd_is_eccerr(err)) { ubi_assert(0); err = -EIO; } @@ -469,7 +469,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum) out: mutex_unlock(&ubi->buf_mutex); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { + if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) { /* * If a bit-flip or data integrity error was detected, the test * has not passed because it happened on a freshly erased @@ -760,7 +760,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, read_err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); if (read_err) { - if (read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG) + if (read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err)) return read_err; /* @@ -776,7 +776,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, magic = be32_to_cpu(ec_hdr->magic); if (magic != UBI_EC_HDR_MAGIC) { - if (read_err == -EBADMSG) + if (mtd_is_eccerr(read_err)) return UBI_IO_BAD_HDR_EBADMSG; /* @@ -1032,12 +1032,12 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, p = (char *)vid_hdr - ubi->vid_hdr_shift; read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); - if (read_err && read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG) + if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err)) return read_err; magic = be32_to_cpu(vid_hdr->magic); if (magic != UBI_VID_HDR_MAGIC) { - if (read_err == -EBADMSG) + if (mtd_is_eccerr(read_err)) return UBI_IO_BAD_HDR_EBADMSG; if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { @@ -1219,7 +1219,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) return -ENOMEM; err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) goto exit; crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); @@ -1306,7 +1306,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) p = (char *)vid_hdr - ubi->vid_hdr_shift; err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) goto exit; crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); @@ -1358,7 +1358,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum, } err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf1); - if (err && err != -EUCLEAN) + if (err && !mtd_is_bitflip(err)) goto out_free; for (i = 0; i < len; i++) { @@ -1422,7 +1422,7 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) } err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); - if (err && err != -EUCLEAN) { + if (err && !mtd_is_bitflip(err)) { ubi_err("error %d while reading %d bytes from PEB %d:%d, " "read %zd bytes", err, len, pnum, offset, read); goto error; diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index d39716e5b204..1a35fc5e3b40 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -410,7 +410,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, return 0; err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); - if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { + if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) { ubi_warn("mark volume %d as corrupted", vol_id); vol->corrupted = 1; } diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index ff2a65c37f69..f6a7d7ac4b98 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -81,7 +81,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id) err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1); if (err) { - if (err == -EBADMSG) + if (mtd_is_eccerr(err)) err = 1; break; } diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index a3a198f9b98d..0cb17d936b5a 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -395,7 +395,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, } err = ubi_io_read_data(ubi, buf, pnum, 0, len); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) goto out_free_buf; data_crc = be32_to_cpu(vid_hdr->data_crc); @@ -793,7 +793,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start, ubi->leb_size); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { + if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) { /* * Bit-flips or integrity errors while reading the data area. * It is difficult to say for sure what type of corruption is diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 97e093d19672..863835f4aefe 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -26,6 +26,7 @@ #include <linux/err.h> #include <linux/math64.h> #include <linux/slab.h> +#include <linux/export.h> #include "ubi.h" #ifdef CONFIG_MTD_UBI_DEBUG diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 4b50a3029b84..9ad18da1891d 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -423,7 +423,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, ubi->vtbl_size); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) + if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) /* * Scrub the PEB later. Note, -EBADMSG indicates an * uncorrectable ECC error, but we have our own CRC and diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 583f66cd5bbd..654a5e94e0e7 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -245,6 +245,8 @@ source "drivers/net/ethernet/Kconfig" source "drivers/net/fddi/Kconfig" +source "drivers/net/hippi/Kconfig" + config NET_SB1000 tristate "General Instruments Surfboard 1000" depends on PNP diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 17206da2fab7..ad284baafe87 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -1,4 +1,5 @@ #include <linux/proc_fs.h> +#include <linux/export.h> #include <net/net_namespace.h> #include <net/netns/generic.h> #include "bonding.h" diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 5d7872ecff52..7f3091e7eb42 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -25,6 +25,7 @@ #include <linux/if_ether.h> #include <linux/ip.h> #include <linux/prefetch.h> +#include <linux/module.h> #include "bnad.h" #include "bna.h" diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c index da5a5d9b8aff..90ff1318cc05 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c @@ -40,6 +40,7 @@ #include <net/netevent.h> #include <linux/highmem.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include "common.h" #include "regs.h" diff --git a/drivers/net/ethernet/chelsio/cxgb3/l2t.c b/drivers/net/ethernet/chelsio/cxgb3/l2t.c index 41540978a173..70fec8b1140f 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb3/l2t.c @@ -35,6 +35,7 @@ #include <linux/if_vlan.h> #include <linux/jhash.h> #include <linux/slab.h> +#include <linux/export.h> #include <net/neighbour.h> #include "common.h" #include "t3cdev.h" diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index a2d323c473f8..6ac77a62f361 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -37,6 +37,9 @@ #include <linux/if.h> #include <linux/if_vlan.h> #include <linux/jhash.h> +#include <linux/module.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> #include <net/neighbour.h> #include "cxgb4.h" #include "l2t.h" @@ -503,10 +506,6 @@ struct l2t_data *t4_init_l2t(void) return d; } -#include <linux/module.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> - static inline void *l2t_get_idx(struct seq_file *seq, loff_t pos) { struct l2t_entry *l2tab = seq->private; diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index ddc16985d0f6..140254c7cba9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -40,6 +40,7 @@ #include <linux/dma-mapping.h> #include <linux/jiffies.h> #include <linux/prefetch.h> +#include <linux/export.h> #include <net/ipv6.h> #include <net/tcp.h> #include "cxgb4.h" diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index e0aed188c57f..bf266a00c774 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -16,6 +16,7 @@ */ #include <linux/prefetch.h> +#include <linux/module.h> #include "be.h" #include "be_cmds.h" #include <asm/div64.h> diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index bdb348a5ccf6..251b635fe75a 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -22,6 +22,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/module.h> #include <net/ethoc.h> static int buffer_size = 0x8000; /* 32 KBytes */ diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index 46d690a92c0b..b5dc0273a1d1 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -17,6 +17,7 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/stddef.h> +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c index 4dd9b63273f6..20e93b08e7f3 100644 --- a/drivers/net/ethernet/intel/e1000e/param.c +++ b/drivers/net/ethernet/intel/e1000e/param.c @@ -27,6 +27,7 @@ *******************************************************************************/ #include <linux/netdevice.h> +#include <linux/module.h> #include <linux/pci.h> #include "e1000.h" diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index db95731863d7..00fcd39ad666 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -442,12 +442,14 @@ static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter, int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter) { +#ifdef CONFIG_PCI_IOV int i; for (i = 0; i < adapter->num_vfs; i++) { if (adapter->vfinfo[i].vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED) return true; } +#endif return false; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h index 4a5d8897faab..df04f1a3857c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h @@ -42,11 +42,11 @@ int ixgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting); int ixgbe_ndo_get_vf_config(struct net_device *netdev, int vf, struct ifla_vf_info *ivi); void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter); -#ifdef CONFIG_PCI_IOV void ixgbe_disable_sriov(struct ixgbe_adapter *adapter); +int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter); +#ifdef CONFIG_PCI_IOV void ixgbe_enable_sriov(struct ixgbe_adapter *adapter, const struct ixgbe_info *ii); -int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter); #endif diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c index 116cae334dad..8be20e7ea3d1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c @@ -34,6 +34,7 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/mm.h> +#include <linux/export.h> #include <linux/bitmap.h> #include <linux/dma-mapping.h> #include <linux/vmalloc.h> diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 32f947154c33..45aea9c3ae2c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -32,6 +32,7 @@ */ #include <linux/workqueue.h> +#include <linux/module.h> #include "mlx4.h" diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 23cee7b6af91..78f5a1a0b8c8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -34,6 +34,7 @@ #include <linux/sched.h> #include <linux/slab.h> +#include <linux/export.h> #include <linux/pci.h> #include <linux/errno.h> diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index bd8ef9f2fa71..499a5168892a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c @@ -35,6 +35,7 @@ */ #include <linux/hardirq.h> +#include <linux/export.h> #include <linux/gfp.h> #include <linux/mlx4/cmd.h> diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 90f2cd24faac..d901b4267537 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -39,6 +39,7 @@ #include <linux/if_vlan.h> #include <linux/vmalloc.h> #include <linux/tcp.h> +#include <linux/moduleparam.h> #include "mlx4_en.h" diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 869a2c220a7b..24ee96775996 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -33,6 +33,7 @@ #include <linux/interrupt.h> #include <linux/slab.h> +#include <linux/export.h> #include <linux/mm.h> #include <linux/dma-mapping.h> diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index abdfbacab4a6..435ca6e49734 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -33,6 +33,7 @@ */ #include <linux/mlx4/cmd.h> +#include <linux/module.h> #include <linux/cache.h> #include "fw.h" diff --git a/drivers/net/ethernet/mellanox/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c index 73c94fcdfddf..ca6feb55bd94 100644 --- a/drivers/net/ethernet/mellanox/mlx4/intf.c +++ b/drivers/net/ethernet/mellanox/mlx4/intf.c @@ -32,6 +32,7 @@ */ #include <linux/slab.h> +#include <linux/export.h> #include "mlx4.h" diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index cd1784593a3c..978688c31046 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -35,6 +35,7 @@ #include <linux/etherdevice.h> #include <linux/mlx4/cmd.h> +#include <linux/export.h> #include "mlx4.h" diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index ab639cfef78e..efa3e77355e4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -33,6 +33,7 @@ */ #include <linux/errno.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/mlx4/cmd.h> diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c index 3736163e30e9..260ed259ce9b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/pd.c +++ b/drivers/net/ethernet/mellanox/mlx4/pd.c @@ -32,6 +32,7 @@ */ #include <linux/errno.h> +#include <linux/export.h> #include <linux/io-mapping.h> #include <asm/page.h> diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index a44f080fdfe5..d942aea4927b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -32,6 +32,7 @@ #include <linux/errno.h> #include <linux/if_ether.h> +#include <linux/export.h> #include <linux/mlx4/cmd.h> diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 51c53898c35f..15f870cb2590 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -34,6 +34,7 @@ */ #include <linux/gfp.h> +#include <linux/export.h> #include <linux/mlx4/cmd.h> #include <linux/mlx4/qp.h> diff --git a/drivers/net/ethernet/mellanox/mlx4/srq.c b/drivers/net/ethernet/mellanox/mlx4/srq.c index a20b141dbb5c..9cbf3fce0145 100644 --- a/drivers/net/ethernet/mellanox/mlx4/srq.c +++ b/drivers/net/ethernet/mellanox/mlx4/srq.c @@ -32,6 +32,7 @@ */ #include <linux/mlx4/cmd.h> +#include <linux/export.h> #include <linux/gfp.h> #include "mlx4.h" diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index 671e166b5af1..a83197d757c1 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -55,6 +55,7 @@ #include <linux/firmware.h> #include <linux/net_tstamp.h> #include <linux/prefetch.h> +#include <linux/module.h> #include "vxge-main.h" #include "vxge-reg.h" diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 1e37eb98c4e2..1dca57013cb2 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -1682,6 +1682,7 @@ static void nv_get_hw_stats(struct net_device *dev) np->estats.tx_pause += readl(base + NvRegTxPause); np->estats.rx_pause += readl(base + NvRegRxPause); np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame); + np->estats.rx_errors_total += np->estats.rx_drop_frame; } if (np->driver_data & DEV_HAS_STATISTICS_V3) { @@ -1706,11 +1707,14 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) nv_get_hw_stats(dev); /* copy to net_device stats */ + dev->stats.tx_packets = np->estats.tx_packets; + dev->stats.rx_bytes = np->estats.rx_bytes; dev->stats.tx_bytes = np->estats.tx_bytes; dev->stats.tx_fifo_errors = np->estats.tx_fifo_errors; dev->stats.tx_carrier_errors = np->estats.tx_carrier_errors; dev->stats.rx_crc_errors = np->estats.rx_crc_errors; dev->stats.rx_over_errors = np->estats.rx_over_errors; + dev->stats.rx_fifo_errors = np->estats.rx_drop_frame; dev->stats.rx_errors = np->estats.rx_errors_total; dev->stats.tx_errors = np->estats.tx_errors_total; } @@ -2099,10 +2103,10 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) /* add fragments to entries count */ for (i = 0; i < fragments; i++) { - u32 size = skb_frag_size(&skb_shinfo(skb)->frags[i]); + u32 frag_size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - entries += (size >> NV_TX2_TSO_MAX_SHIFT) + - ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + entries += (frag_size >> NV_TX2_TSO_MAX_SHIFT) + + ((frag_size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); } spin_lock_irqsave(&np->lock, flags); @@ -2141,13 +2145,13 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) /* setup the fragments */ for (i = 0; i < fragments; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - u32 size = skb_frag_size(frag); + u32 frag_size = skb_frag_size(frag); offset = 0; do { prev_tx = put_tx; prev_tx_ctx = np->put_tx_ctx; - bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; np->put_tx_ctx->dma = skb_frag_dma_map( &np->pci_dev->dev, frag, offset, @@ -2159,12 +2163,12 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); offset += bcnt; - size -= bcnt; + frag_size -= bcnt; if (unlikely(put_tx++ == np->last_tx.orig)) put_tx = np->first_tx.orig; if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; - } while (size); + } while (frag_size); } /* set last fragment flag */ @@ -2213,10 +2217,10 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, /* add fragments to entries count */ for (i = 0; i < fragments; i++) { - u32 size = skb_frag_size(&skb_shinfo(skb)->frags[i]); + u32 frag_size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - entries += (size >> NV_TX2_TSO_MAX_SHIFT) + - ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + entries += (frag_size >> NV_TX2_TSO_MAX_SHIFT) + + ((frag_size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); } spin_lock_irqsave(&np->lock, flags); @@ -2257,13 +2261,13 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, /* setup the fragments */ for (i = 0; i < fragments; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - u32 size = skb_frag_size(frag); + u32 frag_size = skb_frag_size(frag); offset = 0; do { prev_tx = put_tx; prev_tx_ctx = np->put_tx_ctx; - bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; np->put_tx_ctx->dma = skb_frag_dma_map( &np->pci_dev->dev, frag, offset, @@ -2276,12 +2280,12 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); offset += bcnt; - size -= bcnt; + frag_size -= bcnt; if (unlikely(put_tx++ == np->last_tx.ex)) put_tx = np->first_tx.ex; if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; - } while (size); + } while (frag_size); } /* set last fragment flag */ @@ -2374,16 +2378,8 @@ static int nv_tx_done(struct net_device *dev, int limit) if (np->desc_ver == DESC_VER_1) { if (flags & NV_TX_LASTPACKET) { if (flags & NV_TX_ERROR) { - if (flags & NV_TX_UNDERFLOW) - dev->stats.tx_fifo_errors++; - if (flags & NV_TX_CARRIERLOST) - dev->stats.tx_carrier_errors++; if ((flags & NV_TX_RETRYERROR) && !(flags & NV_TX_RETRYCOUNT_MASK)) nv_legacybackoff_reseed(dev); - dev->stats.tx_errors++; - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += np->get_tx_ctx->skb->len; } dev_kfree_skb_any(np->get_tx_ctx->skb); np->get_tx_ctx->skb = NULL; @@ -2392,16 +2388,8 @@ static int nv_tx_done(struct net_device *dev, int limit) } else { if (flags & NV_TX2_LASTPACKET) { if (flags & NV_TX2_ERROR) { - if (flags & NV_TX2_UNDERFLOW) - dev->stats.tx_fifo_errors++; - if (flags & NV_TX2_CARRIERLOST) - dev->stats.tx_carrier_errors++; if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) nv_legacybackoff_reseed(dev); - dev->stats.tx_errors++; - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += np->get_tx_ctx->skb->len; } dev_kfree_skb_any(np->get_tx_ctx->skb); np->get_tx_ctx->skb = NULL; @@ -2434,9 +2422,7 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit) nv_unmap_txskb(np, np->get_tx_ctx); if (flags & NV_TX2_LASTPACKET) { - if (!(flags & NV_TX2_ERROR)) - dev->stats.tx_packets++; - else { + if (flags & NV_TX2_ERROR) { if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) { if (np->driver_data & DEV_HAS_GEAR_MODE) nv_gear_backoff_reseed(dev); @@ -2636,7 +2622,6 @@ static int nv_rx_process(struct net_device *dev, int limit) if ((flags & NV_RX_ERROR_MASK) == NV_RX_ERROR4) { len = nv_getlen(dev, skb->data, len); if (len < 0) { - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2650,11 +2635,6 @@ static int nv_rx_process(struct net_device *dev, int limit) else { if (flags & NV_RX_MISSEDFRAME) dev->stats.rx_missed_errors++; - if (flags & NV_RX_CRCERR) - dev->stats.rx_crc_errors++; - if (flags & NV_RX_OVERFLOW) - dev->stats.rx_over_errors++; - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2670,7 +2650,6 @@ static int nv_rx_process(struct net_device *dev, int limit) if ((flags & NV_RX2_ERROR_MASK) == NV_RX2_ERROR4) { len = nv_getlen(dev, skb->data, len); if (len < 0) { - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2682,11 +2661,6 @@ static int nv_rx_process(struct net_device *dev, int limit) } /* the rest are hard errors */ else { - if (flags & NV_RX2_CRCERR) - dev->stats.rx_crc_errors++; - if (flags & NV_RX2_OVERFLOW) - dev->stats.rx_over_errors++; - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2704,7 +2678,6 @@ static int nv_rx_process(struct net_device *dev, int limit) skb->protocol = eth_type_trans(skb, dev); napi_gro_receive(&np->napi, skb); dev->stats.rx_packets++; - dev->stats.rx_bytes += len; next_pkt: if (unlikely(np->get_rx.orig++ == np->last_rx.orig)) np->get_rx.orig = np->first_rx.orig; @@ -2787,9 +2760,7 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit) __vlan_hwaccel_put_tag(skb, vid); } napi_gro_receive(&np->napi, skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += len; } else { dev_kfree_skb(skb); } @@ -2962,11 +2933,11 @@ static void nv_set_multicast(struct net_device *dev) struct netdev_hw_addr *ha; netdev_for_each_mc_addr(ha, dev) { - unsigned char *addr = ha->addr; + unsigned char *hw_addr = ha->addr; u32 a, b; - a = le32_to_cpu(*(__le32 *) addr); - b = le16_to_cpu(*(__le16 *) (&addr[4])); + a = le32_to_cpu(*(__le32 *) hw_addr); + b = le16_to_cpu(*(__le16 *) (&hw_addr[4])); alwaysOn[0] &= a; alwaysOff[0] &= ~a; alwaysOn[1] &= b; @@ -3398,7 +3369,8 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) for (i = 0;; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL; - writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus); + writel(events, base + NvRegMSIXIrqStatus); + netdev_dbg(dev, "tx irq events: %08x\n", events); if (!(events & np->irqmask)) break; @@ -3509,7 +3481,8 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) for (i = 0;; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL; - writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); + writel(events, base + NvRegMSIXIrqStatus); + netdev_dbg(dev, "rx irq events: %08x\n", events); if (!(events & np->irqmask)) break; @@ -3553,7 +3526,8 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) for (i = 0;; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER; - writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus); + writel(events, base + NvRegMSIXIrqStatus); + netdev_dbg(dev, "irq events: %08x\n", events); if (!(events & np->irqmask)) break; @@ -3617,10 +3591,10 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data) if (!(np->msi_flags & NV_MSI_X_ENABLED)) { events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; - writel(NVREG_IRQ_TIMER, base + NvRegIrqStatus); + writel(events & NVREG_IRQ_TIMER, base + NvRegIrqStatus); } else { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; - writel(NVREG_IRQ_TIMER, base + NvRegMSIXIrqStatus); + writel(events & NVREG_IRQ_TIMER, base + NvRegMSIXIrqStatus); } pci_push(base); if (!(events & NVREG_IRQ_TIMER)) @@ -4566,7 +4540,7 @@ static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *e struct fe_priv *np = netdev_priv(dev); /* update stats */ - nv_do_stats_poll((unsigned long)dev); + nv_get_hw_stats(dev); memcpy(buffer, &np->estats, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64)); } diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c index bc1d946b7971..212f43b308a3 100644 --- a/drivers/net/ethernet/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/octeon/octeon_mgmt.c @@ -9,6 +9,7 @@ #include <linux/capability.h> #include <linux/dma-mapping.h> #include <linux/init.h> +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/netdevice.h> diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index b89f3a684aec..48406ca382f1 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -20,6 +20,7 @@ #include "pch_gbe.h" #include "pch_gbe_api.h" +#include <linux/module.h> #define DRV_VERSION "1.00" const char pch_driver_version[] = DRV_VERSION; diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c index 5b5d90a47e29..9c075ea2682e 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c @@ -18,6 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/module.h> /* for __MODULE_STRING */ #include "pch_gbe.h" #define OPTION_UNSET -1 diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 92b45f08858f..6f06aa10f0d7 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -1292,7 +1292,7 @@ static void __rtl8169_check_link_status(struct net_device *dev, netif_carrier_off(dev); netif_info(tp, ifdown, dev, "link down\n"); if (pm) - pm_schedule_suspend(&tp->pci_dev->dev, 100); + pm_schedule_suspend(&tp->pci_dev->dev, 5000); } spin_unlock_irqrestore(&tp->lock, flags); } diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index adbda182f159..752d521c09b1 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -15,6 +15,7 @@ #include <linux/tcp.h> #include <linux/udp.h> #include <linux/prefetch.h> +#include <linux/moduleparam.h> #include <net/ip.h> #include <net/checksum.h> #include "net_driver.h" diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c index 4f15680849ff..edb24b0e337b 100644 --- a/drivers/net/ethernet/smsc/smsc9420.c +++ b/drivers/net/ethernet/smsc/smsc9420.c @@ -28,6 +28,7 @@ #include <linux/dma-mapping.h> #include <linux/crc32.h> #include <linux/slab.h> +#include <linux/module.h> #include <asm/unaligned.h> #include "smsc9420.h" diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index ac6f190743dd..22745d7bf530 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -29,15 +29,6 @@ config STMMAC_DA By default, the DMA arbitration scheme is based on Round-robin (rx:tx priority is 1:1). -config STMMAC_DUAL_MAC - bool "STMMAC: dual mac support (EXPERIMENTAL)" - default n - depends on EXPERIMENTAL && STMMAC_ETH && !STMMAC_TIMER - ---help--- - Some ST SoCs (for example the stx7141 and stx7200c2) have two - Ethernet Controllers. This option turns on the second Ethernet - device on this kind of platforms. - config STMMAC_TIMER bool "STMMAC Timer optimisation" default n diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index c517dac02ae1..cf14ab9db576 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -2637,7 +2637,7 @@ static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int i sbus_dp = op->dev.parent->of_node; /* We can match PCI devices too, do not accept those here. */ - if (strcmp(sbus_dp->name, "sbus")) + if (strcmp(sbus_dp->name, "sbus") && strcmp(sbus_dp->name, "sbi")) return err; if (is_qfe) { diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c index ddb33cfd3543..7bf1e2015784 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c @@ -1674,6 +1674,9 @@ static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) int result; pr_debug("%s: called\n", __func__); + + udbg_shutdown_ps3gelic(); + result = ps3_open_hv_device(dev); if (result) { diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h index d3fadfbc3bcc..a93df6ac1909 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_net.h +++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.h @@ -359,6 +359,12 @@ static inline void *port_priv(struct gelic_port *port) return port->priv; } +#ifdef CONFIG_PPC_EARLY_DEBUG_PS3GELIC +extern void udbg_shutdown_ps3gelic(void); +#else +static inline void udbg_shutdown_ps3gelic(void) {} +#endif + extern int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask); /* shared netdev ops */ extern void gelic_card_up(struct gelic_card *card); diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index caf3659e173c..2681b53820ee 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -114,6 +114,7 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value) return; temac_iow(lp, XTE_LSW0_OFFSET, value); temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg); + temac_indirect_busywait(lp); } /** @@ -203,6 +204,9 @@ static void temac_dma_bd_release(struct net_device *ndev) struct temac_local *lp = netdev_priv(ndev); int i; + /* Reset Local Link (DMA) */ + lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST); + for (i = 0; i < RX_BD_NUM; i++) { if (!lp->rx_skb[i]) break; @@ -860,6 +864,8 @@ static int temac_open(struct net_device *ndev) phy_start(lp->phy_dev); } + temac_device_reset(ndev); + rc = request_irq(lp->tx_irq, ll_temac_tx_irq, 0, ndev->name, ndev); if (rc) goto err_tx_irq; @@ -867,7 +873,6 @@ static int temac_open(struct net_device *ndev) if (rc) goto err_rx_irq; - temac_device_reset(ndev); return 0; err_rx_irq: diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index ec96d910e9a3..f45c85a84261 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -35,6 +35,7 @@ #include <linux/platform_device.h> #include <linux/ptp_classify.h> #include <linux/slab.h> +#include <linux/module.h> #include <mach/ixp46x_ts.h> #include <mach/npe.h> #include <mach/qmgr.h> diff --git a/drivers/net/hippi/Kconfig b/drivers/net/hippi/Kconfig index 7393eb732ee6..95eb34fdbba7 100644 --- a/drivers/net/hippi/Kconfig +++ b/drivers/net/hippi/Kconfig @@ -36,4 +36,4 @@ config ROADRUNNER_LARGE_RINGS kernel code or by user space programs. Say Y here only if you have the memory. -endif /* HIPPI */ +endif # HIPPI diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index a4eae750a414..f414ffb5b728 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -14,6 +14,7 @@ * */ #include <linux/phy.h> +#include <linux/module.h> #define RTL821x_PHYSR 0x11 #define RTL821x_PHYSR_DUPLEX 0x2000 diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c index 1e7221951056..d43db32f9478 100644 --- a/drivers/net/usb/lg-vl600.c +++ b/drivers/net/usb/lg-vl600.c @@ -27,6 +27,7 @@ #include <linux/if_ether.h> #include <linux/if_arp.h> #include <linux/inetdevice.h> +#include <linux/module.h> /* * The device has a CDC ACM port for modem control (it claims to be diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 22a7cf951e72..a5b9b12ef268 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -51,6 +51,7 @@ #define USB_VENDOR_ID_SMSC (0x0424) #define USB_PRODUCT_ID_LAN7500 (0x7500) #define USB_PRODUCT_ID_LAN7505 (0x7505) +#define RXW_PADDING 2 #define check_warn(ret, fmt, args...) \ ({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); }) @@ -1088,13 +1089,13 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) memcpy(&rx_cmd_b, skb->data, sizeof(rx_cmd_b)); le32_to_cpus(&rx_cmd_b); - skb_pull(skb, 4 + NET_IP_ALIGN); + skb_pull(skb, 4 + RXW_PADDING); packet = skb->data; /* get the packet length */ - size = (rx_cmd_a & RX_CMD_A_LEN) - NET_IP_ALIGN; - align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4; + size = (rx_cmd_a & RX_CMD_A_LEN) - RXW_PADDING; + align_count = (4 - ((size + RXW_PADDING) % 4)) % 4; if (unlikely(rx_cmd_a & RX_CMD_A_RED)) { netif_dbg(dev, rx_err, dev->net, diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 7d6082160bcc..fae0fbd8bc88 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1057,7 +1057,8 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, unsigned long flags; int retval; - skb_tx_timestamp(skb); + if (skb) + skb_tx_timestamp(skb); // some devices want funky USB-level framing, for // win32 driver (usually) and/or hardware quirks diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 5b23767ea817..ef883e97cee0 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -17,6 +17,7 @@ #include <net/dst.h> #include <net/xfrm.h> #include <linux/veth.h> +#include <linux/module.h> #define DRV_NAME "veth" #define DRV_VERSION "1.0" diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index b771ebac0f01..d96bfb1ac20b 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -24,6 +24,7 @@ * */ +#include <linux/module.h> #include <net/ip6_checksum.h> #include "vmxnet3_int.h" diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index 727d728649b7..2fea02b35b2d 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -78,6 +78,8 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/wimax/i2400m.h> +#include <linux/export.h> +#include <linux/moduleparam.h> #define D_SUBMODULE control diff --git a/drivers/net/wimax/i2400m/debugfs.c b/drivers/net/wimax/i2400m/debugfs.c index 9c70b5fa3f51..129ba36bd04d 100644 --- a/drivers/net/wimax/i2400m/debugfs.c +++ b/drivers/net/wimax/i2400m/debugfs.c @@ -26,6 +26,7 @@ #include <linux/etherdevice.h> #include <linux/spinlock.h> #include <linux/device.h> +#include <linux/export.h> #include "i2400m.h" diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 85dadd5bf4be..7cbd7d231e11 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -158,6 +158,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/export.h> #include "i2400m.h" diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 2edd8fe1c1f3..64a110604ad3 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -76,6 +76,7 @@ #include <linux/slab.h> #include <linux/netdevice.h> #include <linux/ethtool.h> +#include <linux/export.h> #include "i2400m.h" diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index 2f94a872101f..37becfcc98f2 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -149,6 +149,8 @@ #include <linux/if_arp.h> #include <linux/netdevice.h> #include <linux/workqueue.h> +#include <linux/export.h> +#include <linux/moduleparam.h> #include "i2400m.h" diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index be428cae28d8..21a9edd6e75d 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -55,6 +55,7 @@ #include <linux/mmc/sdio_func.h> #include "i2400m-sdio.h" #include <linux/wimax/i2400m.h> +#include <linux/module.h> #define D_SUBMODULE main #include "sdio-debug-levels.h" diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 4b30ed11d785..4b9ecb20deec 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -245,6 +245,7 @@ */ #include <linux/netdevice.h> #include <linux/slab.h> +#include <linux/export.h> #include "i2400m.h" diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 9a644d052f1e..2c1b8b687646 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -67,6 +67,7 @@ #include <linux/wimax/i2400m.h> #include <linux/debugfs.h> #include <linux/slab.h> +#include <linux/module.h> #define D_SUBMODULE usb diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 3b752d9fb3cd..f5ce5623da99 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -25,6 +25,7 @@ #include <linux/delay.h> #include <linux/crc32.h> #include <linux/eeprom_93cx6.h> +#include <linux/module.h> #include <net/mac80211.h> #include "adm8211.h" diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index fce8c904eea9..8c5ce8b0c734 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -57,8 +57,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. */ +#include <linux/export.h> +#include <linux/moduleparam.h> -#include <linux/module.h> #include <linux/seq_file.h> #include <linux/list.h> #include "debug.h" diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index c1dff2ced044..dfa48eb7d953 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -18,6 +18,7 @@ #include <linux/pci.h> #include <linux/pci-aspm.h> #include <linux/etherdevice.h> +#include <linux/module.h> #include "../ath.h" #include "ath5k.h" #include "debug.h" diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 3aff36bad5d3..f517eb8f7b44 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/moduleparam.h> + #include "core.h" #include "cfg80211.h" #include "debug.h" diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index ba3f23d71150..7879b5314285 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -19,6 +19,7 @@ #include <linux/circ_buf.h> #include <linux/fs.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include "debug.h" #include "target.h" diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index f1dc311ee0c7..066d4f88807f 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/module.h> #include <linux/mmc/card.h> #include <linux/mmc/mmc.h> #include <linux/mmc/host.h> diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 85a54cd2b083..5e47ca6d16a8 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -19,6 +19,7 @@ #include <linux/nl80211.h> #include <linux/platform_device.h> #include <linux/ath9k_platform.h> +#include <linux/module.h> #include "ath9k.h" static const struct platform_device_id ath9k_platform_id_table[] = { diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 2776c3c1f506..a639b94f7643 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -15,6 +15,7 @@ */ #include <linux/kernel.h> +#include <linux/export.h> #include "hw.h" #include "hw-ops.h" diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 626d547d2f06..11f192a1ceb7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/moduleparam.h> #include "hw.h" #include "ar5008_initvals.h" #include "ar9001_initvals.h" diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index f7d8e516a2a9..b5920168606d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -15,6 +15,7 @@ */ #include "hw.h" +#include <linux/export.h> #define AR_BufLen 0x00000fff diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index b363cc06cfd9..ccde784a842f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -13,6 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include "hw.h" #include "ar9003_mac.h" diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 0c462c904cbe..a4450cba0653 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include "hw.h" #include "ar9003_phy.h" diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index fe96997921d3..2330e7ede199 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include "hw.h" #include "ar9003_phy.h" diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 6635c377dc00..012263968d64 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include "hw.h" enum ath_bt_mode { diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index ebaf304f464b..99538810a312 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -16,6 +16,7 @@ #include "hw.h" #include "hw-ops.h" +#include <linux/export.h> /* Common calibration code */ diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 327aa28f6030..2741203e803f 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <asm/unaligned.h> #include "ath9k.h" diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b479160dc262..2f91acccb7db 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -16,6 +16,7 @@ #include <linux/io.h> #include <linux/slab.h> +#include <linux/module.h> #include <asm/unaligned.h> #include "hw.h" diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index af1b32549531..d4c909f8e474 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -17,6 +17,7 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/ath9k_platform.h> +#include <linux/module.h> #include "ath9k.h" diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 6a8fdf33a527..ecdb6fd29079 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -16,6 +16,7 @@ #include "hw.h" #include "hw-ops.h" +#include <linux/export.h> static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, struct ath9k_tx_queue_info *qi) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index edb0b4b3da3a..2dcdf63cb390 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -18,6 +18,7 @@ #include <linux/pci.h> #include <linux/pci-aspm.h> #include <linux/ath9k_platform.h> +#include <linux/module.h> #include "ath9k.h" static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 8448281dd069..888abc2be3a5 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -16,6 +16,7 @@ */ #include <linux/slab.h> +#include <linux/export.h> #include "ath9k.h" diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index f4cae1cccbff..cba9d0435dc4 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/firmware.h> #include <linux/crc32.h> +#include <linux/module.h> #include "carl9170.h" #include "fwcmd.h" #include "version.h" diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c index 5367b1086e09..508eccf5d982 100644 --- a/drivers/net/wireless/ath/debug.c +++ b/drivers/net/wireless/ath/debug.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include "ath.h" const char *ath_opmode_to_string(enum nl80211_iftype opmode) diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c index 3f508e59f146..19befb331073 100644 --- a/drivers/net/wireless/ath/hw.c +++ b/drivers/net/wireless/ath/hw.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include <asm/unaligned.h> #include "ath.h" diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 17b0efd86f9a..4cf7c5eb4813 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -15,6 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include <asm/unaligned.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index f1be57f0f5bb..65ecb5bab25a 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -15,6 +15,7 @@ */ #include <linux/kernel.h> +#include <linux/export.h> #include <net/cfg80211.h> #include <net/mac80211.h> #include "regd.h" diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 7cf4125a1624..5634d9a9965b 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -34,7 +34,7 @@ #include <linux/delay.h> #include <linux/init.h> -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <linux/firmware.h> diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 12b6b4067a39..714cad649c45 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -25,6 +25,7 @@ #include <linux/ssb/ssb.h> #include <linux/slab.h> +#include <linux/module.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index a3b72cd72c66..20f02437af8c 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -31,7 +31,7 @@ #include <linux/delay.h> #include <linux/init.h> -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <linux/firmware.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index bff9dcd6fadc..89ff94da556a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -17,6 +17,7 @@ #include <linux/types.h> #include <linux/netdevice.h> +#include <linux/export.h> #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/sched.h> diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index ac8d02bd34f2..0d8a9cdf897a 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -21,6 +21,7 @@ #include <linux/sched.h> #include <linux/firmware.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <net/mac80211.h> #include <defs.h> #include "nicpci.h" diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index e0b3e8d406b3..df7050abe717 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -1,5 +1,6 @@ #include <linux/etherdevice.h> #include <linux/slab.h> +#include <linux/export.h> #include <net/lib80211.h> #include <linux/if_arp.h> diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index c34a3b7f1292..344a981a052e 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -1,4 +1,5 @@ #include <linux/slab.h> +#include <linux/export.h> #include "hostap_80211.h" #include "hostap_common.h" diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 3d05dc15c6b8..e1f410277242 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -21,6 +21,8 @@ #include <linux/random.h> #include <linux/if_arp.h> #include <linux/slab.h> +#include <linux/export.h> +#include <linux/moduleparam.h> #include "hostap_wlan.h" #include "hostap.h" diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index d737091cf6ac..47932b28aac1 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -3,6 +3,7 @@ #include <linux/if_arp.h> #include <linux/sched.h> #include <linux/slab.h> +#include <linux/export.h> #include "hostap_wlan.h" #include "hostap.h" #include "hostap_ap.h" diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 12de46407c71..045a93645a3d 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -5,6 +5,7 @@ #include <linux/sched.h> #include <linux/ethtool.h> #include <linux/if_arp.h> +#include <linux/module.h> #include <net/lib80211.h> #include "hostap_wlan.h" diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index 005ff25a405f..75ef8f04aabe 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -2,6 +2,7 @@ #include <linux/types.h> #include <linux/proc_fs.h> +#include <linux/export.h> #include <net/lib80211.h> #include "hostap_wlan.h" diff --git a/drivers/net/wireless/iwlegacy/iwl-debugfs.c b/drivers/net/wireless/iwlegacy/iwl-debugfs.c index 996996a71657..1407dca70def 100644 --- a/drivers/net/wireless/iwlegacy/iwl-debugfs.c +++ b/drivers/net/wireless/iwlegacy/iwl-debugfs.c @@ -26,6 +26,7 @@ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #include <linux/ieee80211.h> +#include <linux/export.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlegacy/iwl-rx.c b/drivers/net/wireless/iwlegacy/iwl-rx.c index 9b5d0abe8be9..f4d21ec22497 100644 --- a/drivers/net/wireless/iwlegacy/iwl-rx.c +++ b/drivers/net/wireless/iwlegacy/iwl-rx.c @@ -29,6 +29,7 @@ #include <linux/etherdevice.h> #include <linux/slab.h> +#include <linux/export.h> #include <net/mac80211.h> #include <asm/unaligned.h> #include "iwl-eeprom.h" diff --git a/drivers/net/wireless/iwlegacy/iwl-scan.c b/drivers/net/wireless/iwlegacy/iwl-scan.c index a6b5222fc59e..521b73b527d3 100644 --- a/drivers/net/wireless/iwlegacy/iwl-scan.c +++ b/drivers/net/wireless/iwlegacy/iwl-scan.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/etherdevice.h> +#include <linux/export.h> #include <net/mac80211.h> #include "iwl-eeprom.h" diff --git a/drivers/net/wireless/iwlegacy/iwl-sta.c b/drivers/net/wireless/iwlegacy/iwl-sta.c index 66f0fb2bbe00..f10df3e2813a 100644 --- a/drivers/net/wireless/iwlegacy/iwl-sta.c +++ b/drivers/net/wireless/iwlegacy/iwl-sta.c @@ -31,6 +31,7 @@ #include <linux/etherdevice.h> #include <linux/sched.h> #include <linux/lockdep.h> +#include <linux/export.h> #include "iwl-dev.h" #include "iwl-core.h" diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c index ef9e268bf8a0..c0dfb1a4e968 100644 --- a/drivers/net/wireless/iwlegacy/iwl-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-tx.c @@ -30,6 +30,7 @@ #include <linux/etherdevice.h> #include <linux/sched.h> #include <linux/slab.h> +#include <linux/export.h> #include <net/mac80211.h> #include "iwl-eeprom.h" #include "iwl-dev.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index 19cc6a81da57..1800029911ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -60,6 +60,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +#include <linux/module.h> #include <linux/pci.h> #include <linux/pci-aspm.h> diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 50dee6a0a5ca..bd75078c454b 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -42,6 +42,7 @@ #include <linux/ieee80211.h> #include <linux/sched.h> #include <linux/slab.h> +#include <linux/moduleparam.h> #include "iwm.h" #include "bus.h" diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c index 0a0cc9667cd6..87eef5773a02 100644 --- a/drivers/net/wireless/iwmc3200wifi/debugfs.c +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c @@ -25,6 +25,7 @@ #include <linux/kernel.h> #include <linux/bitops.h> #include <linux/debugfs.h> +#include <linux/export.h> #include "iwm.h" #include "bus.h" diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 362002735b12..98a179f98ea1 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -42,6 +42,7 @@ #include <linux/ieee80211.h> #include <linux/wireless.h> #include <linux/slab.h> +#include <linux/moduleparam.h> #include "iwm.h" #include "debug.h" diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index 56383e7be835..764b40dd24ad 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -63,6 +63,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/netdevice.h> #include <linux/debugfs.h> diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index e08ab1de3d9d..d798bcc0d83a 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -8,6 +8,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/if_arp.h> +#include <linux/export.h> #include "decl.h" #include "cfg.h" diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 1af182778844..d8d8f0d0899f 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -5,6 +5,7 @@ #include <linux/mm.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/export.h> #include "decl.h" #include "cmd.h" diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index c962e21762dc..9804ebc892d4 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -29,7 +29,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/firmware.h> #include <linux/netdevice.h> diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 622ae6de0d8b..11b69b300dc0 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -21,7 +21,7 @@ #include <linux/hardirq.h> #include <linux/interrupt.h> -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/firmware.h> #include <linux/jiffies.h> #include <linux/list.h> diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 8147f1e2a0b0..db879c364ebf 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -5,7 +5,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/delay.h> -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/firmware.h> #include <linux/netdevice.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 39a6a7a40244..957681dede17 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -6,7 +6,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/hardirq.h> diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 62e10eeadd7e..c7366b07b568 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -8,6 +8,7 @@ #include <linux/hardirq.h> #include <linux/slab.h> #include <linux/types.h> +#include <linux/export.h> #include <net/cfg80211.h> #include "defs.h" diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 8f127520d786..c025f9c18282 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -5,6 +5,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/sched.h> +#include <linux/export.h> #include <net/cfg80211.h> #include "host.h" diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c index 13557fe0bf95..909ac3685010 100644 --- a/drivers/net/wireless/libertas_tf/cmd.c +++ b/drivers/net/wireless/libertas_tf/cmd.c @@ -11,6 +11,7 @@ #include <linux/hardirq.h> #include <linux/slab.h> +#include <linux/export.h> #include "libertas_tf.h" diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c index ba7d96584cb6..68202e63873a 100644 --- a/drivers/net/wireless/libertas_tf/if_usb.c +++ b/drivers/net/wireless/libertas_tf/if_usb.c @@ -15,7 +15,7 @@ #include "if_usb.h" #include <linux/delay.h> -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/firmware.h> #include <linux/netdevice.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index acc461aa385e..ceb51b6e6702 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <linux/etherdevice.h> +#include <linux/module.h> #include "libertas_tf.h" #define DRIVER_RELEASE_VERSION "004.p0" diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 68455a2307cb..523ad55a2885 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -26,6 +26,7 @@ #include <linux/rtnetlink.h> #include <linux/etherdevice.h> #include <linux/debugfs.h> +#include <linux/module.h> #include <net/genetlink.h> #include "mac80211_hwsim.h" diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c index 527cf5333db5..4df8cf64b56c 100644 --- a/drivers/net/wireless/orinoco/fw.c +++ b/drivers/net/wireless/orinoco/fw.c @@ -6,6 +6,7 @@ #include <linux/slab.h> #include <linux/firmware.h> #include <linux/device.h> +#include <linux/module.h> #include "hermes.h" #include "hermes_dld.h" diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 8b6f363b3f7d..fa8ce5104781 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -24,6 +24,7 @@ #include <net/mac80211.h> #include <linux/crc-ccitt.h> +#include <linux/export.h> #include "p54.h" #include "eeprom.h" diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 53a3408931be..18e82b31afa6 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -20,6 +20,7 @@ #include <linux/slab.h> #include <linux/firmware.h> #include <linux/etherdevice.h> +#include <linux/export.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index ad9ae04d07aa..db4d9a02f264 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -20,6 +20,7 @@ #include <linux/slab.h> #include <linux/firmware.h> #include <linux/etherdevice.h> +#include <linux/module.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 1b753173680f..b1f51a215792 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -20,6 +20,7 @@ #include <linux/etherdevice.h> #include <linux/delay.h> #include <linux/completion.h> +#include <linux/module.h> #include <net/mac80211.h> #include "p54.h" diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index a8f3bc740dfa..9b6096866427 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -20,6 +20,7 @@ #include <linux/etherdevice.h> #include <linux/delay.h> #include <linux/crc32.h> +#include <linux/module.h> #include <net/mac80211.h> #include "p54.h" diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index f485784a60ae..6ed9c323e3cb 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -16,6 +16,7 @@ * published by the Free Software Foundation. */ +#include <linux/export.h> #include <linux/init.h> #include <linux/firmware.h> #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 0082015ff664..2f14a5fb0cbb 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/eeprom_93cx6.h> +#include <linux/module.h> #include <net/mac80211.h> #include "rtl8180.h" diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index 24873b55b55c..4a78f9e39dfa 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -26,6 +26,7 @@ #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/eeprom_93cx6.h> +#include <linux/module.h> #include <net/mac80211.h> #include "rtl8187.h" diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index d4fdd2a5a739..b4ce93436d2e 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/ip.h> +#include <linux/module.h> #include "wifi.h" #include "rc.h" #include "base.h" diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c index 7babb6acd957..dc36d7461caa 100644 --- a/drivers/net/wireless/rtlwifi/cam.c +++ b/drivers/net/wireless/rtlwifi/cam.c @@ -29,6 +29,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/export.h> #include "wifi.h" #include "cam.h" diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 3fc21f60bb04..ed1058b71587 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -27,6 +27,7 @@ * *****************************************************************************/ +#include <linux/export.h> #include "wifi.h" #include "efuse.h" diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 177a8e669241..eb61061821e4 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -27,6 +27,7 @@ * *****************************************************************************/ +#include <linux/export.h> #include "core.h" #include "wifi.h" #include "pci.h" diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index a693feffbe72..db5262844543 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -27,6 +27,7 @@ * *****************************************************************************/ +#include <linux/export.h> #include "wifi.h" #include "base.h" #include "ps.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index a00774e7090d..72a98cab6f69 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -27,6 +27,7 @@ * *****************************************************************************/ +#include <linux/export.h> #include "dm_common.h" #include "phy_common.h" #include "../pci.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 49a064bdbce6..950c65a15b8a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/firmware.h> +#include <linux/export.h> #include "../wifi.h" #include "../pci.h" #include "../base.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/main.c b/drivers/net/wireless/rtlwifi/rtl8192c/main.c index 2f624fc27499..605ff191aeb7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/main.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/main.c @@ -27,6 +27,7 @@ * *****************************************************************************/ +#include <linux/module.h> #include "../wifi.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index 3b11642d3f7d..1f07558debf2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -27,6 +27,7 @@ * *****************************************************************************/ +#include <linux/export.h> #include "../wifi.h" #include "../rtl8192ce/reg.h" #include "../rtl8192ce/def.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index a48404cc2b96..f2aa33dc4d78 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -28,6 +28,7 @@ *****************************************************************************/ #include <linux/vmalloc.h> +#include <linux/module.h> #include "../wifi.h" #include "../core.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index feed1ed8d9b6..c244f2f1b83f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -42,6 +42,7 @@ #include "led.h" #include "hw.h" #include <linux/vmalloc.h> +#include <linux/module.h> MODULE_AUTHOR("Georgia <georgia@realtek.com>"); MODULE_AUTHOR("Ziv Huang <ziv_huang@realtek.com>"); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c index 691f80092185..149493f4c25c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/vmalloc.h> +#include <linux/module.h> #include "../wifi.h" #include "../core.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index 3ec9a0d41baf..92f49d522c56 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/vmalloc.h> +#include <linux/module.h> #include "../wifi.h" #include "../core.h" diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index b42c2e2b2055..54cb8a60514d 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -28,6 +28,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/usb.h> +#include <linux/export.h> #include "core.h" #include "wifi.h" #include "usb.h" diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index d4e628db76b0..681337914976 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/wl12xx.h> +#include <linux/export.h> #include "acx.h" #include "reg.h" diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index cf0d69dd7be5..785bdbe38f2a 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -28,6 +28,7 @@ #include <linux/skbuff.h> #include <linux/usb.h> #include <linux/workqueue.h> +#include <linux/module.h> #include <net/mac80211.h> #include <asm/unaligned.h> diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 161f207786a4..94b79c3338c4 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -58,10 +58,6 @@ struct xenvif { u8 fe_dev_addr[6]; /* Physical parameters of the comms window. */ - grant_handle_t tx_shmem_handle; - grant_ref_t tx_shmem_ref; - grant_handle_t rx_shmem_handle; - grant_ref_t rx_shmem_ref; unsigned int irq; /* List of frontends to notify after a batch of frames sent. */ @@ -70,8 +66,6 @@ struct xenvif { /* The shared rings and indexes. */ struct xen_netif_tx_back_ring tx; struct xen_netif_rx_back_ring rx; - struct vm_struct *tx_comms_area; - struct vm_struct *rx_comms_area; /* Frontend feature information. */ u8 can_sg:1; @@ -106,6 +100,11 @@ struct xenvif { wait_queue_head_t waiting_to_free; }; +static inline struct xenbus_device *xenvif_to_xenbus_device(struct xenvif *vif) +{ + return to_xenbus_device(vif->dev->dev.parent); +} + #define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE) #define XEN_NETIF_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index d5508957200e..0cb594c86090 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1589,88 +1589,42 @@ static int xen_netbk_kthread(void *data) void xen_netbk_unmap_frontend_rings(struct xenvif *vif) { - struct gnttab_unmap_grant_ref op; - - if (vif->tx.sring) { - gnttab_set_unmap_op(&op, (unsigned long)vif->tx_comms_area->addr, - GNTMAP_host_map, vif->tx_shmem_handle); - - if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) - BUG(); - } - - if (vif->rx.sring) { - gnttab_set_unmap_op(&op, (unsigned long)vif->rx_comms_area->addr, - GNTMAP_host_map, vif->rx_shmem_handle); - - if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) - BUG(); - } - if (vif->rx_comms_area) - free_vm_area(vif->rx_comms_area); - if (vif->tx_comms_area) - free_vm_area(vif->tx_comms_area); + if (vif->tx.sring) + xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif), + vif->tx.sring); + if (vif->rx.sring) + xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif), + vif->rx.sring); } int xen_netbk_map_frontend_rings(struct xenvif *vif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref) { - struct gnttab_map_grant_ref op; + void *addr; struct xen_netif_tx_sring *txs; struct xen_netif_rx_sring *rxs; int err = -ENOMEM; - vif->tx_comms_area = alloc_vm_area(PAGE_SIZE); - if (vif->tx_comms_area == NULL) + err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif), + tx_ring_ref, &addr); + if (err) goto err; - vif->rx_comms_area = alloc_vm_area(PAGE_SIZE); - if (vif->rx_comms_area == NULL) - goto err; - - gnttab_set_map_op(&op, (unsigned long)vif->tx_comms_area->addr, - GNTMAP_host_map, tx_ring_ref, vif->domid); - - if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) - BUG(); - - if (op.status) { - netdev_warn(vif->dev, - "failed to map tx ring. err=%d status=%d\n", - err, op.status); - err = op.status; - goto err; - } - - vif->tx_shmem_ref = tx_ring_ref; - vif->tx_shmem_handle = op.handle; - - txs = (struct xen_netif_tx_sring *)vif->tx_comms_area->addr; + txs = (struct xen_netif_tx_sring *)addr; BACK_RING_INIT(&vif->tx, txs, PAGE_SIZE); - gnttab_set_map_op(&op, (unsigned long)vif->rx_comms_area->addr, - GNTMAP_host_map, rx_ring_ref, vif->domid); - - if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) - BUG(); - - if (op.status) { - netdev_warn(vif->dev, - "failed to map rx ring. err=%d status=%d\n", - err, op.status); - err = op.status; + err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif), + rx_ring_ref, &addr); + if (err) goto err; - } - - vif->rx_shmem_ref = rx_ring_ref; - vif->rx_shmem_handle = op.handle; - vif->rx_req_cons_peek = 0; - rxs = (struct xen_netif_rx_sring *)vif->rx_comms_area->addr; + rxs = (struct xen_netif_rx_sring *)addr; BACK_RING_INIT(&vif->rx, rxs, PAGE_SIZE); + vif->rx_req_cons_peek = 0; + return 0; err: diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index 5b0f1ff80361..06c3642e5bdb 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c @@ -27,6 +27,7 @@ * */ #include <linux/platform_device.h> +#include <linux/module.h> #include <linux/nfc.h> #include <net/nfc/nci.h> #include <net/nfc/nci_core.h> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index aeec35bc3789..fd85fa298e0f 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -681,9 +681,14 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, if (p != NULL && l > 0) strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else + * managed to set the command line, unless CONFIG_CMDLINE_FORCE + * is set in which case we override whatever was found earlier. + */ #ifdef CONFIG_CMDLINE #ifndef CONFIG_CMDLINE_FORCE - if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) + if (!((char *)data)[0]) #endif strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); #endif /* CONFIG_CMDLINE */ diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c index bb184717588f..ffab033d207e 100644 --- a/drivers/of/of_net.c +++ b/drivers/of/of_net.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/of_net.h> #include <linux/phy.h> +#include <linux/export.h> /** * It maps 'enum phy_interface_t' found in include/linux/phy.h diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 3701b62c1d5e..13e37e2d8ec1 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -1,4 +1,5 @@ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/of.h> #include <linux/of_pci.h> #include <asm/prom.h> diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c index ac1ec54e4fd5..93125163dea2 100644 --- a/drivers/of/of_pci_irq.c +++ b/drivers/of/of_pci_irq.c @@ -1,6 +1,7 @@ #include <linux/kernel.h> #include <linux/of_pci.h> #include <linux/of_irq.h> +#include <linux/export.h> #include <asm/prom.h> /** diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c index 1dbce58a58b0..6dbc074e4876 100644 --- a/drivers/of/of_spi.c +++ b/drivers/of/of_spi.c @@ -6,6 +6,7 @@ * tree. */ +#include <linux/module.h> #include <linux/of.h> #include <linux/device.h> #include <linux/spi/spi.h> diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 75a80e46b391..8b490d77054f 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -44,6 +44,7 @@ #include <linux/seq_file.h> #include <linux/scatterlist.h> #include <linux/iommu-helper.h> +#include <linux/export.h> #include <asm/byteorder.h> #include <asm/cache.h> /* for L1_CACHE_BYTES */ diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index a6f762188bc3..8644d5372e7f 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -39,6 +39,7 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/module.h> #include <asm/ropes.h> #include <asm/mckinley.h> /* for proc_mckinley_root */ diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index cec66064ee4b..b6f9749b4fa7 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -51,17 +51,6 @@ config XEN_PCIDEV_FRONTEND The PCI device frontend driver allows the kernel to import arbitrary PCI devices from a PCI backend to support PCI driver domains. -config XEN_PCIDEV_FE_DEBUG - bool "Xen PCI Frontend debugging" - depends on XEN_PCIDEV_FRONTEND && PCI_DEBUG - help - Say Y here if you want the Xen PCI frontend to produce a bunch of debug - messages to the system log. Select this if you are having a - problem with Xen PCI frontend support and want to see more of what is - going on. - - When in doubt, say N. - config HT_IRQ bool "Interrupts on hypertransport devices" default y diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index f727a09eb72f..7ec56fb0bd78 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -10,6 +10,7 @@ * PASID support added by Joerg Roedel <joerg.roedel@amd.com> */ +#include <linux/export.h> #include <linux/pci-ats.h> #include <linux/pci.h> diff --git a/drivers/pci/hotplug-pci.c b/drivers/pci/hotplug-pci.c index 4d4a64478404..d3509cdeb554 100644 --- a/drivers/pci/hotplug-pci.c +++ b/drivers/pci/hotplug-pci.c @@ -1,6 +1,7 @@ /* Core PCI functionality used only by PCI hotplug */ #include <linux/pci.h> +#include <linux/export.h> #include "pci.h" diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c index 5f7226223a62..376d70d17176 100644 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ b/drivers/pci/hotplug/pciehp_acpi.c @@ -27,6 +27,7 @@ #include <linux/pci.h> #include <linux/pci_hotplug.h> #include <linux/slab.h> +#include <linux/module.h> #include "pciehp.h" #define PCIEHP_DETECT_PCIE (0) diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c index 3ffd9c1acc0a..8c05a18c9770 100644 --- a/drivers/pci/hotplug/pcihp_slot.c +++ b/drivers/pci/hotplug/pcihp_slot.c @@ -24,6 +24,7 @@ */ #include <linux/pci.h> +#include <linux/export.h> #include <linux/pci_hotplug.h> static struct hpp_type0 pci_default_type0 = { diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index 1d002b1c2bf4..c56a9413e1af 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -18,6 +18,7 @@ #undef DEBUG #include <linux/init.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/string.h> #include <linux/vmalloc.h> diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index db057b6fe0c8..6e373ea57b32 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -9,6 +9,7 @@ #include <linux/irq.h> #include <linux/pci.h> #include <linux/spinlock.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/htirq.h> diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c index 203508b227b7..5775638ac017 100644 --- a/drivers/pci/ioapic.c +++ b/drivers/pci/ioapic.c @@ -17,6 +17,7 @@ */ #include <linux/pci.h> +#include <linux/export.h> #include <linux/acpi.h> #include <linux/slab.h> #include <acpi/acpi_bus.h> diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 9b4e88c636f8..b82c155d7b37 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -11,6 +11,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/mutex.h> +#include <linux/export.h> #include <linux/string.h> #include <linux/delay.h> #include <linux/pci-ats.h> diff --git a/drivers/pci/irq.c b/drivers/pci/irq.c index de01174aff06..e5f69a43b1b1 100644 --- a/drivers/pci/irq.c +++ b/drivers/pci/irq.c @@ -7,6 +7,7 @@ #include <linux/acpi.h> #include <linux/device.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/pci.h> static void pci_note_irq_problem(struct pci_dev *pdev, const char *reason) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 2f10328bf661..0e6d04d7ba4f 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -11,6 +11,7 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/export.h> #include <linux/ioport.h> #include <linux/pci.h> #include <linux/proc_fs.h> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 7bcf12adced7..106be0d08f81 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -19,6 +19,7 @@ #include <linux/sched.h> #include <linux/pci.h> #include <linux/stat.h> +#include <linux/export.h> #include <linux/topology.h> #include <linux/mm.h> #include <linux/fs.h> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7285145ac1c9..64765474676f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -17,6 +17,7 @@ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/pci.h> #include <linux/init.h> #include <linux/delay.h> diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index 36864a935d68..48ebdb237f3f 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -7,6 +7,7 @@ * PCI ROM access routines */ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/pci.h> #include <linux/slab.h> diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 51a9095c7da4..5717509becbe 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -18,6 +18,7 @@ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/pci.h> #include <linux/errno.h> #include <linux/ioport.h> diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 968cfea04f74..ac6412fb8d6f 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -7,6 +7,7 @@ #include <linux/kobject.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/err.h> #include "pci.h" diff --git a/drivers/pci/vpd.c b/drivers/pci/vpd.c index a5a5ca17cfe6..39b79070335d 100644 --- a/drivers/pci/vpd.c +++ b/drivers/pci/vpd.c @@ -6,6 +6,7 @@ */ #include <linux/pci.h> +#include <linux/export.h> int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt) { diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c index 01757f18a208..3e49df6d5e3b 100644 --- a/drivers/pcmcia/db1xxx_ss.c +++ b/drivers/pcmcia/db1xxx_ss.c @@ -24,6 +24,7 @@ #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/pm.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/resource.h> #include <linux/slab.h> diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 2c540542b5af..a87e2728b2c3 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -231,6 +231,7 @@ void pxa2xx_configure_sockets(struct device *dev) __raw_writel(mecr, MECR); } +EXPORT_SYMBOL(pxa2xx_configure_sockets); static const char *skt_names[] = { "PCMCIA socket 0", diff --git a/drivers/pcmcia/pxa2xx_cm_x255.c b/drivers/pcmcia/pxa2xx_cm_x255.c index 63f4d5211ed2..0b4f946cf13a 100644 --- a/drivers/pcmcia/pxa2xx_cm_x255.c +++ b/drivers/pcmcia/pxa2xx_cm_x255.c @@ -14,6 +14,7 @@ #include <linux/irq.h> #include <linux/delay.h> #include <linux/gpio.h> +#include <linux/export.h> #include <asm/mach-types.h> diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c index 6ee42b4c3e68..923f315926ef 100644 --- a/drivers/pcmcia/pxa2xx_cm_x270.c +++ b/drivers/pcmcia/pxa2xx_cm_x270.c @@ -14,6 +14,7 @@ #include <linux/irq.h> #include <linux/delay.h> #include <linux/gpio.h> +#include <linux/export.h> #include <asm/mach-types.h> diff --git a/drivers/pcmcia/pxa2xx_cm_x2xx.c b/drivers/pcmcia/pxa2xx_cm_x2xx.c index 4f09506ad8d4..6e7dcfd22ede 100644 --- a/drivers/pcmcia/pxa2xx_cm_x2xx.c +++ b/drivers/pcmcia/pxa2xx_cm_x2xx.c @@ -12,9 +12,8 @@ #include <linux/module.h> -#include <asm/system.h> #include <asm/mach-types.h> -#include <mach/system.h> +#include <mach/hardware.h> int cmx255_pcmcia_init(void); int cmx270_pcmcia_init(void); diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 423522d87313..eadef9e191ea 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) "pinctrl core: " fmt #include <linux/kernel.h> +#include <linux/export.h> #include <linux/init.h> #include <linux/device.h> #include <linux/slab.h> diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index c86665369a22..48870e504231 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -24,6 +24,7 @@ #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/sfi.h> +#include <linux/module.h> #include <asm/mrst.h> #include <asm/intel_scu_ipc.h> diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c index 6f40bf202dc7..2264331bd48e 100644 --- a/drivers/platform/x86/msi-wmi.c +++ b/drivers/platform/x86/msi-wmi.c @@ -28,6 +28,7 @@ #include <linux/acpi.h> #include <linux/backlight.h> #include <linux/slab.h> +#include <linux/module.h> MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>"); MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver"); diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 9b88be42b6cd..a134c26870b0 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -36,6 +36,7 @@ #include <linux/list.h> #include <linux/acpi.h> #include <linux/slab.h> +#include <linux/module.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index ca84d5099ce7..b00c17612a89 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -19,6 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/export.h> #include <linux/acpi.h> #include <linux/pnp.h> #include <linux/slab.h> diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index bbf3edd85beb..5be4a392a3ae 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -509,15 +509,12 @@ static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, struct acpi_resource_dma *p) { int i; - unsigned char map = 0, flags = 0; - - if (p->channel_count == 0) - flags |= IORESOURCE_DISABLED; + unsigned char map = 0, flags; for (i = 0; i < p->channel_count; i++) map |= 1 << p->channels[i]; - flags |= dma_flags(dev, p->type, p->bus_master, p->transfer); + flags = dma_flags(dev, p->type, p->bus_master, p->transfer); pnp_register_dma_resource(dev, option_flags, map, flags); } @@ -527,17 +524,14 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, { int i; pnp_irq_mask_t map; - unsigned char flags = 0; - - if (p->interrupt_count == 0) - flags |= IORESOURCE_DISABLED; + unsigned char flags; bitmap_zero(map.bits, PNP_IRQ_NR); for (i = 0; i < p->interrupt_count; i++) if (p->interrupts[i]) __set_bit(p->interrupts[i], map.bits); - flags |= irq_flags(p->triggering, p->polarity, p->sharable); + flags = irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(dev, option_flags, &map, flags); } @@ -547,10 +541,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, { int i; pnp_irq_mask_t map; - unsigned char flags = 0; - - if (p->interrupt_count == 0) - flags |= IORESOURCE_DISABLED; + unsigned char flags; bitmap_zero(map.bits, PNP_IRQ_NR); for (i = 0; i < p->interrupt_count; i++) { @@ -564,7 +555,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, } } - flags |= irq_flags(p->triggering, p->polarity, p->sharable); + flags = irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(dev, option_flags, &map, flags); } @@ -574,11 +565,8 @@ static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (io->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (io->io_decode == ACPI_DECODE_16) - flags |= IORESOURCE_IO_16BIT_ADDR; + flags = IORESOURCE_IO_16BIT_ADDR; pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, io->alignment, io->address_length, flags); } @@ -587,13 +575,8 @@ static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, unsigned int option_flags, struct acpi_resource_fixed_io *io) { - unsigned char flags = 0; - - if (io->address_length == 0) - flags |= IORESOURCE_DISABLED; - pnp_register_port_resource(dev, option_flags, io->address, io->address, - 0, io->address_length, flags | IORESOURCE_IO_FIXED); + 0, io->address_length, IORESOURCE_IO_FIXED); } static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, @@ -602,11 +585,8 @@ static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, p->alignment, p->address_length, flags); } @@ -617,11 +597,8 @@ static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, p->alignment, p->address_length, flags); } @@ -632,11 +609,8 @@ static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->address, p->address, 0, p->address_length, flags); } @@ -656,19 +630,16 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, return; } - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->resource_type == ACPI_MEMORY_RANGE) { if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, flags); } else if (p->resource_type == ACPI_IO_RANGE) pnp_register_port_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, - flags | IORESOURCE_IO_FIXED); + IORESOURCE_IO_FIXED); } static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, @@ -678,19 +649,16 @@ static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, struct acpi_resource_extended_address64 *p = &r->data.ext_address64; unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->resource_type == ACPI_MEMORY_RANGE) { if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, flags); } else if (p->resource_type == ACPI_IO_RANGE) pnp_register_port_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, - flags | IORESOURCE_IO_FIXED); + IORESOURCE_IO_FIXED); } struct acpipnp_parse_option_s { diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c index 98bfab35b8e9..9f0183c73076 100644 --- a/drivers/power/max17042_battery.c +++ b/drivers/power/max17042_battery.c @@ -23,6 +23,7 @@ */ #include <linux/init.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/mod_devicetable.h> diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index a9b0209a2f55..2595145f3bff 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c @@ -22,6 +22,7 @@ #include <linux/gpio.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/power_supply.h> #include <linux/platform_device.h> diff --git a/drivers/power/max8997_charger.c b/drivers/power/max8997_charger.c index ffc5033ea9c9..a23317d75c5a 100644 --- a/drivers/power/max8997_charger.c +++ b/drivers/power/max8997_charger.c @@ -19,6 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/module.h> #include <linux/err.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c index ef8efadb58cb..93e3bb47a3a8 100644 --- a/drivers/power/max8998_charger.c +++ b/drivers/power/max8998_charger.c @@ -19,6 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/module.h> #include <linux/err.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 605514afc29f..e15d4c9d3988 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -14,6 +14,7 @@ #include <linux/ctype.h> #include <linux/power_supply.h> #include <linux/slab.h> +#include <linux/stat.h> #include "power_supply.h" diff --git a/drivers/ps3/ps3stor_lib.c b/drivers/ps3/ps3stor_lib.c index af0afa1db4a8..cc328dec946b 100644 --- a/drivers/ps3/ps3stor_lib.c +++ b/drivers/ps3/ps3stor_lib.c @@ -19,6 +19,7 @@ */ #include <linux/dma-mapping.h> +#include <linux/module.h> #include <asm/lv1call.h> #include <asm/ps3stor.h> diff --git a/drivers/ps3/sys-manager-core.c b/drivers/ps3/sys-manager-core.c index 474225852b63..0e41737ea835 100644 --- a/drivers/ps3/sys-manager-core.c +++ b/drivers/ps3/sys-manager-core.c @@ -19,6 +19,7 @@ */ #include <linux/kernel.h> +#include <linux/export.h> #include <asm/lv1call.h> #include <asm/ps3.h> diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c index 043ee3136e40..809b7a3336ba 100644 --- a/drivers/rapidio/switches/idt_gen2.c +++ b/drivers/rapidio/switches/idt_gen2.c @@ -10,6 +10,7 @@ * option) any later version. */ +#include <linux/stat.h> #include <linux/rio.h> #include <linux/rio_drv.h> #include <linux/rio_ids.h> diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index e821b2159b4b..ca0d608f8248 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -16,6 +16,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/mfd/88pm860x.h> +#include <linux/module.h> struct pm8607_regulator_info { struct regulator_desc desc; diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 02f3c2333c83..6e1ae69646b3 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -13,6 +13,7 @@ */ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/err.h> #include <linux/platform_device.h> #include <linux/mfd/ab8500.h> diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c index 068d488a4f71..e24d1b7d97a8 100644 --- a/drivers/regulator/bq24022.c +++ b/drivers/regulator/bq24022.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/err.h> +#include <linux/module.h> #include <linux/gpio.h> #include <linux/regulator/bq24022.h> #include <linux/regulator/driver.h> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 67fa2a3297ad..669d02160221 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -28,6 +28,7 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/module.h> #define CREATE_TRACE_POINTS #include <trace/events/regulator.h> diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 362e08221085..e23ddfa8b2c6 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 2d014a144365..78329751af54 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -17,6 +17,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/db8500-prcmu.h> +#include <linux/module.h> /* * power state reference count diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index f6ef6694ab98..b8f520513ce7 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c @@ -16,6 +16,7 @@ */ #include <linux/err.h> +#include <linux/export.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 2fe9d99c9f23..21ecf212a522 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -20,6 +20,7 @@ #include <linux/err.h> #include <linux/mutex.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/fixed.h> diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 0f22ef12601c..72b16b5f3db6 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/regulator/driver.h> #include <linux/regulator/lp3971.h> #include <linux/slab.h> diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index 6aa1b506fb5d..fbc5e3741bef 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -12,6 +12,7 @@ #include <linux/bug.h> #include <linux/err.h> #include <linux/i2c.h> +#include <linux/module.h> #include <linux/kernel.h> #include <linux/regulator/driver.h> #include <linux/regulator/lp3972.h> diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index e4dbd667c043..cc9ec0e03271 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/err.h> #include <linux/i2c.h> diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index ad6628ca94f4..6176129a27e5 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -26,6 +26,7 @@ #include <linux/err.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index cb2841feeefd..8479082e1aea 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/module.h> #include "mc13xxx.h" #define MC13783_REG_SWITCHERS5 29 diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 3285d41842f2..023d17d022cf 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/module.h> #include "mc13xxx.h" #define MC13892_REVISION 7 diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index bc27ab136378..6532853a6ef5 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/module.h> #include "mc13xxx.h" static int mc13xxx_regulator_enable(struct regulator_dev *rdev) diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index dbcf09d5080c..14b9389dd52a 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -14,6 +14,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/err.h> #include <linux/slab.h> diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c index 9d5ba9357597..fc6655146999 100644 --- a/drivers/regulator/userspace-consumer.c +++ b/drivers/regulator/userspace-consumer.c @@ -18,6 +18,7 @@ #include <linux/err.h> #include <linux/mutex.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/regulator/userspace-consumer.h> diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index 69e550f57638..858c1f861ba5 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/module.h> struct virtual_consumer_data { struct mutex lock; diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 0f12c70bebc9..71632ddc3781 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -15,6 +15,7 @@ #include <linux/bug.h> #include <linux/err.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/regulator/driver.h> #include <linux/mfd/wm8400-private.h> diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 44e91e598f8d..8e286259a007 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -13,6 +13,7 @@ #include <linux/rtc.h> #include <linux/sched.h> +#include <linux/module.h> #include <linux/log2.h> #include <linux/workqueue.h> diff --git a/drivers/rtc/rtc-dm355evm.c b/drivers/rtc/rtc-dm355evm.c index 58d4e18530da..2322c43af201 100644 --- a/drivers/rtc/rtc-dm355evm.c +++ b/drivers/rtc/rtc-dm355evm.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #include <linux/i2c/dm355evm_msp.h> +#include <linux/module.h> /* diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 57fbcc149ba7..3a33b1fdbe0f 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -17,6 +17,7 @@ #include <linux/spi/spi.h> #include <linux/spi/ds1305.h> +#include <linux/module.h> /* diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 568ad30617e7..586c244a05d8 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -23,6 +23,7 @@ #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/module.h> #define DRV_VERSION "0.6" diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index fee41b97c9e8..1350029044e6 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -18,6 +18,7 @@ #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/module.h> #define DRV_VERSION "0.3" diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 06dfb54f99b6..a319402a5447 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -11,6 +11,7 @@ #include <linux/i2c.h> #include <linux/rtc.h> +#include <linux/module.h> #define DRV_VERSION "0.4" diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index d84a448dd754..e3e0f92b60f0 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -21,6 +21,7 @@ #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/module.h> #define DRV_VERSION "0.4" diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c index d8e1c2578553..8414dea5fb14 100644 --- a/drivers/rtc/rtc-em3027.c +++ b/drivers/rtc/rtc-em3027.c @@ -14,6 +14,7 @@ #include <linux/i2c.h> #include <linux/rtc.h> #include <linux/bcd.h> +#include <linux/module.h> /* Registers */ #define EM3027_REG_ON_OFF_CTRL 0x00 diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index ddbc797ea6cd..6186833973ee 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -15,6 +15,7 @@ #include <linux/bcd.h> #include <linux/rtc.h> #include <linux/slab.h> +#include <linux/module.h> #define DRV_VERSION "0.1" diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index 60627a764514..768e2edb9678 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/gfp.h> +#include <linux/module.h> #define RTC_TIME_REG_OFFS 0 diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 71bab0ef5443..2ee3bbf7e5ea 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -42,6 +42,7 @@ #include <linux/slab.h> #include <linux/rtc.h> #include <linux/spi/spi.h> +#include <linux/module.h> #define DRV_VERSION "0.6" diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index b42c0c679266..606fdfab34e2 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -18,6 +18,7 @@ #include <linux/bcd.h> #include <linux/rtc.h> #include <linux/slab.h> +#include <linux/module.h> #define DRV_VERSION "0.4.3" diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c index 368d0e63cf83..971bc8e08da6 100644 --- a/drivers/rtc/rtc-rs5c348.c +++ b/drivers/rtc/rtc-rs5c348.c @@ -23,6 +23,7 @@ #include <linux/rtc.h> #include <linux/workqueue.h> #include <linux/spi/spi.h> +#include <linux/module.h> #define DRV_VERSION "0.2" diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 85c1b848dd72..d29f5432c6e8 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -14,6 +14,7 @@ #include <linux/rtc.h> #include <linux/bcd.h> #include <linux/slab.h> +#include <linux/module.h> #define DRV_VERSION "0.6" diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index 3b943673cd3e..ed3e9b599031 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -21,6 +21,7 @@ #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/module.h> #define DRV_VERSION "0.1" diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index ec6313d15359..aac0ffed4345 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -11,6 +11,7 @@ #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/io.h> #include <linux/gfp.h> #include <asm/txx9/tx4939.h> diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index b00aad2620d4..8c051d3179db 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -21,6 +21,7 @@ #include <linux/bcd.h> #include <linux/rtc.h> #include <linux/delay.h> +#include <linux/module.h> #define DRV_VERSION "1.0.8" diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 9b43ae94beba..a5a55da2a1ac 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -27,7 +27,7 @@ static int dcssblk_open(struct block_device *bdev, fmode_t mode); static int dcssblk_release(struct gendisk *disk, fmode_t mode); -static int dcssblk_make_request(struct request_queue *q, struct bio *bio); +static void dcssblk_make_request(struct request_queue *q, struct bio *bio); static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, void **kaddr, unsigned long *pfn); @@ -814,7 +814,7 @@ out: return rc; } -static int +static void dcssblk_make_request(struct request_queue *q, struct bio *bio) { struct dcssblk_dev_info *dev_info; @@ -871,10 +871,9 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) bytes_done += bvec->bv_len; } bio_endio(bio, 0); - return 0; + return; fail: bio_io_error(bio); - return 0; } static int diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 1f6a4d894e73..98f3e4ade924 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -181,7 +181,7 @@ static unsigned long xpram_highest_page_index(void) /* * Block device make request function. */ -static int xpram_make_request(struct request_queue *q, struct bio *bio) +static void xpram_make_request(struct request_queue *q, struct bio *bio) { xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data; struct bio_vec *bvec; @@ -221,10 +221,9 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio) } set_bit(BIO_UPTODATE, &bio->bi_flags); bio_endio(bio, 0); - return 0; + return; fail: bio_io_error(bio); - return 0; } static int xpram_getgeo(struct block_device *bdev, struct hd_geometry *geo) diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index f6489eb7e976..e71298158f9e 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -11,6 +11,7 @@ #include <linux/console.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/list.h> #include <linux/slab.h> #include <linux/types.h> diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c index 4a51e3f09689..bd1b9c919051 100644 --- a/drivers/s390/char/sclp_cpi_sys.c +++ b/drivers/s390/char/sclp_cpi_sys.c @@ -21,6 +21,7 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/completion.h> +#include <linux/export.h> #include <asm/ebcdic.h> #include <asm/sclp.h> diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 31a3ccbb6495..75bde6a8b7dc 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/miscdevice.h> #include <linux/slab.h> +#include <linux/export.h> #include <asm/compat.h> #include <asm/cpcmd.h> #include <asm/debug.h> diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index d291a54acfad..85f4a9a5d12e 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -13,6 +13,7 @@ #include <linux/cdev.h> #include <linux/slab.h> +#include <linux/module.h> #include <asm/uaccess.h> #include <asm/cio.h> diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 2d32233943a9..e792436c9270 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -10,6 +10,8 @@ #include <linux/bug.h> #include <linux/workqueue.h> #include <linux/spinlock.h> +#include <linux/export.h> +#include <linux/sched.h> #include <linux/init.h> #include <linux/jiffies.h> #include <linux/wait.h> diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index ed68245f9741..29021f4e96b6 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -7,6 +7,8 @@ */ #include <linux/seq_file.h> #include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/export.h> #include <asm/debug.h> #include "qdio_debug.h" #include "qdio.h" diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index d9a46a429bcc..2acc01f90a6a 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -8,6 +8,7 @@ */ #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/export.h> #include <asm/qdio.h> #include "cio.h" diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 3c2c923d5c0a..94f49ffa70ba 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -20,6 +20,7 @@ #include <linux/virtio_console.h> #include <linux/interrupt.h> #include <linux/virtio_ring.h> +#include <linux/export.h> #include <linux/pfn.h> #include <asm/io.h> #include <asm/kvm_para.h> diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 645b0fcbb370..086018109662 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -31,6 +31,7 @@ #include <linux/miscdevice.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/module.h> #include "zfcp_ext.h" #include "zfcp_fc.h" #include "zfcp_reqlist.h" diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index e8b7cee62046..96f13ad88123 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -9,6 +9,7 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/module.h> #include "zfcp_ext.h" #include "zfcp_reqlist.h" diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 967e7b70e977..a9a816e4aa55 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -9,6 +9,7 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/module.h> #include <linux/ctype.h> #include <linux/slab.h> #include <asm/debug.h> diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index df9e69f54742..e14da5751d32 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/slab.h> +#include <linux/module.h> #include "zfcp_ext.h" #include "zfcp_qdio.h" diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 09126a9d62ff..11f07f888223 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -9,6 +9,7 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/module.h> #include <linux/types.h> #include <linux/slab.h> #include <scsi/fc/fc_fcp.h> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index aa573c39f596..06ea3bcfdd2a 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -617,20 +617,6 @@ config SCSI_ARCMSR To compile this driver as a module, choose M here: the module will be called arcmsr (modprobe arcmsr). -config SCSI_ARCMSR_AER - bool "Enable PCI Error Recovery Capability in Areca Driver(ARCMSR)" - depends on SCSI_ARCMSR && PCIEAER - default n - help - The advanced error reporting(AER) capability is "NOT" provided by - ARC1200/1201/1202 SATA RAID controllers cards. - If your card is one of ARC1200/1201/1202, please use the default setting, n. - If your card is other models, you could pick it - on condition that the kernel version is greater than 2.6.19. - This function is maintained driver by Nick Cheng. If you have any - problems or suggestion, you are welcome to contact with <nick.cheng@areca.com.tw>. - To enable this function, choose Y here. - source "drivers/scsi/megaraid/Kconfig.megaraid" source "drivers/scsi/mpt2sas/Kconfig" diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index 1bb5d3f0e260..79a30633d4aa 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -5,6 +5,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/zorro.h> +#include <linux/module.h> #include <asm/page.h> #include <asm/pgtable.h> diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index d9468027fb61..e29fe0e708f8 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -6,6 +6,7 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/module.h> #include <asm/page.h> #include <asm/pgtable.h> diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 061995741444..409f5805bdd6 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -34,6 +34,7 @@ #include <linux/blkdev.h> #include <asm/uaccess.h> #include <linux/highmem.h> /* For flush_kernel_dcache_page */ +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 7b0a8ab71049..379c696dac19 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -27,6 +27,7 @@ #include <linux/kernel.h> #include <linux/semaphore.h> #include <linux/iscsi_boot_sysfs.h> +#include <linux/module.h> #include <scsi/libiscsi.h> #include <scsi/scsi_transport_iscsi.h> diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c index b412e0300dd4..dee1a094c2c2 100644 --- a/drivers/scsi/bfa/bfad_debugfs.c +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -16,6 +16,7 @@ */ #include <linux/debugfs.h> +#include <linux/export.h> #include "bfad_drv.h" #include "bfad_im.h" diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 01312381639f..e5db649e8eb7 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -19,6 +19,8 @@ * bfad_im.c Linux driver IM module. */ +#include <linux/export.h> + #include "bfad_drv.h" #include "bfad_im.h" #include "bfa_fcs.h" diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 63de1c7cd0cb..049ea907e04a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -62,7 +62,7 @@ #include "bnx2fc_constants.h" #define BNX2FC_NAME "bnx2fc" -#define BNX2FC_VERSION "1.0.8" +#define BNX2FC_VERSION "1.0.9" #define PFX "bnx2fc: " @@ -145,6 +145,9 @@ #define REC_RETRY_COUNT 1 #define BNX2FC_NUM_ERR_BITS 63 +#define BNX2FC_RELOGIN_WAIT_TIME 200 +#define BNX2FC_RELOGIN_WAIT_CNT 10 + /* bnx2fc driver uses only one instance of fcoe_percpu_s */ extern struct fcoe_percpu_s bnx2fc_global; diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index fd382fe33f6e..ce0ce3e32f33 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -268,17 +268,6 @@ void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg) orig_io_req = cb_arg->aborted_io_req; srr_req = cb_arg->io_req; - if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) { - BNX2FC_IO_DBG(srr_req, "srr_compl: xid - 0x%x completed", - orig_io_req->xid); - goto srr_compl_done; - } - if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { - BNX2FC_IO_DBG(srr_req, "rec abts in prog " - "orig_io - 0x%x\n", - orig_io_req->xid); - goto srr_compl_done; - } if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &srr_req->req_flags)) { /* SRR timedout */ BNX2FC_IO_DBG(srr_req, "srr timed out, abort " @@ -290,6 +279,12 @@ void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg) "failed. issue cleanup\n"); bnx2fc_initiate_cleanup(srr_req); } + if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) || + test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { + BNX2FC_IO_DBG(srr_req, "srr_compl:xid 0x%x flags = %lx", + orig_io_req->xid, orig_io_req->req_flags); + goto srr_compl_done; + } orig_io_req->srr_retry++; if (orig_io_req->srr_retry <= SRR_RETRY_COUNT) { struct bnx2fc_rport *tgt = orig_io_req->tgt; @@ -311,6 +306,12 @@ void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg) } goto srr_compl_done; } + if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) || + test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { + BNX2FC_IO_DBG(srr_req, "srr_compl:xid - 0x%x flags = %lx", + orig_io_req->xid, orig_io_req->req_flags); + goto srr_compl_done; + } mp_req = &(srr_req->mp_req); fc_hdr = &(mp_req->resp_fc_hdr); resp_len = mp_req->resp_len; diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 85bcc4b55965..8c6156a10d90 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -22,7 +22,7 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); #define DRV_MODULE_NAME "bnx2fc" #define DRV_MODULE_VERSION BNX2FC_VERSION -#define DRV_MODULE_RELDATE "Oct 02, 2011" +#define DRV_MODULE_RELDATE "Oct 21, 2011" static char version[] __devinitdata = diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 0c64d184d731..84a78af83f90 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1103,7 +1103,10 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) struct fc_rport_libfc_priv *rp = rport->dd_data; struct bnx2fc_cmd *io_req; struct fc_lport *lport; + struct fc_rport_priv *rdata; struct bnx2fc_rport *tgt; + int logo_issued; + int wait_cnt = 0; int rc = FAILED; @@ -1192,8 +1195,40 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) } else { printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " "already in abts processing\n", io_req->xid); + if (cancel_delayed_work(&io_req->timeout_work)) + kref_put(&io_req->refcount, + bnx2fc_cmd_release); /* drop timer hold */ + bnx2fc_initiate_cleanup(io_req); + + spin_unlock_bh(&tgt->tgt_lock); + + wait_for_completion(&io_req->tm_done); + + spin_lock_bh(&tgt->tgt_lock); + io_req->wait_for_comp = 0; + rdata = io_req->tgt->rdata; + logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, + &tgt->flags); kref_put(&io_req->refcount, bnx2fc_cmd_release); spin_unlock_bh(&tgt->tgt_lock); + + if (!logo_issued) { + BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", + tgt->flags); + mutex_lock(&lport->disc.disc_mutex); + lport->tt.rport_logoff(rdata); + mutex_unlock(&lport->disc.disc_mutex); + do { + msleep(BNX2FC_RELOGIN_WAIT_TIME); + /* + * If session not recovered, let SCSI-ml + * escalate error recovery. + */ + if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) + return FAILED; + } while (!test_bit(BNX2FC_FLAG_SESSION_READY, + &tgt->flags)); + } return SUCCESS; } if (rc == FAILED) { @@ -1275,6 +1310,8 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, io_req->refcount.refcount.counter, io_req->cmd_type); bnx2fc_scsi_done(io_req, DID_ERROR); kref_put(&io_req->refcount, bnx2fc_cmd_release); + if (io_req->wait_for_comp) + complete(&io_req->tm_done); } void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index c363a4b260fd..c10f74a566f2 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -25,6 +25,7 @@ #include <net/dst.h> #include <net/route.h> #include <linux/inetdevice.h> /* ip_dev_find */ +#include <linux/module.h> #include <net/tcp.h> static unsigned int dbg_level; diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 7c05fd9dccfd..23149b9e297c 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -22,6 +22,7 @@ */ #include <linux/slab.h> +#include <linux/module.h> #include <scsi/scsi_dh.h> #include "../scsi_priv.h" @@ -441,7 +442,15 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) spin_lock_irqsave(q->queue_lock, flags); sdev = q->queuedata; - if (sdev && sdev->scsi_dh_data) + if (!sdev) { + spin_unlock_irqrestore(q->queue_lock, flags); + err = SCSI_DH_NOSYS; + if (fn) + fn(data, err); + return err; + } + + if (sdev->scsi_dh_data) scsi_dh = sdev->scsi_dh_data->scsi_dh; dev = get_device(&sdev->sdev_gendev); if (!scsi_dh || !dev || diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 627f4b5e5176..4ef021291a4d 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -21,6 +21,7 @@ */ #include <linux/slab.h> #include <linux/delay.h> +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_dh.h> @@ -507,7 +508,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) int len, k, off, valid_states = 0; unsigned char *ucp; unsigned err; - unsigned long expiry, interval = 1; + unsigned long expiry, interval = 1000; expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT); retry: @@ -734,6 +735,7 @@ static int alua_bus_attach(struct scsi_device *sdev) spin_lock_irqsave(sdev->request_queue->queue_lock, flags); sdev->scsi_dh_data = scsi_dh_data; spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); + sdev_printk(KERN_NOTICE, sdev, "%s: Attached\n", ALUA_DH_NAME); return 0; diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 48441f6908a4..591186cf1896 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -21,6 +21,7 @@ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/slab.h> +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_dh.h> diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index b479f1eef968..0f86a18b157d 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -22,6 +22,7 @@ */ #include <linux/slab.h> +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_dbg.h> #include <scsi/scsi_eh.h> diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 82d612f0c49d..1d3127920063 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -24,6 +24,7 @@ #include <scsi/scsi_dh.h> #include <linux/workqueue.h> #include <linux/slab.h> +#include <linux/module.h> #define RDAC_NAME "rdac" #define RDAC_RETRY_COUNT 5 diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 61384ee4049b..cefbe44bb84a 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -2347,14 +2347,11 @@ static void fcoe_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) goto done; mac = fr_cb(fp)->granted_mac; - if (is_zero_ether_addr(mac)) { - /* pre-FIP */ - if (fcoe_ctlr_recv_flogi(fip, lport, fp)) { - fc_frame_free(fp); - return; - } - } - fcoe_update_src_mac(lport, mac); + /* pre-FIP */ + if (is_zero_ether_addr(mac)) + fcoe_ctlr_recv_flogi(fip, lport, fp); + if (!is_zero_ether_addr(mac)) + fcoe_update_src_mac(lport, mac); done: fc_lport_flogi_resp(seq, fp, lport); } diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index 50bb54150a78..488fbc648656 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -5,6 +5,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/zorro.h> +#include <linux/module.h> #include <asm/page.h> #include <asm/pgtable.h> diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 4f7a5829ea4c..351dc0b86fab 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -286,6 +286,7 @@ static void scsi_host_dev_release(struct device *dev) { struct Scsi_Host *shost = dev_to_shost(dev); struct device *parent = dev->parent; + struct request_queue *q; scsi_proc_hostdir_rm(shost->hostt); @@ -293,9 +294,11 @@ 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); + q = shost->uspace_req_q; + if (q) { + kfree(q->queuedata); + q->queuedata = NULL; + scsi_free_queue(q); } scsi_destroy_command_freelist(shost); diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9825ecf34957..e76107b2ade3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -48,6 +48,7 @@ #include <linux/bitmap.h> #include <linux/atomic.h> #include <linux/kthread.h> +#include <linux/jiffies.h> #include "hpsa_cmd.h" #include "hpsa.h" @@ -127,6 +128,10 @@ static struct board_type products[] = { static int number_of_controllers; +static struct list_head hpsa_ctlr_list = LIST_HEAD_INIT(hpsa_ctlr_list); +static spinlock_t lockup_detector_lock; +static struct task_struct *hpsa_lockup_detector; + static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg); @@ -484,6 +489,7 @@ static struct scsi_host_template hpsa_driver_template = { #endif .sdev_attrs = hpsa_sdev_attrs, .shost_attrs = hpsa_shost_attrs, + .max_sectors = 8192, }; @@ -566,16 +572,16 @@ static int hpsa_find_target_lun(struct ctlr_info *h, * assumes h->devlock is held */ int i, found = 0; - DECLARE_BITMAP(lun_taken, HPSA_MAX_SCSI_DEVS_PER_HBA); + DECLARE_BITMAP(lun_taken, HPSA_MAX_DEVICES); - memset(&lun_taken[0], 0, HPSA_MAX_SCSI_DEVS_PER_HBA >> 3); + memset(&lun_taken[0], 0, HPSA_MAX_DEVICES >> 3); for (i = 0; i < h->ndevices; i++) { if (h->dev[i]->bus == bus && h->dev[i]->target != -1) set_bit(h->dev[i]->target, lun_taken); } - for (i = 0; i < HPSA_MAX_SCSI_DEVS_PER_HBA; i++) { + for (i = 0; i < HPSA_MAX_DEVICES; i++) { if (!test_bit(i, lun_taken)) { /* *bus = 1; */ *target = i; @@ -598,7 +604,7 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, unsigned char addr1[8], addr2[8]; struct hpsa_scsi_dev_t *sd; - if (n >= HPSA_MAX_SCSI_DEVS_PER_HBA) { + if (n >= HPSA_MAX_DEVICES) { dev_err(&h->pdev->dev, "too many devices, some will be " "inaccessible.\n"); return -1; @@ -673,7 +679,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, struct hpsa_scsi_dev_t *removed[], int *nremoved) { /* assumes h->devlock is held */ - BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA); + BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES); removed[*nremoved] = h->dev[entry]; (*nremoved)++; @@ -702,7 +708,7 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, int i; struct hpsa_scsi_dev_t *sd; - BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA); + BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES); sd = h->dev[entry]; removed[*nremoved] = h->dev[entry]; @@ -814,10 +820,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, int nadded, nremoved; struct Scsi_Host *sh = NULL; - added = kzalloc(sizeof(*added) * HPSA_MAX_SCSI_DEVS_PER_HBA, - GFP_KERNEL); - removed = kzalloc(sizeof(*removed) * HPSA_MAX_SCSI_DEVS_PER_HBA, - GFP_KERNEL); + added = kzalloc(sizeof(*added) * HPSA_MAX_DEVICES, GFP_KERNEL); + removed = kzalloc(sizeof(*removed) * HPSA_MAX_DEVICES, GFP_KERNEL); if (!added || !removed) { dev_warn(&h->pdev->dev, "out of memory in " @@ -1338,6 +1342,22 @@ static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, wait_for_completion(&wait); } +static void hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, + struct CommandList *c) +{ + unsigned long flags; + + /* If controller lockup detected, fake a hardware error. */ + spin_lock_irqsave(&h->lock, flags); + if (unlikely(h->lockup_detected)) { + spin_unlock_irqrestore(&h->lock, flags); + c->err_info->CommandStatus = CMD_HARDWARE_ERR; + } else { + spin_unlock_irqrestore(&h->lock, flags); + hpsa_scsi_do_simple_cmd_core(h, c); + } +} + static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, struct CommandList *c, int data_direction) { @@ -1735,7 +1755,6 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h, if (is_scsi_rev_5(h)) return 0; /* p1210m doesn't need to do this. */ -#define MAX_MSA2XXX_ENCLOSURES 32 if (*nmsa2xxx_enclosures >= MAX_MSA2XXX_ENCLOSURES) { dev_warn(&h->pdev->dev, "Maximum number of MSA2XXX " "enclosures exceeded. Check your hardware " @@ -1846,8 +1865,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) int raid_ctlr_position; DECLARE_BITMAP(lunzerobits, HPSA_MAX_TARGETS_PER_CTLR); - currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_SCSI_DEVS_PER_HBA, - GFP_KERNEL); + currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL); physdev_list = kzalloc(reportlunsize, GFP_KERNEL); logdev_list = kzalloc(reportlunsize, GFP_KERNEL); tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); @@ -1870,6 +1888,13 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) /* Allocate the per device structures */ for (i = 0; i < ndevs_to_allocate; i++) { + if (i >= HPSA_MAX_DEVICES) { + dev_warn(&h->pdev->dev, "maximum devices (%d) exceeded." + " %d devices ignored.\n", HPSA_MAX_DEVICES, + ndevs_to_allocate - HPSA_MAX_DEVICES); + break; + } + currentsd[i] = kzalloc(sizeof(*currentsd[i]), GFP_KERNEL); if (!currentsd[i]) { dev_warn(&h->pdev->dev, "out of memory at %s:%d\n", @@ -1956,7 +1981,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) default: break; } - if (ncurrent >= HPSA_MAX_SCSI_DEVS_PER_HBA) + if (ncurrent >= HPSA_MAX_DEVICES) break; } adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); @@ -2048,8 +2073,14 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, } memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); - /* Need a lock as this is being allocated from the pool */ spin_lock_irqsave(&h->lock, flags); + if (unlikely(h->lockup_detected)) { + spin_unlock_irqrestore(&h->lock, flags); + cmd->result = DID_ERROR << 16; + done(cmd); + return 0; + } + /* Need a lock as this is being allocated from the pool */ c = cmd_alloc(h); spin_unlock_irqrestore(&h->lock, flags); if (c == NULL) { /* trouble... */ @@ -2601,7 +2632,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->SG[0].Len = iocommand.buf_size; c->SG[0].Ext = 0; /* we are not chaining*/ } - hpsa_scsi_do_simple_cmd_core(h, c); + hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); if (iocommand.buf_size > 0) hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL); check_ioctl_unit_attention(h, c); @@ -2724,7 +2755,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->SG[i].Ext = 0; } } - hpsa_scsi_do_simple_cmd_core(h, c); + hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); if (sg_used) hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL); check_ioctl_unit_attention(h, c); @@ -2872,6 +2903,8 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.Timeout = 0; c->Request.CDB[0] = BMIC_WRITE; c->Request.CDB[6] = BMIC_CACHE_FLUSH; + c->Request.CDB[7] = (size >> 8) & 0xFF; + c->Request.CDB[8] = size & 0xFF; break; case TEST_UNIT_READY: c->Request.CDBLen = 6; @@ -3091,6 +3124,7 @@ static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id) if (interrupt_not_for_us(h)) return IRQ_NONE; spin_lock_irqsave(&h->lock, flags); + h->last_intr_timestamp = get_jiffies_64(); while (interrupt_pending(h)) { raw_tag = get_next_completion(h); while (raw_tag != FIFO_EMPTY) @@ -3110,6 +3144,7 @@ static irqreturn_t hpsa_msix_discard_completions(int irq, void *dev_id) return IRQ_NONE; spin_lock_irqsave(&h->lock, flags); + h->last_intr_timestamp = get_jiffies_64(); raw_tag = get_next_completion(h); while (raw_tag != FIFO_EMPTY) raw_tag = next_command(h); @@ -3126,6 +3161,7 @@ static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id) if (interrupt_not_for_us(h)) return IRQ_NONE; spin_lock_irqsave(&h->lock, flags); + h->last_intr_timestamp = get_jiffies_64(); while (interrupt_pending(h)) { raw_tag = get_next_completion(h); while (raw_tag != FIFO_EMPTY) { @@ -3146,6 +3182,7 @@ static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id) u32 raw_tag; spin_lock_irqsave(&h->lock, flags); + h->last_intr_timestamp = get_jiffies_64(); raw_tag = get_next_completion(h); while (raw_tag != FIFO_EMPTY) { if (hpsa_tag_contains_index(raw_tag)) @@ -3300,6 +3337,13 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= PCI_D0; pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); + + /* + * The P600 requires a small delay when changing states. + * Otherwise we may think the board did not reset and we bail. + * This for kdump only and is particular to the P600. + */ + msleep(500); } return 0; } @@ -4083,6 +4127,149 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) kfree(h); } +static void remove_ctlr_from_lockup_detector_list(struct ctlr_info *h) +{ + assert_spin_locked(&lockup_detector_lock); + if (!hpsa_lockup_detector) + return; + if (h->lockup_detected) + return; /* already stopped the lockup detector */ + list_del(&h->lockup_list); +} + +/* Called when controller lockup detected. */ +static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list) +{ + struct CommandList *c = NULL; + + assert_spin_locked(&h->lock); + /* Mark all outstanding commands as failed and complete them. */ + while (!list_empty(list)) { + c = list_entry(list->next, struct CommandList, list); + c->err_info->CommandStatus = CMD_HARDWARE_ERR; + finish_cmd(c, c->Header.Tag.lower); + } +} + +static void controller_lockup_detected(struct ctlr_info *h) +{ + unsigned long flags; + + assert_spin_locked(&lockup_detector_lock); + remove_ctlr_from_lockup_detector_list(h); + h->access.set_intr_mask(h, HPSA_INTR_OFF); + spin_lock_irqsave(&h->lock, flags); + h->lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); + spin_unlock_irqrestore(&h->lock, flags); + dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x\n", + h->lockup_detected); + pci_disable_device(h->pdev); + spin_lock_irqsave(&h->lock, flags); + fail_all_cmds_on_list(h, &h->cmpQ); + fail_all_cmds_on_list(h, &h->reqQ); + spin_unlock_irqrestore(&h->lock, flags); +} + +#define HEARTBEAT_SAMPLE_INTERVAL (10 * HZ) +#define HEARTBEAT_CHECK_MINIMUM_INTERVAL (HEARTBEAT_SAMPLE_INTERVAL / 2) + +static void detect_controller_lockup(struct ctlr_info *h) +{ + u64 now; + u32 heartbeat; + unsigned long flags; + + assert_spin_locked(&lockup_detector_lock); + now = get_jiffies_64(); + /* If we've received an interrupt recently, we're ok. */ + if (time_after64(h->last_intr_timestamp + + (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now)) + return; + + /* + * If we've already checked the heartbeat recently, we're ok. + * This could happen if someone sends us a signal. We + * otherwise don't care about signals in this thread. + */ + if (time_after64(h->last_heartbeat_timestamp + + (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now)) + return; + + /* If heartbeat has not changed since we last looked, we're not ok. */ + spin_lock_irqsave(&h->lock, flags); + heartbeat = readl(&h->cfgtable->HeartBeat); + spin_unlock_irqrestore(&h->lock, flags); + if (h->last_heartbeat == heartbeat) { + controller_lockup_detected(h); + return; + } + + /* We're ok. */ + h->last_heartbeat = heartbeat; + h->last_heartbeat_timestamp = now; +} + +static int detect_controller_lockup_thread(void *notused) +{ + struct ctlr_info *h; + unsigned long flags; + + while (1) { + struct list_head *this, *tmp; + + schedule_timeout_interruptible(HEARTBEAT_SAMPLE_INTERVAL); + if (kthread_should_stop()) + break; + spin_lock_irqsave(&lockup_detector_lock, flags); + list_for_each_safe(this, tmp, &hpsa_ctlr_list) { + h = list_entry(this, struct ctlr_info, lockup_list); + detect_controller_lockup(h); + } + spin_unlock_irqrestore(&lockup_detector_lock, flags); + } + return 0; +} + +static void add_ctlr_to_lockup_detector_list(struct ctlr_info *h) +{ + unsigned long flags; + + spin_lock_irqsave(&lockup_detector_lock, flags); + list_add_tail(&h->lockup_list, &hpsa_ctlr_list); + spin_unlock_irqrestore(&lockup_detector_lock, flags); +} + +static void start_controller_lockup_detector(struct ctlr_info *h) +{ + /* Start the lockup detector thread if not already started */ + if (!hpsa_lockup_detector) { + spin_lock_init(&lockup_detector_lock); + hpsa_lockup_detector = + kthread_run(detect_controller_lockup_thread, + NULL, "hpsa"); + } + if (!hpsa_lockup_detector) { + dev_warn(&h->pdev->dev, + "Could not start lockup detector thread\n"); + return; + } + add_ctlr_to_lockup_detector_list(h); +} + +static void stop_controller_lockup_detector(struct ctlr_info *h) +{ + unsigned long flags; + + spin_lock_irqsave(&lockup_detector_lock, flags); + remove_ctlr_from_lockup_detector_list(h); + /* If the list of ctlr's to monitor is empty, stop the thread */ + if (list_empty(&hpsa_ctlr_list)) { + kthread_stop(hpsa_lockup_detector); + hpsa_lockup_detector = NULL; + } + spin_unlock_irqrestore(&lockup_detector_lock, flags); +} + static int __devinit hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -4120,7 +4307,6 @@ reinit_after_soft_reset: return -ENOMEM; h->pdev = pdev; - h->busy_initializing = 1; h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; INIT_LIST_HEAD(&h->cmpQ); INIT_LIST_HEAD(&h->reqQ); @@ -4229,7 +4415,7 @@ reinit_after_soft_reset: hpsa_hba_inquiry(h); hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ - h->busy_initializing = 0; + start_controller_lockup_detector(h); return 1; clean4: @@ -4238,7 +4424,6 @@ clean4: free_irq(h->intr[h->intr_mode], h); clean2: clean1: - h->busy_initializing = 0; kfree(h); return rc; } @@ -4293,10 +4478,11 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev) struct ctlr_info *h; if (pci_get_drvdata(pdev) == NULL) { - dev_err(&pdev->dev, "unable to remove device \n"); + dev_err(&pdev->dev, "unable to remove device\n"); return; } h = pci_get_drvdata(pdev); + stop_controller_lockup_detector(h); hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ hpsa_shutdown(pdev); iounmap(h->vaddr); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 7f53ceaa7239..91edafb8c7e6 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -95,8 +95,6 @@ struct ctlr_info { unsigned long *cmd_pool_bits; int nr_allocs; int nr_frees; - int busy_initializing; - int busy_scanning; int scan_finished; spinlock_t scan_lock; wait_queue_head_t scan_wait_queue; @@ -104,8 +102,7 @@ struct ctlr_info { struct Scsi_Host *scsi_host; spinlock_t devlock; /* to protect hba[ctlr]->dev[]; */ int ndevices; /* number of used elements in .dev[] array. */ -#define HPSA_MAX_SCSI_DEVS_PER_HBA 256 - struct hpsa_scsi_dev_t *dev[HPSA_MAX_SCSI_DEVS_PER_HBA]; + struct hpsa_scsi_dev_t *dev[HPSA_MAX_DEVICES]; /* * Performant mode tables. */ @@ -124,6 +121,11 @@ struct ctlr_info { unsigned char reply_pool_wraparound; u32 *blockFetchTable; unsigned char *hba_inquiry_data; + u64 last_intr_timestamp; + u32 last_heartbeat; + u64 last_heartbeat_timestamp; + u32 lockup_detected; + struct list_head lockup_list; }; #define HPSA_ABORT_MSG 0 #define HPSA_DEVICE_RESET_MSG 1 diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 55d741b019db..3fd4715935c2 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -123,8 +123,11 @@ union u64bit { /* FIXME this is a per controller value (barf!) */ #define HPSA_MAX_TARGETS_PER_CTLR 16 -#define HPSA_MAX_LUN 256 +#define HPSA_MAX_LUN 1024 #define HPSA_MAX_PHYS_LUN 1024 +#define MAX_MSA2XXX_ENCLOSURES 32 +#define HPSA_MAX_DEVICES (HPSA_MAX_PHYS_LUN + HPSA_MAX_LUN + \ + MAX_MSA2XXX_ENCLOSURES + 1) /* + 1 is for the controller itself */ /* SCSI-3 Commands */ #pragma pack(1) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 73e24b48dced..fd860d952b28 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -9123,6 +9123,8 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B2, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C3, 0, 0, 0 }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C4, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B4, 0, 0, 0 }, diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 6d257e0dd6a5..ac84736c1b9c 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -82,6 +82,7 @@ #define IPR_SUBS_DEV_ID_57B4 0x033B #define IPR_SUBS_DEV_ID_57B2 0x035F +#define IPR_SUBS_DEV_ID_57C3 0x0353 #define IPR_SUBS_DEV_ID_57C4 0x0354 #define IPR_SUBS_DEV_ID_57C6 0x0357 #define IPR_SUBS_DEV_ID_57CC 0x035C diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index f07f30fada1b..e7fe9c4c85b8 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1350,7 +1350,7 @@ static void isci_user_parameters_get(struct sci_user_parameters *u) u->stp_max_occupancy_timeout = stp_max_occ_to; u->ssp_max_occupancy_timeout = ssp_max_occ_to; u->no_outbound_task_timeout = no_outbound_task_to; - u->max_number_concurrent_device_spin_up = max_concurr_spinup; + u->max_concurr_spinup = max_concurr_spinup; } static void sci_controller_initial_state_enter(struct sci_base_state_machine *sm) @@ -1661,7 +1661,7 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost ihost->oem_parameters.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; /* Default to APC mode. */ - ihost->oem_parameters.controller.max_concurrent_dev_spin_up = 1; + ihost->oem_parameters.controller.max_concurr_spin_up = 1; /* Default to no SSC operation. */ ihost->oem_parameters.controller.do_enable_ssc = false; @@ -1787,7 +1787,8 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem) } else return -EINVAL; - if (oem->controller.max_concurrent_dev_spin_up > MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT) + if (oem->controller.max_concurr_spin_up > MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT || + oem->controller.max_concurr_spin_up < 1) return -EINVAL; return 0; @@ -1810,6 +1811,16 @@ static enum sci_status sci_oem_parameters_set(struct isci_host *ihost) return SCI_FAILURE_INVALID_STATE; } +static u8 max_spin_up(struct isci_host *ihost) +{ + if (ihost->user_parameters.max_concurr_spinup) + return min_t(u8, ihost->user_parameters.max_concurr_spinup, + MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT); + else + return min_t(u8, ihost->oem_parameters.controller.max_concurr_spin_up, + MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT); +} + static void power_control_timeout(unsigned long data) { struct sci_timer *tmr = (struct sci_timer *)data; @@ -1839,8 +1850,7 @@ static void power_control_timeout(unsigned long data) if (iphy == NULL) continue; - if (ihost->power_control.phys_granted_power >= - ihost->oem_parameters.controller.max_concurrent_dev_spin_up) + if (ihost->power_control.phys_granted_power >= max_spin_up(ihost)) break; ihost->power_control.requesters[i] = NULL; @@ -1865,8 +1875,7 @@ void sci_controller_power_control_queue_insert(struct isci_host *ihost, { BUG_ON(iphy == NULL); - if (ihost->power_control.phys_granted_power < - ihost->oem_parameters.controller.max_concurrent_dev_spin_up) { + if (ihost->power_control.phys_granted_power < max_spin_up(ihost)) { ihost->power_control.phys_granted_power++; sci_phy_consume_power_handler(iphy); diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 43fe840fbe9c..a97edabcb85a 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -118,7 +118,7 @@ unsigned char phy_gen = 3; module_param(phy_gen, byte, 0); MODULE_PARM_DESC(phy_gen, "PHY generation (1: 1.5Gbps 2: 3.0Gbps 3: 6.0Gbps)"); -unsigned char max_concurr_spinup = 1; +unsigned char max_concurr_spinup; module_param(max_concurr_spinup, byte, 0); MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup"); diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c index 8e59c8865dcd..ac7f27749f97 100644 --- a/drivers/scsi/isci/port.c +++ b/drivers/scsi/isci/port.c @@ -145,48 +145,15 @@ static void sci_port_bcn_enable(struct isci_port *iport) } } -/* called under sci_lock to stabilize phy:port associations */ -void isci_port_bcn_enable(struct isci_host *ihost, struct isci_port *iport) -{ - int i; - - clear_bit(IPORT_BCN_BLOCKED, &iport->flags); - wake_up(&ihost->eventq); - - if (!test_and_clear_bit(IPORT_BCN_PENDING, &iport->flags)) - return; - - for (i = 0; i < ARRAY_SIZE(iport->phy_table); i++) { - struct isci_phy *iphy = iport->phy_table[i]; - - if (!iphy) - continue; - - ihost->sas_ha.notify_port_event(&iphy->sas_phy, - PORTE_BROADCAST_RCVD); - break; - } -} - static void isci_port_bc_change_received(struct isci_host *ihost, struct isci_port *iport, struct isci_phy *iphy) { - if (iport && test_bit(IPORT_BCN_BLOCKED, &iport->flags)) { - dev_dbg(&ihost->pdev->dev, - "%s: disabled BCN; isci_phy = %p, sas_phy = %p\n", - __func__, iphy, &iphy->sas_phy); - set_bit(IPORT_BCN_PENDING, &iport->flags); - atomic_inc(&iport->event); - wake_up(&ihost->eventq); - } else { - dev_dbg(&ihost->pdev->dev, - "%s: isci_phy = %p, sas_phy = %p\n", - __func__, iphy, &iphy->sas_phy); + dev_dbg(&ihost->pdev->dev, + "%s: isci_phy = %p, sas_phy = %p\n", + __func__, iphy, &iphy->sas_phy); - ihost->sas_ha.notify_port_event(&iphy->sas_phy, - PORTE_BROADCAST_RCVD); - } + ihost->sas_ha.notify_port_event(&iphy->sas_phy, PORTE_BROADCAST_RCVD); sci_port_bcn_enable(iport); } @@ -278,9 +245,6 @@ static void isci_port_link_down(struct isci_host *isci_host, /* check to see if this is the last phy on this port. */ if (isci_phy->sas_phy.port && isci_phy->sas_phy.port->num_phys == 1) { - atomic_inc(&isci_port->event); - isci_port_bcn_enable(isci_host, isci_port); - /* change the state for all devices on this port. The * next task sent to this device will be returned as * SAS_TASK_UNDELIVERED, and the scsi mid layer will @@ -350,6 +314,34 @@ static void isci_port_stop_complete(struct isci_host *ihost, dev_dbg(&ihost->pdev->dev, "Port stop complete\n"); } + +static bool is_port_ready_state(enum sci_port_states state) +{ + switch (state) { + case SCI_PORT_READY: + case SCI_PORT_SUB_WAITING: + case SCI_PORT_SUB_OPERATIONAL: + case SCI_PORT_SUB_CONFIGURING: + return true; + default: + return false; + } +} + +/* flag dummy rnc hanling when exiting a ready state */ +static void port_state_machine_change(struct isci_port *iport, + enum sci_port_states state) +{ + struct sci_base_state_machine *sm = &iport->sm; + enum sci_port_states old_state = sm->current_state_id; + + if (is_port_ready_state(old_state) && !is_port_ready_state(state)) + iport->ready_exit = true; + + sci_change_state(sm, state); + iport->ready_exit = false; +} + /** * isci_port_hard_reset_complete() - This function is called by the sci core * when the hard reset complete notification has been received. @@ -368,6 +360,26 @@ static void isci_port_hard_reset_complete(struct isci_port *isci_port, /* Save the status of the hard reset from the port. */ isci_port->hard_reset_status = completion_status; + if (completion_status != SCI_SUCCESS) { + + /* The reset failed. The port state is now SCI_PORT_FAILED. */ + if (isci_port->active_phy_mask == 0) { + + /* Generate the link down now to the host, since it + * was intercepted by the hard reset state machine when + * it really happened. + */ + isci_port_link_down(isci_port->isci_host, + &isci_port->isci_host->phys[ + isci_port->last_active_phy], + isci_port); + } + /* Advance the port state so that link state changes will be + * noticed. + */ + port_state_machine_change(isci_port, SCI_PORT_SUB_WAITING); + + } complete_all(&isci_port->hard_reset_complete); } @@ -657,6 +669,8 @@ void sci_port_deactivate_phy(struct isci_port *iport, struct isci_phy *iphy, struct isci_host *ihost = iport->owning_controller; iport->active_phy_mask &= ~(1 << iphy->phy_index); + if (!iport->active_phy_mask) + iport->last_active_phy = iphy->phy_index; iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; @@ -683,33 +697,6 @@ static void sci_port_invalid_link_up(struct isci_port *iport, struct isci_phy *i } } -static bool is_port_ready_state(enum sci_port_states state) -{ - switch (state) { - case SCI_PORT_READY: - case SCI_PORT_SUB_WAITING: - case SCI_PORT_SUB_OPERATIONAL: - case SCI_PORT_SUB_CONFIGURING: - return true; - default: - return false; - } -} - -/* flag dummy rnc hanling when exiting a ready state */ -static void port_state_machine_change(struct isci_port *iport, - enum sci_port_states state) -{ - struct sci_base_state_machine *sm = &iport->sm; - enum sci_port_states old_state = sm->current_state_id; - - if (is_port_ready_state(old_state) && !is_port_ready_state(state)) - iport->ready_exit = true; - - sci_change_state(sm, state); - iport->ready_exit = false; -} - /** * sci_port_general_link_up_handler - phy can be assigned to port? * @sci_port: sci_port object for which has a phy that has gone link up. @@ -1622,7 +1609,8 @@ void sci_port_construct(struct isci_port *iport, u8 index, iport->logical_port_index = SCIC_SDS_DUMMY_PORT; iport->physical_port_index = index; iport->active_phy_mask = 0; - iport->ready_exit = false; + iport->last_active_phy = 0; + iport->ready_exit = false; iport->owning_controller = ihost; @@ -1648,7 +1636,6 @@ void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index) init_completion(&iport->start_complete); iport->isci_host = ihost; isci_port_change_state(iport, isci_freed); - atomic_set(&iport->event, 0); } /** @@ -1676,7 +1663,7 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor { unsigned long flags; enum sci_status status; - int idx, ret = TMF_RESP_FUNC_COMPLETE; + int ret = TMF_RESP_FUNC_COMPLETE; dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n", __func__, iport); @@ -1697,8 +1684,13 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor "%s: iport = %p; hard reset completion\n", __func__, iport); - if (iport->hard_reset_status != SCI_SUCCESS) + if (iport->hard_reset_status != SCI_SUCCESS) { ret = TMF_RESP_FUNC_FAILED; + + dev_err(&ihost->pdev->dev, + "%s: iport = %p; hard reset failed (0x%x)\n", + __func__, iport, iport->hard_reset_status); + } } else { ret = TMF_RESP_FUNC_FAILED; @@ -1718,18 +1710,6 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor "%s: iport = %p; hard reset failed " "(0x%x) - driving explicit link fail for all phys\n", __func__, iport, iport->hard_reset_status); - - /* Down all phys in the port. */ - spin_lock_irqsave(&ihost->scic_lock, flags); - for (idx = 0; idx < SCI_MAX_PHYS; ++idx) { - struct isci_phy *iphy = iport->phy_table[idx]; - - if (!iphy) - continue; - sci_phy_stop(iphy); - sci_phy_start(iphy); - } - spin_unlock_irqrestore(&ihost->scic_lock, flags); } return ret; } diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h index b50ecd4e8f9c..cb5ffbc38603 100644 --- a/drivers/scsi/isci/port.h +++ b/drivers/scsi/isci/port.h @@ -77,7 +77,6 @@ enum isci_status { /** * struct isci_port - isci direct attached sas port object - * @event: counts bcns and port stop events (for bcn filtering) * @ready_exit: several states constitute 'ready'. When exiting ready we * need to take extra port-teardown actions that are * skipped when exiting to another 'ready' state. @@ -92,10 +91,6 @@ enum isci_status { */ struct isci_port { enum isci_status status; - #define IPORT_BCN_BLOCKED 0 - #define IPORT_BCN_PENDING 1 - unsigned long flags; - atomic_t event; struct isci_host *isci_host; struct asd_sas_port sas_port; struct list_head remote_dev_list; @@ -109,6 +104,7 @@ struct isci_port { u8 logical_port_index; u8 physical_port_index; u8 active_phy_mask; + u8 last_active_phy; u16 reserved_rni; u16 reserved_tag; u32 started_request_count; diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h index dc007e692f4e..2c75248ca326 100644 --- a/drivers/scsi/isci/probe_roms.h +++ b/drivers/scsi/isci/probe_roms.h @@ -112,7 +112,7 @@ struct sci_user_parameters { * This field specifies the maximum number of direct attached devices * that can have power supplied to them simultaneously. */ - u8 max_number_concurrent_device_spin_up; + u8 max_concurr_spinup; /** * This field specifies the number of seconds to allow a phy to consume @@ -219,7 +219,7 @@ struct sci_bios_oem_param_block_hdr { struct sci_oem_params { struct { uint8_t mode_type; - uint8_t max_concurrent_dev_spin_up; + uint8_t max_concurr_spin_up; uint8_t do_enable_ssc; uint8_t reserved; } controller; diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index fbf9ce28c3f5..b207cd3b15a0 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -1438,88 +1438,3 @@ int isci_remote_device_found(struct domain_device *domain_dev) return status == SCI_SUCCESS ? 0 : -ENODEV; } -/** - * isci_device_is_reset_pending() - This function will check if there is any - * pending reset condition on the device. - * @request: This parameter is the isci_device object. - * - * true if there is a reset pending for the device. - */ -bool isci_device_is_reset_pending( - struct isci_host *isci_host, - struct isci_remote_device *isci_device) -{ - struct isci_request *isci_request; - struct isci_request *tmp_req; - bool reset_is_pending = false; - unsigned long flags; - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_device = %p\n", __func__, isci_device); - - spin_lock_irqsave(&isci_host->scic_lock, flags); - - /* Check for reset on all pending requests. */ - list_for_each_entry_safe(isci_request, tmp_req, - &isci_device->reqs_in_process, dev_node) { - dev_dbg(&isci_host->pdev->dev, - "%s: isci_device = %p request = %p\n", - __func__, isci_device, isci_request); - - if (isci_request->ttype == io_task) { - struct sas_task *task = isci_request_access_task( - isci_request); - - spin_lock(&task->task_state_lock); - if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) - reset_is_pending = true; - spin_unlock(&task->task_state_lock); - } - } - - spin_unlock_irqrestore(&isci_host->scic_lock, flags); - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_device = %p reset_is_pending = %d\n", - __func__, isci_device, reset_is_pending); - - return reset_is_pending; -} - -/** - * isci_device_clear_reset_pending() - This function will clear if any pending - * reset condition flags on the device. - * @request: This parameter is the isci_device object. - * - * true if there is a reset pending for the device. - */ -void isci_device_clear_reset_pending(struct isci_host *ihost, struct isci_remote_device *idev) -{ - struct isci_request *isci_request; - struct isci_request *tmp_req; - unsigned long flags = 0; - - dev_dbg(&ihost->pdev->dev, "%s: idev=%p, ihost=%p\n", - __func__, idev, ihost); - - spin_lock_irqsave(&ihost->scic_lock, flags); - - /* Clear reset pending on all pending requests. */ - list_for_each_entry_safe(isci_request, tmp_req, - &idev->reqs_in_process, dev_node) { - dev_dbg(&ihost->pdev->dev, "%s: idev = %p request = %p\n", - __func__, idev, isci_request); - - if (isci_request->ttype == io_task) { - - unsigned long flags2; - struct sas_task *task = isci_request_access_task( - isci_request); - - spin_lock_irqsave(&task->task_state_lock, flags2); - task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET; - spin_unlock_irqrestore(&task->task_state_lock, flags2); - } - } - spin_unlock_irqrestore(&ihost->scic_lock, flags); -} diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h index e1747ea0d0ea..483ee50152f3 100644 --- a/drivers/scsi/isci/remote_device.h +++ b/drivers/scsi/isci/remote_device.h @@ -132,10 +132,7 @@ void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remote_device *idev); void isci_remote_device_gone(struct domain_device *domain_dev); int isci_remote_device_found(struct domain_device *domain_dev); -bool isci_device_is_reset_pending(struct isci_host *ihost, - struct isci_remote_device *idev); -void isci_device_clear_reset_pending(struct isci_host *ihost, - struct isci_remote_device *idev); + /** * sci_remote_device_stop() - This method will stop both transmission and * reception of link activity for the supplied remote device. This method diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 565a9f0a9bc2..192cb48d849a 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -191,7 +191,7 @@ static void sci_task_request_build_ssp_task_iu(struct isci_request *ireq) task_iu->task_func = isci_tmf->tmf_code; task_iu->task_tag = - (ireq->ttype == tmf_task) ? + (test_bit(IREQ_TMF, &ireq->flags)) ? isci_tmf->io_tag : SCI_CONTROLLER_INVALID_IO_TAG; } @@ -516,7 +516,7 @@ sci_io_request_construct_sata(struct isci_request *ireq, struct domain_device *dev = ireq->target_device->domain_dev; /* check for management protocols */ - if (ireq->ttype == tmf_task) { + if (test_bit(IREQ_TMF, &ireq->flags)) { struct isci_tmf *tmf = isci_request_access_tmf(ireq); if (tmf->tmf_code == isci_tmf_sata_srst_high || @@ -632,7 +632,7 @@ enum sci_status sci_task_request_construct_sata(struct isci_request *ireq) enum sci_status status = SCI_SUCCESS; /* check for management protocols */ - if (ireq->ttype == tmf_task) { + if (test_bit(IREQ_TMF, &ireq->flags)) { struct isci_tmf *tmf = isci_request_access_tmf(ireq); if (tmf->tmf_code == isci_tmf_sata_srst_high || @@ -2630,14 +2630,8 @@ static void isci_task_save_for_upper_layer_completion( switch (task_notification_selection) { case isci_perform_normal_io_completion: - /* Normal notification (task_done) */ - dev_dbg(&host->pdev->dev, - "%s: Normal - task = %p, response=%d (%d), status=%d (%d)\n", - __func__, - task, - task->task_status.resp, response, - task->task_status.stat, status); + /* Add to the completed list. */ list_add(&request->completed_node, &host->requests_to_complete); @@ -2650,13 +2644,6 @@ static void isci_task_save_for_upper_layer_completion( /* No notification to libsas because this request is * already in the abort path. */ - dev_dbg(&host->pdev->dev, - "%s: Aborted - task = %p, response=%d (%d), status=%d (%d)\n", - __func__, - task, - task->task_status.resp, response, - task->task_status.stat, status); - /* Wake up whatever process was waiting for this * request to complete. */ @@ -2673,30 +2660,22 @@ static void isci_task_save_for_upper_layer_completion( case isci_perform_error_io_completion: /* Use sas_task_abort */ - dev_dbg(&host->pdev->dev, - "%s: Error - task = %p, response=%d (%d), status=%d (%d)\n", - __func__, - task, - task->task_status.resp, response, - task->task_status.stat, status); /* Add to the aborted list. */ list_add(&request->completed_node, &host->requests_to_errorback); break; default: - dev_dbg(&host->pdev->dev, - "%s: Unknown - task = %p, response=%d (%d), status=%d (%d)\n", - __func__, - task, - task->task_status.resp, response, - task->task_status.stat, status); - /* Add to the error to libsas list. */ list_add(&request->completed_node, &host->requests_to_errorback); break; } + dev_dbg(&host->pdev->dev, + "%s: %d - task = %p, response=%d (%d), status=%d (%d)\n", + __func__, task_notification_selection, task, + (task) ? task->task_status.resp : 0, response, + (task) ? task->task_status.stat : 0, status); } static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis) @@ -2728,9 +2707,9 @@ static void isci_request_io_request_complete(struct isci_host *ihost, struct sas_task *task = isci_request_access_task(request); struct ssp_response_iu *resp_iu; unsigned long task_flags; - struct isci_remote_device *idev = isci_lookup_device(task->dev); - enum service_response response = SAS_TASK_UNDELIVERED; - enum exec_status status = SAS_ABORTED_TASK; + struct isci_remote_device *idev = request->target_device; + enum service_response response = SAS_TASK_UNDELIVERED; + enum exec_status status = SAS_ABORTED_TASK; enum isci_request_status request_status; enum isci_completion_selection complete_to_host = isci_perform_normal_io_completion; @@ -3061,7 +3040,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost, /* complete the io request to the core. */ sci_controller_complete_io(ihost, request->target_device, request); - isci_put_device(idev); /* set terminated handle so it cannot be completed or * terminated again, and to cause any calls into abort @@ -3080,7 +3058,7 @@ static void sci_request_started_state_enter(struct sci_base_state_machine *sm) /* XXX as hch said always creating an internal sas_task for tmf * requests would simplify the driver */ - task = ireq->ttype == io_task ? isci_request_access_task(ireq) : NULL; + task = (test_bit(IREQ_TMF, &ireq->flags)) ? NULL : isci_request_access_task(ireq); /* all unaccelerated request types (non ssp or ncq) handled with * substates @@ -3564,7 +3542,7 @@ static struct isci_request *isci_io_request_from_tag(struct isci_host *ihost, ireq = isci_request_from_tag(ihost, tag); ireq->ttype_ptr.io_task_ptr = task; - ireq->ttype = io_task; + clear_bit(IREQ_TMF, &ireq->flags); task->lldd_task = ireq; return ireq; @@ -3578,7 +3556,7 @@ struct isci_request *isci_tmf_request_from_tag(struct isci_host *ihost, ireq = isci_request_from_tag(ihost, tag); ireq->ttype_ptr.tmf_task_ptr = isci_tmf; - ireq->ttype = tmf_task; + set_bit(IREQ_TMF, &ireq->flags); return ireq; } diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h index f720b97b7bb5..be38933dd6df 100644 --- a/drivers/scsi/isci/request.h +++ b/drivers/scsi/isci/request.h @@ -77,11 +77,6 @@ enum isci_request_status { dead = 0x07 }; -enum task_type { - io_task = 0, - tmf_task = 1 -}; - enum sci_request_protocol { SCIC_NO_PROTOCOL, SCIC_SMP_PROTOCOL, @@ -116,7 +111,6 @@ struct isci_request { #define IREQ_ACTIVE 3 unsigned long flags; /* XXX kill ttype and ttype_ptr, allocate full sas_task */ - enum task_type ttype; union ttype_ptr_union { struct sas_task *io_task_ptr; /* When ttype==io_task */ struct isci_tmf *tmf_task_ptr; /* When ttype==tmf_task */ diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index e2d9418683ce..66ad3dc89498 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -212,16 +212,27 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&task->task_state_lock, flags); - /* Indicate QUEUE_FULL so that the scsi - * midlayer retries. if the request - * failed for remote device reasons, - * it gets returned as - * SAS_TASK_UNDELIVERED next time - * through. - */ - isci_task_refuse(ihost, task, - SAS_TASK_COMPLETE, - SAS_QUEUE_FULL); + if (test_bit(IDEV_GONE, &idev->flags)) { + + /* Indicate that the device + * is gone. + */ + isci_task_refuse(ihost, task, + SAS_TASK_UNDELIVERED, + SAS_DEVICE_UNKNOWN); + } else { + /* Indicate QUEUE_FULL so that + * the scsi midlayer retries. + * If the request failed for + * remote device reasons, it + * gets returned as + * SAS_TASK_UNDELIVERED next + * time through. + */ + isci_task_refuse(ihost, task, + SAS_TASK_COMPLETE, + SAS_QUEUE_FULL); + } } } } @@ -243,7 +254,7 @@ static enum sci_status isci_sata_management_task_request_build(struct isci_reque struct isci_tmf *isci_tmf; enum sci_status status; - if (tmf_task != ireq->ttype) + if (!test_bit(IREQ_TMF, &ireq->flags)) return SCI_FAILURE; isci_tmf = isci_request_access_tmf(ireq); @@ -327,6 +338,60 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, return ireq; } +/** +* isci_request_mark_zombie() - This function must be called with scic_lock held. +*/ +static void isci_request_mark_zombie(struct isci_host *ihost, struct isci_request *ireq) +{ + struct completion *tmf_completion = NULL; + struct completion *req_completion; + + /* Set the request state to "dead". */ + ireq->status = dead; + + req_completion = ireq->io_request_completion; + ireq->io_request_completion = NULL; + + if (test_bit(IREQ_TMF, &ireq->flags)) { + /* Break links with the TMF request. */ + struct isci_tmf *tmf = isci_request_access_tmf(ireq); + + /* In the case where a task request is dying, + * the thread waiting on the complete will sit and + * timeout unless we wake it now. Since the TMF + * has a default error status, complete it here + * to wake the waiting thread. + */ + if (tmf) { + tmf_completion = tmf->complete; + tmf->complete = NULL; + } + ireq->ttype_ptr.tmf_task_ptr = NULL; + dev_dbg(&ihost->pdev->dev, "%s: tmf_code %d, managed tag %#x\n", + __func__, tmf->tmf_code, tmf->io_tag); + } else { + /* Break links with the sas_task - the callback is done + * elsewhere. + */ + struct sas_task *task = isci_request_access_task(ireq); + + if (task) + task->lldd_task = NULL; + + ireq->ttype_ptr.io_task_ptr = NULL; + } + + dev_warn(&ihost->pdev->dev, "task context unrecoverable (tag: %#x)\n", + ireq->io_tag); + + /* Don't force waiting threads to timeout. */ + if (req_completion) + complete(req_completion); + + if (tmf_completion != NULL) + complete(tmf_completion); +} + static int isci_task_execute_tmf(struct isci_host *ihost, struct isci_remote_device *idev, struct isci_tmf *tmf, unsigned long timeout_ms) @@ -364,6 +429,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost, /* Assign the pointer to the TMF's completion kernel wait structure. */ tmf->complete = &completion; + tmf->status = SCI_FAILURE_TIMEOUT; ireq = isci_task_request_build(ihost, idev, tag, tmf); if (!ireq) @@ -399,18 +465,35 @@ static int isci_task_execute_tmf(struct isci_host *ihost, msecs_to_jiffies(timeout_ms)); if (timeleft == 0) { + /* The TMF did not complete - this could be because + * of an unplug. Terminate the TMF request now. + */ spin_lock_irqsave(&ihost->scic_lock, flags); if (tmf->cb_state_func != NULL) - tmf->cb_state_func(isci_tmf_timed_out, tmf, tmf->cb_data); + tmf->cb_state_func(isci_tmf_timed_out, tmf, + tmf->cb_data); - sci_controller_terminate_request(ihost, - idev, - ireq); + sci_controller_terminate_request(ihost, idev, ireq); spin_unlock_irqrestore(&ihost->scic_lock, flags); - wait_for_completion(tmf->complete); + timeleft = wait_for_completion_timeout( + &completion, + msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC)); + + if (!timeleft) { + /* Strange condition - the termination of the TMF + * request timed-out. + */ + spin_lock_irqsave(&ihost->scic_lock, flags); + + /* If the TMF status has not changed, kill it. */ + if (tmf->status == SCI_FAILURE_TIMEOUT) + isci_request_mark_zombie(ihost, ireq); + + spin_unlock_irqrestore(&ihost->scic_lock, flags); + } } isci_print_tmf(tmf); @@ -501,48 +584,17 @@ static enum isci_request_status isci_task_validate_request_to_abort( return old_state; } -/** -* isci_request_cleanup_completed_loiterer() - This function will take care of -* the final cleanup on any request which has been explicitly terminated. -* @isci_host: This parameter specifies the ISCI host object -* @isci_device: This is the device to which the request is pending. -* @isci_request: This parameter specifies the terminated request object. -* @task: This parameter is the libsas I/O request. -*/ -static void isci_request_cleanup_completed_loiterer( - struct isci_host *isci_host, - struct isci_remote_device *isci_device, - struct isci_request *isci_request, - struct sas_task *task) +static int isci_request_is_dealloc_managed(enum isci_request_status stat) { - unsigned long flags; - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_device=%p, request=%p, task=%p\n", - __func__, isci_device, isci_request, task); - - if (task != NULL) { - - spin_lock_irqsave(&task->task_state_lock, flags); - task->lldd_task = NULL; - - task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET; - - isci_set_task_doneflags(task); - - /* If this task is not in the abort path, call task_done. */ - if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - - spin_unlock_irqrestore(&task->task_state_lock, flags); - task->task_done(task); - } else - spin_unlock_irqrestore(&task->task_state_lock, flags); - } - - if (isci_request != NULL) { - spin_lock_irqsave(&isci_host->scic_lock, flags); - list_del_init(&isci_request->dev_node); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + switch (stat) { + case aborted: + case aborting: + case terminating: + case completed: + case dead: + return true; + default: + return false; } } @@ -563,11 +615,9 @@ static void isci_terminate_request_core(struct isci_host *ihost, enum sci_status status = SCI_SUCCESS; bool was_terminated = false; bool needs_cleanup_handling = false; - enum isci_request_status request_status; unsigned long flags; unsigned long termination_completed = 1; struct completion *io_request_completion; - struct sas_task *task; dev_dbg(&ihost->pdev->dev, "%s: device = %p; request = %p\n", @@ -577,10 +627,6 @@ static void isci_terminate_request_core(struct isci_host *ihost, io_request_completion = isci_request->io_request_completion; - task = (isci_request->ttype == io_task) - ? isci_request_access_task(isci_request) - : NULL; - /* Note that we are not going to control * the target to abort the request. */ @@ -619,42 +665,27 @@ static void isci_terminate_request_core(struct isci_host *ihost, __func__, isci_request, io_request_completion); /* Wait here for the request to complete. */ - #define TERMINATION_TIMEOUT_MSEC 500 termination_completed = wait_for_completion_timeout( io_request_completion, - msecs_to_jiffies(TERMINATION_TIMEOUT_MSEC)); + msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC)); if (!termination_completed) { /* The request to terminate has timed out. */ - spin_lock_irqsave(&ihost->scic_lock, - flags); + spin_lock_irqsave(&ihost->scic_lock, flags); /* Check for state changes. */ - if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) { + if (!test_bit(IREQ_TERMINATED, + &isci_request->flags)) { /* The best we can do is to have the * request die a silent death if it * ever really completes. - * - * Set the request state to "dead", - * and clear the task pointer so that - * an actual completion event callback - * doesn't do anything. */ - isci_request->status = dead; - isci_request->io_request_completion - = NULL; - - if (isci_request->ttype == io_task) { - - /* Break links with the - * sas_task. - */ - isci_request->ttype_ptr.io_task_ptr - = NULL; - } + isci_request_mark_zombie(ihost, + isci_request); + needs_cleanup_handling = true; } else termination_completed = 1; @@ -691,29 +722,28 @@ static void isci_terminate_request_core(struct isci_host *ihost, * needs to be detached and freed here. */ spin_lock_irqsave(&isci_request->state_lock, flags); - request_status = isci_request->status; - - if ((isci_request->ttype == io_task) /* TMFs are in their own thread */ - && ((request_status == aborted) - || (request_status == aborting) - || (request_status == terminating) - || (request_status == completed) - || (request_status == dead) - ) - ) { - - /* The completion routine won't free a request in - * the aborted/aborting/etc. states, so we do - * it here. - */ - needs_cleanup_handling = true; - } + + needs_cleanup_handling + = isci_request_is_dealloc_managed( + isci_request->status); + spin_unlock_irqrestore(&isci_request->state_lock, flags); } - if (needs_cleanup_handling) - isci_request_cleanup_completed_loiterer( - ihost, idev, isci_request, task); + if (needs_cleanup_handling) { + + dev_dbg(&ihost->pdev->dev, + "%s: cleanup isci_device=%p, request=%p\n", + __func__, idev, isci_request); + + if (isci_request != NULL) { + spin_lock_irqsave(&ihost->scic_lock, flags); + isci_free_tag(ihost, isci_request->io_tag); + isci_request_change_state(isci_request, unallocated); + list_del_init(&isci_request->dev_node); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + } + } } } @@ -772,7 +802,9 @@ void isci_terminate_pending_requests(struct isci_host *ihost, dev_dbg(&ihost->pdev->dev, "%s: idev=%p request=%p; task=%p old_state=%d\n", __func__, idev, ireq, - ireq->ttype == io_task ? isci_request_access_task(ireq) : NULL, + (!test_bit(IREQ_TMF, &ireq->flags) + ? isci_request_access_task(ireq) + : NULL), old_state); /* If the old_state is started: @@ -889,22 +921,14 @@ int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun) "%s: domain_device=%p, isci_host=%p; isci_device=%p\n", __func__, domain_device, isci_host, isci_device); - if (isci_device) - set_bit(IDEV_EH, &isci_device->flags); + if (!isci_device) { + /* If the device is gone, stop the escalations. */ + dev_dbg(&isci_host->pdev->dev, "%s: No dev\n", __func__); - /* If there is a device reset pending on any request in the - * device's list, fail this LUN reset request in order to - * escalate to the device reset. - */ - if (!isci_device || - isci_device_is_reset_pending(isci_host, isci_device)) { - dev_dbg(&isci_host->pdev->dev, - "%s: No dev (%p), or " - "RESET PENDING: domain_device=%p\n", - __func__, isci_device, domain_device); - ret = TMF_RESP_FUNC_FAILED; + ret = TMF_RESP_FUNC_COMPLETE; goto out; } + set_bit(IDEV_EH, &isci_device->flags); /* Send the task management part of the reset. */ if (sas_protocol_ata(domain_device->tproto)) { @@ -1013,7 +1037,7 @@ int isci_task_abort_task(struct sas_task *task) struct isci_tmf tmf; int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; - bool any_dev_reset = false; + int perform_termination = 0; /* Get the isci_request reference from the task. Note that * this check does not depend on the pending request list @@ -1035,89 +1059,34 @@ int isci_task_abort_task(struct sas_task *task) spin_unlock_irqrestore(&isci_host->scic_lock, flags); dev_dbg(&isci_host->pdev->dev, - "%s: task = %p\n", __func__, task); - - if (!isci_device || !old_request) - goto out; - - set_bit(IDEV_EH, &isci_device->flags); - - /* This version of the driver will fail abort requests for - * SATA/STP. Failing the abort request this way will cause the - * SCSI error handler thread to escalate to LUN reset - */ - if (sas_protocol_ata(task->task_proto)) { - dev_dbg(&isci_host->pdev->dev, - " task %p is for a STP/SATA device;" - " returning TMF_RESP_FUNC_FAILED\n" - " to cause a LUN reset...\n", task); - goto out; - } + "%s: dev = %p, task = %p, old_request == %p\n", + __func__, isci_device, task, old_request); - dev_dbg(&isci_host->pdev->dev, - "%s: old_request == %p\n", __func__, old_request); - - any_dev_reset = isci_device_is_reset_pending(isci_host, isci_device); - - spin_lock_irqsave(&task->task_state_lock, flags); - - any_dev_reset = any_dev_reset || (task->task_state_flags & SAS_TASK_NEED_DEV_RESET); + if (isci_device) + set_bit(IDEV_EH, &isci_device->flags); - /* If the extraction of the request reference from the task - * failed, then the request has been completed (or if there is a - * pending reset then this abort request function must be failed - * in order to escalate to the target reset). + /* Device reset conditions signalled in task_state_flags are the + * responsbility of libsas to observe at the start of the error + * handler thread. */ - if ((old_request == NULL) || any_dev_reset) { - - /* If the device reset task flag is set, fail the task - * management request. Otherwise, the original request - * has completed. - */ - if (any_dev_reset) { - - /* Turn off the task's DONE to make sure this - * task is escalated to a target reset. - */ - task->task_state_flags &= ~SAS_TASK_STATE_DONE; - - /* Make the reset happen as soon as possible. */ - task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; - - spin_unlock_irqrestore(&task->task_state_lock, flags); - - /* Fail the task management request in order to - * escalate to the target reset. - */ - ret = TMF_RESP_FUNC_FAILED; - - dev_dbg(&isci_host->pdev->dev, - "%s: Failing task abort in order to " - "escalate to target reset because\n" - "SAS_TASK_NEED_DEV_RESET is set for " - "task %p on dev %p\n", - __func__, task, isci_device); - - - } else { - /* The request has already completed and there - * is nothing to do here other than to set the task - * done bit, and indicate that the task abort function - * was sucessful. - */ - isci_set_task_doneflags(task); - - spin_unlock_irqrestore(&task->task_state_lock, flags); + if (!isci_device || !old_request) { + /* The request has already completed and there + * is nothing to do here other than to set the task + * done bit, and indicate that the task abort function + * was sucessful. + */ + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags |= SAS_TASK_STATE_DONE; + task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | + SAS_TASK_STATE_PENDING); + spin_unlock_irqrestore(&task->task_state_lock, flags); - ret = TMF_RESP_FUNC_COMPLETE; + ret = TMF_RESP_FUNC_COMPLETE; - dev_dbg(&isci_host->pdev->dev, - "%s: abort task not needed for %p\n", - __func__, task); - } + dev_dbg(&isci_host->pdev->dev, + "%s: abort task not needed for %p\n", + __func__, task); goto out; - } else { - spin_unlock_irqrestore(&task->task_state_lock, flags); } spin_lock_irqsave(&isci_host->scic_lock, flags); @@ -1146,24 +1115,44 @@ int isci_task_abort_task(struct sas_task *task) goto out; } if (task->task_proto == SAS_PROTOCOL_SMP || + sas_protocol_ata(task->task_proto) || test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { spin_unlock_irqrestore(&isci_host->scic_lock, flags); dev_dbg(&isci_host->pdev->dev, - "%s: SMP request (%d)" + "%s: %s request" " or complete_in_target (%d), thus no TMF\n", - __func__, (task->task_proto == SAS_PROTOCOL_SMP), + __func__, + ((task->task_proto == SAS_PROTOCOL_SMP) + ? "SMP" + : (sas_protocol_ata(task->task_proto) + ? "SATA/STP" + : "<other>") + ), test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)); - /* Set the state on the task. */ - isci_task_all_done(task); - - ret = TMF_RESP_FUNC_COMPLETE; + if (test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags |= SAS_TASK_STATE_DONE; + task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | + SAS_TASK_STATE_PENDING); + spin_unlock_irqrestore(&task->task_state_lock, flags); + ret = TMF_RESP_FUNC_COMPLETE; + } else { + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | + SAS_TASK_STATE_PENDING); + spin_unlock_irqrestore(&task->task_state_lock, flags); + } - /* Stopping and SMP devices are not sent a TMF, and are not - * reset, but the outstanding I/O request is terminated below. + /* STP and SMP devices are not sent a TMF, but the + * outstanding I/O request is terminated below. This is + * because SATA/STP and SMP discovery path timeouts directly + * call the abort task interface for cleanup. */ + perform_termination = 1; + } else { /* Fill in the tmf stucture */ isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort, @@ -1172,22 +1161,24 @@ int isci_task_abort_task(struct sas_task *task) spin_unlock_irqrestore(&isci_host->scic_lock, flags); - #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* half second timeout. */ + #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */ ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, ISCI_ABORT_TASK_TIMEOUT_MS); - if (ret != TMF_RESP_FUNC_COMPLETE) + if (ret == TMF_RESP_FUNC_COMPLETE) + perform_termination = 1; + else dev_dbg(&isci_host->pdev->dev, - "%s: isci_task_send_tmf failed\n", - __func__); + "%s: isci_task_send_tmf failed\n", __func__); } - if (ret == TMF_RESP_FUNC_COMPLETE) { + if (perform_termination) { set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags); /* Clean up the request on our side, and wait for the aborted * I/O to complete. */ - isci_terminate_request_core(isci_host, isci_device, old_request); + isci_terminate_request_core(isci_host, isci_device, + old_request); } /* Make sure we do not leave a reference to aborted_io_completion */ @@ -1288,7 +1279,8 @@ isci_task_request_complete(struct isci_host *ihost, enum sci_task_status completion_status) { struct isci_tmf *tmf = isci_request_access_tmf(ireq); - struct completion *tmf_complete; + struct completion *tmf_complete = NULL; + struct completion *request_complete = ireq->io_request_completion; dev_dbg(&ihost->pdev->dev, "%s: request = %p, status=%d\n", @@ -1296,255 +1288,53 @@ isci_task_request_complete(struct isci_host *ihost, isci_request_change_state(ireq, completed); - tmf->status = completion_status; set_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags); - if (tmf->proto == SAS_PROTOCOL_SSP) { - memcpy(&tmf->resp.resp_iu, - &ireq->ssp.rsp, - SSP_RESP_IU_MAX_SIZE); - } else if (tmf->proto == SAS_PROTOCOL_SATA) { - memcpy(&tmf->resp.d2h_fis, - &ireq->stp.rsp, - sizeof(struct dev_to_host_fis)); + if (tmf) { + tmf->status = completion_status; + + if (tmf->proto == SAS_PROTOCOL_SSP) { + memcpy(&tmf->resp.resp_iu, + &ireq->ssp.rsp, + SSP_RESP_IU_MAX_SIZE); + } else if (tmf->proto == SAS_PROTOCOL_SATA) { + memcpy(&tmf->resp.d2h_fis, + &ireq->stp.rsp, + sizeof(struct dev_to_host_fis)); + } + /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ + tmf_complete = tmf->complete; } - - /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ - tmf_complete = tmf->complete; - sci_controller_complete_io(ihost, ireq->target_device, ireq); /* set the 'terminated' flag handle to make sure it cannot be terminated * or completed again. */ set_bit(IREQ_TERMINATED, &ireq->flags); - isci_request_change_state(ireq, unallocated); - list_del_init(&ireq->dev_node); - - /* The task management part completes last. */ - complete(tmf_complete); -} - -static void isci_smp_task_timedout(unsigned long _task) -{ - struct sas_task *task = (void *) _task; - unsigned long flags; - - spin_lock_irqsave(&task->task_state_lock, flags); - 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); - - complete(&task->completion); -} - -static void isci_smp_task_done(struct sas_task *task) -{ - if (!del_timer(&task->timer)) - return; - complete(&task->completion); -} - -static int isci_smp_execute_task(struct isci_host *ihost, - struct domain_device *dev, void *req, - int req_size, void *resp, int resp_size) -{ - int res, retry; - struct sas_task *task = NULL; - - for (retry = 0; retry < 3; retry++) { - task = sas_alloc_task(GFP_KERNEL); - if (!task) - return -ENOMEM; - - task->dev = dev; - task->task_proto = dev->tproto; - sg_init_one(&task->smp_task.smp_req, req, req_size); - sg_init_one(&task->smp_task.smp_resp, resp, resp_size); - - task->task_done = isci_smp_task_done; - - task->timer.data = (unsigned long) task; - task->timer.function = isci_smp_task_timedout; - task->timer.expires = jiffies + 10*HZ; - add_timer(&task->timer); - - res = isci_task_execute_task(task, 1, GFP_KERNEL); - - if (res) { - del_timer(&task->timer); - dev_dbg(&ihost->pdev->dev, - "%s: executing SMP task failed:%d\n", - __func__, res); - goto ex_err; - } - - wait_for_completion(&task->completion); - res = -ECOMM; - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - dev_dbg(&ihost->pdev->dev, - "%s: smp task timed out or aborted\n", - __func__); - isci_task_abort_task(task); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - dev_dbg(&ihost->pdev->dev, - "%s: SMP task aborted and not done\n", - __func__); - goto ex_err; - } - } - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_STAT_GOOD) { - res = 0; - break; - } - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_UNDERRUN) { - /* no error, but return the number of bytes of - * underrun */ - res = task->task_status.residual; - break; - } - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_OVERRUN) { - res = -EMSGSIZE; - break; - } else { - dev_dbg(&ihost->pdev->dev, - "%s: task to dev %016llx response: 0x%x " - "status 0x%x\n", __func__, - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat); - sas_free_task(task); - task = NULL; - } - } -ex_err: - BUG_ON(retry == 3 && task != NULL); - sas_free_task(task); - return res; -} - -#define DISCOVER_REQ_SIZE 16 -#define DISCOVER_RESP_SIZE 56 - -int isci_smp_get_phy_attached_dev_type(struct isci_host *ihost, - struct domain_device *dev, - int phy_id, int *adt) -{ - struct smp_resp *disc_resp; - u8 *disc_req; - int res; - - disc_resp = kzalloc(DISCOVER_RESP_SIZE, GFP_KERNEL); - if (!disc_resp) - return -ENOMEM; - - disc_req = kzalloc(DISCOVER_REQ_SIZE, GFP_KERNEL); - if (disc_req) { - disc_req[0] = SMP_REQUEST; - disc_req[1] = SMP_DISCOVER; - disc_req[9] = phy_id; - } else { - kfree(disc_resp); - return -ENOMEM; - } - res = isci_smp_execute_task(ihost, dev, disc_req, DISCOVER_REQ_SIZE, - disc_resp, DISCOVER_RESP_SIZE); - if (!res) { - if (disc_resp->result != SMP_RESP_FUNC_ACC) - res = disc_resp->result; - else - *adt = disc_resp->disc.attached_dev_type; + /* As soon as something is in the terminate path, deallocation is + * managed there. Note that the final non-managed state of a task + * request is "completed". + */ + if ((ireq->status == completed) || + !isci_request_is_dealloc_managed(ireq->status)) { + isci_request_change_state(ireq, unallocated); + isci_free_tag(ihost, ireq->io_tag); + list_del_init(&ireq->dev_node); } - kfree(disc_req); - kfree(disc_resp); - - return res; -} - -static void isci_wait_for_smp_phy_reset(struct isci_remote_device *idev, int phy_num) -{ - struct domain_device *dev = idev->domain_dev; - struct isci_port *iport = idev->isci_port; - struct isci_host *ihost = iport->isci_host; - int res, iteration = 0, attached_device_type; - #define STP_WAIT_MSECS 25000 - unsigned long tmo = msecs_to_jiffies(STP_WAIT_MSECS); - unsigned long deadline = jiffies + tmo; - enum { - SMP_PHYWAIT_PHYDOWN, - SMP_PHYWAIT_PHYUP, - SMP_PHYWAIT_DONE - } phy_state = SMP_PHYWAIT_PHYDOWN; - - /* While there is time, wait for the phy to go away and come back */ - while (time_is_after_jiffies(deadline) && phy_state != SMP_PHYWAIT_DONE) { - int event = atomic_read(&iport->event); - - ++iteration; - - tmo = wait_event_timeout(ihost->eventq, - event != atomic_read(&iport->event) || - !test_bit(IPORT_BCN_BLOCKED, &iport->flags), - tmo); - /* link down, stop polling */ - if (!test_bit(IPORT_BCN_BLOCKED, &iport->flags)) - break; - dev_dbg(&ihost->pdev->dev, - "%s: iport %p, iteration %d," - " phase %d: time_remaining %lu, bcns = %d\n", - __func__, iport, iteration, phy_state, - tmo, test_bit(IPORT_BCN_PENDING, &iport->flags)); - - res = isci_smp_get_phy_attached_dev_type(ihost, dev, phy_num, - &attached_device_type); - tmo = deadline - jiffies; - - if (res) { - dev_dbg(&ihost->pdev->dev, - "%s: iteration %d, phase %d:" - " SMP error=%d, time_remaining=%lu\n", - __func__, iteration, phy_state, res, tmo); - break; - } - dev_dbg(&ihost->pdev->dev, - "%s: iport %p, iteration %d," - " phase %d: time_remaining %lu, bcns = %d, " - "attdevtype = %x\n", - __func__, iport, iteration, phy_state, - tmo, test_bit(IPORT_BCN_PENDING, &iport->flags), - attached_device_type); - - switch (phy_state) { - case SMP_PHYWAIT_PHYDOWN: - /* Has the device gone away? */ - if (!attached_device_type) - phy_state = SMP_PHYWAIT_PHYUP; - - break; - - case SMP_PHYWAIT_PHYUP: - /* Has the device come back? */ - if (attached_device_type) - phy_state = SMP_PHYWAIT_DONE; - break; - - case SMP_PHYWAIT_DONE: - break; - } + /* "request_complete" is set if the task was being terminated. */ + if (request_complete) + complete(request_complete); - } - dev_dbg(&ihost->pdev->dev, "%s: done\n", __func__); + /* The task management part completes last. */ + if (tmf_complete) + complete(tmf_complete); } static int isci_reset_device(struct isci_host *ihost, struct isci_remote_device *idev) { struct sas_phy *phy = sas_find_local_phy(idev->domain_dev); - struct isci_port *iport = idev->isci_port; enum sci_status status; unsigned long flags; int rc; @@ -1564,13 +1354,6 @@ static int isci_reset_device(struct isci_host *ihost, } spin_unlock_irqrestore(&ihost->scic_lock, flags); - /* Make sure all pending requests are able to be fully terminated. */ - isci_device_clear_reset_pending(ihost, idev); - - /* If this is a device on an expander, disable BCN processing. */ - if (!scsi_is_sas_phy_local(phy)) - set_bit(IPORT_BCN_BLOCKED, &iport->flags); - rc = sas_phy_reset(phy, true); /* Terminate in-progress I/O now. */ @@ -1581,21 +1364,6 @@ static int isci_reset_device(struct isci_host *ihost, status = sci_remote_device_reset_complete(idev); spin_unlock_irqrestore(&ihost->scic_lock, flags); - /* If this is a device on an expander, bring the phy back up. */ - if (!scsi_is_sas_phy_local(phy)) { - /* A phy reset will cause the device to go away then reappear. - * Since libsas will take action on incoming BCNs (eg. remove - * a device going through an SMP phy-control driven reset), - * we need to wait until the phy comes back up before letting - * discovery proceed in libsas. - */ - isci_wait_for_smp_phy_reset(idev, phy->number); - - spin_lock_irqsave(&ihost->scic_lock, flags); - isci_port_bcn_enable(ihost, idev->isci_port); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - } - if (status != SCI_SUCCESS) { dev_dbg(&ihost->pdev->dev, "%s: sci_remote_device_reset_complete(%p) " diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h index 15b18d158993..bc78c0a41d5c 100644 --- a/drivers/scsi/isci/task.h +++ b/drivers/scsi/isci/task.h @@ -58,6 +58,8 @@ #include <scsi/sas_ata.h> #include "host.h" +#define ISCI_TERMINATION_TIMEOUT_MSEC 500 + struct isci_request; /** @@ -224,35 +226,6 @@ enum isci_completion_selection { isci_perform_error_io_completion /* Use sas_task_abort */ }; -static inline void isci_set_task_doneflags( - struct sas_task *task) -{ - /* Since no futher action will be taken on this task, - * make sure to mark it complete from the lldd perspective. - */ - task->task_state_flags |= SAS_TASK_STATE_DONE; - task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - task->task_state_flags &= ~SAS_TASK_STATE_PENDING; -} -/** - * isci_task_all_done() - This function clears the task bits to indicate the - * LLDD is done with the task. - * - * - */ -static inline void isci_task_all_done( - struct sas_task *task) -{ - unsigned long flags; - - /* Since no futher action will be taken on this task, - * make sure to mark it complete from the lldd perspective. - */ - spin_lock_irqsave(&task->task_state_lock, flags); - isci_set_task_doneflags(task); - spin_unlock_irqrestore(&task->task_state_lock, flags); -} - /** * isci_task_set_completion_status() - This function sets the completion status * for the request. @@ -334,7 +307,9 @@ isci_task_set_completion_status( /* Fall through to the normal case... */ case isci_perform_normal_io_completion: /* Normal notification (task_done) */ - isci_set_task_doneflags(task); + task->task_state_flags |= SAS_TASK_STATE_DONE; + task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | + SAS_TASK_STATE_PENDING); break; default: WARN_ONCE(1, "unknown task_notification_selection: %d\n", diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 23e706673d06..7c34d8e7cc75 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -35,6 +35,7 @@ #include <linux/delay.h> #include <linux/kfifo.h> #include <linux/scatterlist.h> +#include <linux/module.h> #include <net/tcp.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index b9cb8140b398..7269e928824a 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -35,6 +35,7 @@ #include <linux/timer.h> #include <linux/slab.h> #include <linux/err.h> +#include <linux/export.h> #include <asm/unaligned.h> #include <scsi/fc/fc_gs.h> diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index 9b25969e2ad0..fb9161dc4ca6 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -21,6 +21,7 @@ * Provide interface to send ELS/CT FC frames */ +#include <linux/export.h> #include <asm/unaligned.h> #include <scsi/fc/fc_gs.h> #include <scsi/fc/fc_ns.h> diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 7c055fdca45d..9de9db27e874 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -26,6 +26,7 @@ #include <linux/timer.h> #include <linux/slab.h> #include <linux/err.h> +#include <linux/export.h> #include <scsi/fc/fc_fc2.h> @@ -469,6 +470,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame_header *fh = fc_frame_header_get(fp); int error; u32 f_ctl; + u8 fh_type = fh->fh_type; ep = fc_seq_exch(sp); WARN_ON((ep->esb_stat & ESB_ST_SEQ_INIT) != ESB_ST_SEQ_INIT); @@ -493,7 +495,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp, */ error = lport->tt.frame_send(lport, fp); - if (fh->fh_type == FC_TYPE_BLS) + if (fh_type == FC_TYPE_BLS) return error; /* @@ -1792,6 +1794,9 @@ restart: goto restart; } } + pool->next_index = 0; + pool->left = FC_XID_UNKNOWN; + pool->right = FC_XID_UNKNOWN; spin_unlock_bh(&pool->lock); } @@ -2280,6 +2285,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lport, goto free_mempool; for_each_possible_cpu(cpu) { pool = per_cpu_ptr(mp->pool, cpu); + pool->next_index = 0; pool->left = FC_XID_UNKNOWN; pool->right = FC_XID_UNKNOWN; spin_lock_init(&pool->lock); diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c index b7735129f1f3..1bf9841ef154 100644 --- a/drivers/scsi/libfc/fc_libfc.c +++ b/drivers/scsi/libfc/fc_libfc.c @@ -21,6 +21,7 @@ #include <linux/types.h> #include <linux/scatterlist.h> #include <linux/crc32.h> +#include <linux/module.h> #include <scsi/libfc.h> #include <scsi/fc_encode.h> diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 628f347404f9..e77094a587ed 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -89,6 +89,7 @@ #include <linux/timer.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/slab.h> #include <asm/unaligned.h> @@ -1030,16 +1031,8 @@ static void fc_lport_enter_reset(struct fc_lport *lport) FCH_EVT_LIPRESET, 0); fc_vports_linkchange(lport); fc_lport_reset_locked(lport); - if (lport->link_up) { - /* - * Wait upto resource allocation time out before - * doing re-login since incomplete FIP exchanged - * from last session may collide with exchanges - * in new session. - */ - msleep(lport->r_a_tov); + if (lport->link_up) fc_lport_enter_flogi(lport); - } } /** @@ -1481,6 +1474,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, void *lp_arg) { struct fc_lport *lport = lp_arg; + struct fc_frame_header *fh; struct fc_els_flogi *flp; u32 did; u16 csp_flags; @@ -1508,49 +1502,56 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, goto err; } + fh = fc_frame_header_get(fp); did = fc_frame_did(fp); - if (fc_frame_payload_op(fp) == ELS_LS_ACC && did) { - flp = fc_frame_payload_get(fp, sizeof(*flp)); - if (flp) { - mfs = ntohs(flp->fl_csp.sp_bb_data) & - FC_SP_BB_DATA_MASK; - if (mfs >= FC_SP_MIN_MAX_PAYLOAD && - mfs < lport->mfs) - lport->mfs = mfs; - csp_flags = ntohs(flp->fl_csp.sp_features); - r_a_tov = ntohl(flp->fl_csp.sp_r_a_tov); - e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov); - if (csp_flags & FC_SP_FT_EDTR) - e_d_tov /= 1000000; - - lport->npiv_enabled = !!(csp_flags & FC_SP_FT_NPIV_ACC); - - if ((csp_flags & FC_SP_FT_FPORT) == 0) { - if (e_d_tov > lport->e_d_tov) - lport->e_d_tov = e_d_tov; - lport->r_a_tov = 2 * e_d_tov; - fc_lport_set_port_id(lport, did, fp); - printk(KERN_INFO "host%d: libfc: " - "Port (%6.6x) entered " - "point-to-point mode\n", - lport->host->host_no, did); - fc_lport_ptp_setup(lport, fc_frame_sid(fp), - get_unaligned_be64( - &flp->fl_wwpn), - get_unaligned_be64( - &flp->fl_wwnn)); - } else { - lport->e_d_tov = e_d_tov; - lport->r_a_tov = r_a_tov; - fc_host_fabric_name(lport->host) = - get_unaligned_be64(&flp->fl_wwnn); - fc_lport_set_port_id(lport, did, fp); - fc_lport_enter_dns(lport); - } - } - } else { - FC_LPORT_DBG(lport, "FLOGI RJT or bad response\n"); + if (fh->fh_r_ctl != FC_RCTL_ELS_REP || did == 0 || + fc_frame_payload_op(fp) != ELS_LS_ACC) { + FC_LPORT_DBG(lport, "FLOGI not accepted or bad response\n"); fc_lport_error(lport, fp); + goto err; + } + + flp = fc_frame_payload_get(fp, sizeof(*flp)); + if (!flp) { + FC_LPORT_DBG(lport, "FLOGI bad response\n"); + fc_lport_error(lport, fp); + goto err; + } + + mfs = ntohs(flp->fl_csp.sp_bb_data) & + FC_SP_BB_DATA_MASK; + if (mfs >= FC_SP_MIN_MAX_PAYLOAD && + mfs < lport->mfs) + lport->mfs = mfs; + csp_flags = ntohs(flp->fl_csp.sp_features); + r_a_tov = ntohl(flp->fl_csp.sp_r_a_tov); + e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov); + if (csp_flags & FC_SP_FT_EDTR) + e_d_tov /= 1000000; + + lport->npiv_enabled = !!(csp_flags & FC_SP_FT_NPIV_ACC); + + if ((csp_flags & FC_SP_FT_FPORT) == 0) { + if (e_d_tov > lport->e_d_tov) + lport->e_d_tov = e_d_tov; + lport->r_a_tov = 2 * e_d_tov; + fc_lport_set_port_id(lport, did, fp); + printk(KERN_INFO "host%d: libfc: " + "Port (%6.6x) entered " + "point-to-point mode\n", + lport->host->host_no, did); + fc_lport_ptp_setup(lport, fc_frame_sid(fp), + get_unaligned_be64( + &flp->fl_wwpn), + get_unaligned_be64( + &flp->fl_wwnn)); + } else { + lport->e_d_tov = e_d_tov; + lport->r_a_tov = r_a_tov; + fc_host_fabric_name(lport->host) = + get_unaligned_be64(&flp->fl_wwnn); + fc_lport_set_port_id(lport, did, fp); + fc_lport_enter_dns(lport); } out: diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c index f33b897e4784..9fbf78ed821b 100644 --- a/drivers/scsi/libfc/fc_npiv.c +++ b/drivers/scsi/libfc/fc_npiv.c @@ -22,6 +22,7 @@ */ #include <scsi/libfc.h> +#include <linux/export.h> /** * fc_vport_create() - Create a new NPIV vport instance diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 760db7619446..b9e434844a69 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -51,6 +51,7 @@ #include <linux/rcupdate.h> #include <linux/timer.h> #include <linux/workqueue.h> +#include <linux/export.h> #include <asm/unaligned.h> #include <scsi/libfc.h> diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index d7c76f2eb636..143bbe448bec 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -26,6 +26,7 @@ #include <linux/delay.h> #include <linux/log2.h> #include <linux/slab.h> +#include <linux/module.h> #include <asm/unaligned.h> #include <net/tcp.h> #include <scsi/scsi_cmnd.h> diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 09b232fd9a1b..5715a3d0a3d3 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -36,6 +36,7 @@ #include <linux/delay.h> #include <linux/kfifo.h> #include <linux/scatterlist.h> +#include <linux/module.h> #include <net/tcp.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index e1aa17840c5b..bb8f49269a68 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -11,6 +11,7 @@ #include <linux/scatterlist.h> #include <linux/blkdev.h> #include <linux/slab.h> +#include <linux/export.h> #include "sas_internal.h" diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index b2c4a7731656..b6e233d9a0a1 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -25,6 +25,7 @@ #include <linux/kthread.h> #include <linux/firmware.h> +#include <linux/export.h> #include <linux/ctype.h> #include "sas_internal.h" diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c index b13a3346894c..a78e5bd3e514 100644 --- a/drivers/scsi/libsas/sas_task.c +++ b/drivers/scsi/libsas/sas_task.c @@ -1,4 +1,5 @@ #include <linux/kernel.h> +#include <linux/export.h> #include <scsi/sas.h> #include <scsi/libsas.h> diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c index ff6a28ce9b69..0707ecdbaa32 100644 --- a/drivers/scsi/libsrp.c +++ b/drivers/scsi/libsrp.c @@ -23,6 +23,7 @@ #include <linux/kfifo.h> #include <linux/scatterlist.h> #include <linux/dma-mapping.h> +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_tcq.h> diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 4b0333ee2d94..d0ebaeb7ef60 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/pci.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/aer.h> #include <linux/gfp.h> #include <linux/kernel.h> diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 2cd844f7058f..28382596fb9a 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -20,6 +20,7 @@ #include <linux/blkdev.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/dma-mapping.h> #include <linux/idr.h> #include <linux/interrupt.h> diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 907c94b9245d..55bc4fc7376f 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -24,6 +24,7 @@ #include <linux/dma-mapping.h> #include <linux/idr.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/kthread.h> #include <linux/pci.h> #include <linux/spinlock.h> diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 5b8790b3cf4b..2e1e54e5c3ae 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -21,6 +21,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/interrupt.h> +#include <linux/export.h> #include <linux/delay.h> #include <asm/unaligned.h> diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 6c42dff0f4d3..e6173376605d 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -17,6 +17,7 @@ #include <linux/stat.h> #include <linux/spinlock.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <asm/dbdma.h> #include <asm/io.h> #include <asm/pgtable.h> diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 8883ca36f932..35bd13879fed 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -71,6 +71,7 @@ */ #include <linux/slab.h> +#include <linux/module.h> #include "megaraid_mbox.h" static int megaraid_init(void); diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 3105d5e8d908..8dc1b32918dd 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2010 LSI Corporation. + * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.18 + * mpi2.h Version: 02.00.20 * * Version History * --------------- @@ -66,6 +66,9 @@ * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. + * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MPI2_FUNCTION_SEND_HOST_MESSAGE. + * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -91,7 +94,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x12) +#define MPI2_HEADER_VERSION_UNIT (0x14) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -515,6 +518,8 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION #define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) /* Power Management Control */ #define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) +/* Send Host Message */ +#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) /* beginning of product-specific range */ #define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) /* end of product-specific range */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index 61475a6480e3..cfd95b4e3004 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2010 LSI Corporation. + * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2_cnfg.h * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.17 + * mpi2_cnfg.h Version: 02.00.19 * * Version History * --------------- @@ -134,6 +134,12 @@ * to MPI2_CONFIG_PAGE_IO_UNIT_7. * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. + * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST. + * Added IO Unit Page 8, IO Unit Page 9, + * and IO Unit Page 10. + * Added SASNotifyPrimitiveMasks field to + * MPI2_CONFIG_PAGE_IOC_7. + * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec). * -------------------------------------------------------------------------- */ @@ -329,7 +335,9 @@ typedef struct _MPI2_CONFIG_REQUEST U8 VP_ID; /* 0x08 */ U8 VF_ID; /* 0x09 */ U16 Reserved1; /* 0x0A */ - U32 Reserved2; /* 0x0C */ + U8 Reserved2; /* 0x0C */ + U8 ProxyVF_ID; /* 0x0D */ + U16 Reserved4; /* 0x0E */ U32 Reserved3; /* 0x10 */ MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ U32 PageAddress; /* 0x18 */ @@ -915,6 +923,120 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { #define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01) #define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02) +/* IO Unit Page 8 */ + +#define MPI2_IOUNIT8_NUM_THRESHOLDS (4) + +typedef struct _MPI2_IOUNIT8_SENSOR { + U16 Flags; /* 0x00 */ + U16 Reserved1; /* 0x02 */ + U16 + Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /* 0x04 */ + U32 Reserved2; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U32 Reserved4; /* 0x14 */ +} MPI2_IOUNIT8_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT8_SENSOR, +Mpi2IOUnit8Sensor_t, MPI2_POINTER pMpi2IOUnit8Sensor_t; + +/* defines for IO Unit Page 8 Sensor Flags field */ +#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE (0x0008) +#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE (0x0004) +#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE (0x0002) +#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumSensors at runtime. + */ +#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES +#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U8 NumSensors; /* 0x0C */ + U8 PollingInterval; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_IOUNIT8_SENSOR + Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/* 0x10 */ +} MPI2_CONFIG_PAGE_IO_UNIT_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_8, +Mpi2IOUnitPage8_t, MPI2_POINTER pMpi2IOUnitPage8_t; + +#define MPI2_IOUNITPAGE8_PAGEVERSION (0x00) + + +/* IO Unit Page 9 */ + +typedef struct _MPI2_IOUNIT9_SENSOR { + U16 CurrentTemperature; /* 0x00 */ + U16 Reserved1; /* 0x02 */ + U8 Flags; /* 0x04 */ + U8 Reserved2; /* 0x05 */ + U16 Reserved3; /* 0x06 */ + U32 Reserved4; /* 0x08 */ + U32 Reserved5; /* 0x0C */ +} MPI2_IOUNIT9_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT9_SENSOR, +Mpi2IOUnit9Sensor_t, MPI2_POINTER pMpi2IOUnit9Sensor_t; + +/* defines for IO Unit Page 9 Sensor Flags field */ +#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumSensors at runtime. + */ +#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES +#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U8 NumSensors; /* 0x0C */ + U8 Reserved4; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_IOUNIT9_SENSOR + Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/* 0x10 */ +} MPI2_CONFIG_PAGE_IO_UNIT_9, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_9, +Mpi2IOUnitPage9_t, MPI2_POINTER pMpi2IOUnitPage9_t; + +#define MPI2_IOUNITPAGE9_PAGEVERSION (0x00) + + +/* IO Unit Page 10 */ + +typedef struct _MPI2_IOUNIT10_FUNCTION { + U8 CreditPercent; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ +} MPI2_IOUNIT10_FUNCTION, MPI2_POINTER PTR_MPI2_IOUNIT10_FUNCTION, +Mpi2IOUnit10Function_t, MPI2_POINTER pMpi2IOUnit10Function_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumFunctions at runtime. + */ +#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES +#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumFunctions; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U32 Reserved3; /* 0x08 */ + U32 Reserved4; /* 0x0C */ + MPI2_IOUNIT10_FUNCTION + Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/* 0x10 */ +} MPI2_CONFIG_PAGE_IO_UNIT_10, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_10, +Mpi2IOUnitPage10_t, MPI2_POINTER pMpi2IOUnitPage10_t; + +#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01) + /**************************************************************************** @@ -1022,12 +1144,12 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_7 U32 Reserved1; /* 0x04 */ U32 EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */ U16 SASBroadcastPrimitiveMasks; /* 0x18 */ - U16 Reserved2; /* 0x1A */ + U16 SASNotifyPrimitiveMasks; /* 0x1A */ U32 Reserved3; /* 0x1C */ } MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7, Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t; -#define MPI2_IOCPAGE7_PAGEVERSION (0x01) +#define MPI2_IOCPAGE7_PAGEVERSION (0x02) /* IOC Page 8 */ @@ -2070,16 +2192,16 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 { #define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00) /* defines for PowerManagementCapabilities field */ -#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x000001000) -#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x000000800) -#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x000000400) -#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x000000200) -#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x000000100) -#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x000000010) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x000000008) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x000000004) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x000000002) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x000000001) +#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x00001000) +#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x00000800) +#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x00000400) +#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x00000200) +#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x00000100) +#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x00000010) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001) @@ -2266,6 +2388,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 /* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */ /* values for SAS Device Page 0 Flags field */ +#define MPI2_SAS_DEVICE0_FLAGS_UNAUTHORIZED_DEVICE (0x8000) #define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000) #define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800) #define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 1f0c190d336e..93d9b6956d05 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2010 LSI Corporation. + * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2_ioc.h * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.16 + * mpi2_ioc.h Version: 02.00.17 * * Version History * --------------- @@ -104,6 +104,12 @@ * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. + * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added + * SASNotifyPrimitiveMasks field to + * MPI2_EVENT_NOTIFICATION_REQUEST. + * Added Temperature Threshold Event. + * Added Host Message Event. + * Added Send Host Message request and reply. * -------------------------------------------------------------------------- */ @@ -421,7 +427,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST U32 Reserved6; /* 0x10 */ U32 EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */ U16 SASBroadcastPrimitiveMasks; /* 0x24 */ - U16 Reserved7; /* 0x26 */ + U16 SASNotifyPrimitiveMasks; /* 0x26 */ U32 Reserved8; /* 0x28 */ } MPI2_EVENT_NOTIFICATION_REQUEST, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST, @@ -476,6 +482,9 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY #define MPI2_EVENT_GPIO_INTERRUPT (0x0023) #define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) #define MPI2_EVENT_SAS_QUIESCE (0x0025) +#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE (0x0026) +#define MPI2_EVENT_TEMP_THRESHOLD (0x0027) +#define MPI2_EVENT_HOST_MESSAGE (0x0028) /* Log Entry Added Event data */ @@ -507,6 +516,39 @@ typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT { MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT, Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t; +/* Temperature Threshold Event data */ + +typedef struct _MPI2_EVENT_DATA_TEMPERATURE { + U16 Status; /* 0x00 */ + U8 SensorNum; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U16 CurrentTemperature; /* 0x04 */ + U16 Reserved2; /* 0x06 */ + U32 Reserved3; /* 0x08 */ + U32 Reserved4; /* 0x0C */ +} MPI2_EVENT_DATA_TEMPERATURE, +MPI2_POINTER PTR_MPI2_EVENT_DATA_TEMPERATURE, +Mpi2EventDataTemperature_t, MPI2_POINTER pMpi2EventDataTemperature_t; + +/* Temperature Threshold Event data Status bits */ +#define MPI2_EVENT_TEMPERATURE3_EXCEEDED (0x0008) +#define MPI2_EVENT_TEMPERATURE2_EXCEEDED (0x0004) +#define MPI2_EVENT_TEMPERATURE1_EXCEEDED (0x0002) +#define MPI2_EVENT_TEMPERATURE0_EXCEEDED (0x0001) + + +/* Host Message Event data */ + +typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE { + U8 SourceVF_ID; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ + U32 HostData[1]; /* 0x08 */ +} MPI2_EVENT_DATA_HOST_MESSAGE, MPI2_POINTER PTR_MPI2_EVENT_DATA_HOST_MESSAGE, +Mpi2EventDataHostMessage_t, MPI2_POINTER pMpi2EventDataHostMessage_t; + + /* Hard Reset Received Event data */ typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED @@ -749,6 +791,24 @@ typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE #define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) #define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08) +/* SAS Notify Primitive Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE { + U8 PhyNum; /* 0x00 */ + U8 Port; /* 0x01 */ + U8 Reserved1; /* 0x02 */ + U8 Primitive; /* 0x03 */ +} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, +MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, +Mpi2EventDataSasNotifyPrimitive_t, +MPI2_POINTER pMpi2EventDataSasNotifyPrimitive_t; + +/* defines for the Primitive field */ +#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP (0x01) +#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED (0x02) +#define MPI2_EVENT_NOTIFY_RESERVED1 (0x03) +#define MPI2_EVENT_NOTIFY_RESERVED2 (0x04) + /* SAS Initiator Device Status Change Event data */ @@ -1001,6 +1061,53 @@ typedef struct _MPI2_EVENT_ACK_REPLY /**************************************************************************** +* SendHostMessage message +****************************************************************************/ + +/* SendHostMessage Request message */ +typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST { + U16 HostDataLength; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U8 Reserved4; /* 0x0C */ + U8 DestVF_ID; /* 0x0D */ + U16 Reserved5; /* 0x0E */ + U32 Reserved6; /* 0x10 */ + U32 Reserved7; /* 0x14 */ + U32 Reserved8; /* 0x18 */ + U32 Reserved9; /* 0x1C */ + U32 Reserved10; /* 0x20 */ + U32 HostData[1]; /* 0x24 */ +} MPI2_SEND_HOST_MESSAGE_REQUEST, +MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REQUEST, +Mpi2SendHostMessageRequest_t, MPI2_POINTER pMpi2SendHostMessageRequest_t; + + +/* SendHostMessage Reply message */ +typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY { + U16 HostDataLength; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_SEND_HOST_MESSAGE_REPLY, MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REPLY, +Mpi2SendHostMessageReply_t, MPI2_POINTER pMpi2SendHostMessageReply_t; + + +/**************************************************************************** * FWDownload message ****************************************************************************/ diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 81209ca87274..beda04a8404b 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -81,6 +81,15 @@ static int missing_delay[2] = {-1, -1}; module_param_array(missing_delay, int, NULL, 0); MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); +static int mpt2sas_fwfault_debug; +MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " + "and halt firmware - (default=0)"); + +static int disable_discovery = -1; +module_param(disable_discovery, int, 0); +MODULE_PARM_DESC(disable_discovery, " disable discovery "); + + /* diag_buffer_enable is bitwise * bit 0 set = TRACE * bit 1 set = SNAPSHOT @@ -93,14 +102,6 @@ module_param(diag_buffer_enable, int, 0); MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); -static int mpt2sas_fwfault_debug; -MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " - "and halt firmware - (default=0)"); - -static int disable_discovery = -1; -module_param(disable_discovery, int, 0); -MODULE_PARM_DESC(disable_discovery, " disable discovery "); - /** * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. * @@ -691,6 +692,7 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); } ioc->base_cmds.status &= ~MPT2_CMD_PENDING; + complete(&ioc->base_cmds.done); return 1; } @@ -3470,6 +3472,58 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) } /** + * mpt2sas_port_enable_done - command completion routine for port enable + * @ioc: per adapter object + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. + */ +u8 +mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, + u32 reply) +{ + MPI2DefaultReply_t *mpi_reply; + u16 ioc_status; + + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) + return 1; + + if (ioc->port_enable_cmds.status == MPT2_CMD_NOT_USED) + return 1; + + ioc->port_enable_cmds.status |= MPT2_CMD_COMPLETE; + if (mpi_reply) { + ioc->port_enable_cmds.status |= MPT2_CMD_REPLY_VALID; + memcpy(ioc->port_enable_cmds.reply, mpi_reply, + mpi_reply->MsgLength*4); + } + ioc->port_enable_cmds.status &= ~MPT2_CMD_PENDING; + + ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) + ioc->port_enable_failed = 1; + + if (ioc->is_driver_loading) { + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { + mpt2sas_port_enable_complete(ioc); + return 1; + } else { + ioc->start_scan_failed = ioc_status; + ioc->start_scan = 0; + return 1; + } + } + complete(&ioc->port_enable_cmds.done); + return 1; +} + + +/** * _base_send_port_enable - send port_enable(discovery stuff) to firmware * @ioc: per adapter object * @sleep_flag: CAN_SLEEP or NO_SLEEP @@ -3480,67 +3534,151 @@ static int _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { Mpi2PortEnableRequest_t *mpi_request; - u32 ioc_state; + Mpi2PortEnableReply_t *mpi_reply; unsigned long timeleft; int r = 0; u16 smid; + u16 ioc_status; printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); - if (ioc->base_cmds.status & MPT2_CMD_PENDING) { + if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", ioc->name, __func__); return -EAGAIN; } - smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); + smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); if (!smid) { printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", ioc->name, __func__); return -EAGAIN; } - ioc->base_cmds.status = MPT2_CMD_PENDING; + ioc->port_enable_cmds.status = MPT2_CMD_PENDING; mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->base_cmds.smid = smid; + ioc->port_enable_cmds.smid = smid; memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; + init_completion(&ioc->port_enable_cmds.done); mpt2sas_base_put_smid_default(ioc, smid); - init_completion(&ioc->base_cmds.done); - timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, + timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ); - if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { + if (!(ioc->port_enable_cmds.status & MPT2_CMD_COMPLETE)) { printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, __func__); _debug_dump_mf(mpi_request, sizeof(Mpi2PortEnableRequest_t)/4); - if (ioc->base_cmds.status & MPT2_CMD_RESET) + if (ioc->port_enable_cmds.status & MPT2_CMD_RESET) r = -EFAULT; else r = -ETIME; goto out; - } else - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n", - ioc->name, __func__)); + } + mpi_reply = ioc->port_enable_cmds.reply; - ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL, - 60, sleep_flag); - if (ioc_state) { - printk(MPT2SAS_ERR_FMT "%s: failed going to operational state " - " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state); + ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "%s: failed with (ioc_status=0x%08x)\n", + ioc->name, __func__, ioc_status); r = -EFAULT; + goto out; } out: - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - printk(MPT2SAS_INFO_FMT "port enable: %s\n", - ioc->name, ((r == 0) ? "SUCCESS" : "FAILED")); + ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; + printk(MPT2SAS_INFO_FMT "port enable: %s\n", ioc->name, ((r == 0) ? + "SUCCESS" : "FAILED")); return r; } /** + * mpt2sas_port_enable - initiate firmware discovery (don't wait for reply) + * @ioc: per adapter object + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2PortEnableRequest_t *mpi_request; + u16 smid; + + printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); + + if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { + printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", + ioc->name, __func__); + return -EAGAIN; + } + + smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + return -EAGAIN; + } + + ioc->port_enable_cmds.status = MPT2_CMD_PENDING; + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->port_enable_cmds.smid = smid; + memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); + mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; + + mpt2sas_base_put_smid_default(ioc, smid); + return 0; +} + +/** + * _base_determine_wait_on_discovery - desposition + * @ioc: per adapter object + * + * Decide whether to wait on discovery to complete. Used to either + * locate boot device, or report volumes ahead of physical devices. + * + * Returns 1 for wait, 0 for don't wait + */ +static int +_base_determine_wait_on_discovery(struct MPT2SAS_ADAPTER *ioc) +{ + /* We wait for discovery to complete if IR firmware is loaded. + * The sas topology events arrive before PD events, so we need time to + * turn on the bit in ioc->pd_handles to indicate PD + * Also, it maybe required to report Volumes ahead of physical + * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set. + */ + if (ioc->ir_firmware) + return 1; + + /* if no Bios, then we don't need to wait */ + if (!ioc->bios_pg3.BiosVersion) + return 0; + + /* Bios is present, then we drop down here. + * + * If there any entries in the Bios Page 2, then we wait + * for discovery to complete. + */ + + /* Current Boot Device */ + if ((ioc->bios_pg2.CurrentBootDeviceForm & + MPI2_BIOSPAGE2_FORM_MASK) == + MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && + /* Request Boot Device */ + (ioc->bios_pg2.ReqBootDeviceForm & + MPI2_BIOSPAGE2_FORM_MASK) == + MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && + /* Alternate Request Boot Device */ + (ioc->bios_pg2.ReqAltBootDeviceForm & + MPI2_BIOSPAGE2_FORM_MASK) == + MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED) + return 0; + + return 1; +} + + +/** * _base_unmask_events - turn on notification for this event * @ioc: per adapter object * @event: firmware event @@ -3962,6 +4100,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) skip_init_reply_post_host_index: _base_unmask_interrupts(ioc); + r = _base_event_notification(ioc, sleep_flag); if (r) return r; @@ -3969,7 +4108,18 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) if (sleep_flag == CAN_SLEEP) _base_static_config_pages(ioc); - if (ioc->wait_for_port_enable_to_complete && ioc->is_warpdrive) { + + if (ioc->is_driver_loading) { + + + + ioc->wait_for_discovery_to_complete = + _base_determine_wait_on_discovery(ioc); + return r; /* scan_start and scan_finished support */ + } + + + if (ioc->wait_for_discovery_to_complete && ioc->is_warpdrive) { if (ioc->manu_pg10.OEMIdentifier == 0x80) { hide_flag = (u8) (ioc->manu_pg10.OEMSpecificFlags0 & MFG_PAGE10_HIDE_SSDS_MASK); @@ -3978,13 +4128,6 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) } } - if (ioc->wait_for_port_enable_to_complete) { - if (diag_buffer_enable != 0) - mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); - if (disable_discovery > 0) - return r; - } - r = _base_send_port_enable(ioc, sleep_flag); if (r) return r; @@ -4121,6 +4264,10 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); ioc->base_cmds.status = MPT2_CMD_NOT_USED; + /* port_enable command bits */ + ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); + ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; + /* transport internal command bits */ ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); ioc->transport_cmds.status = MPT2_CMD_NOT_USED; @@ -4162,8 +4309,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) goto out_free_resources; } - init_completion(&ioc->shost_recovery_done); - for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) ioc->event_masks[i] = -1; @@ -4186,7 +4331,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) _base_update_missing_delay(ioc, missing_delay[0], missing_delay[1]); - mpt2sas_base_start_watchdog(ioc); return 0; out_free_resources: @@ -4204,6 +4348,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) kfree(ioc->scsih_cmds.reply); kfree(ioc->config_cmds.reply); kfree(ioc->base_cmds.reply); + kfree(ioc->port_enable_cmds.reply); kfree(ioc->ctl_cmds.reply); kfree(ioc->ctl_cmds.sense); kfree(ioc->pfacts); @@ -4243,6 +4388,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) kfree(ioc->ctl_cmds.reply); kfree(ioc->ctl_cmds.sense); kfree(ioc->base_cmds.reply); + kfree(ioc->port_enable_cmds.reply); kfree(ioc->tm_cmds.reply); kfree(ioc->transport_cmds.reply); kfree(ioc->scsih_cmds.reply); @@ -4284,6 +4430,20 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid); complete(&ioc->base_cmds.done); } + if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { + ioc->port_enable_failed = 1; + ioc->port_enable_cmds.status |= MPT2_CMD_RESET; + mpt2sas_base_free_smid(ioc, ioc->port_enable_cmds.smid); + if (ioc->is_driver_loading) { + ioc->start_scan_failed = + MPI2_IOCSTATUS_INTERNAL_ERROR; + ioc->start_scan = 0; + ioc->port_enable_cmds.status = + MPT2_CMD_NOT_USED; + } else + complete(&ioc->port_enable_cmds.done); + + } if (ioc->config_cmds.status & MPT2_CMD_PENDING) { ioc->config_cmds.status |= MPT2_CMD_RESET; mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); @@ -4349,7 +4509,6 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, { int r; unsigned long flags; - u8 pe_complete = ioc->wait_for_port_enable_to_complete; dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); @@ -4396,7 +4555,8 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, /* If this hard reset is called while port enable is active, then * there is no reason to call make_ioc_operational */ - if (pe_complete) { + if (ioc->is_driver_loading && ioc->port_enable_failed) { + ioc->remove_host = 1; r = -EFAULT; goto out; } @@ -4410,7 +4570,6 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); ioc->ioc_reset_in_progress_status = r; ioc->shost_recovery = 0; - complete(&ioc->shost_recovery_done); spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); mutex_unlock(&ioc->reset_in_progress_mutex); diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 59354dba68c0..3c3babc7d260 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,11 +69,11 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>" #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "09.100.00.01" -#define MPT2SAS_MAJOR_VERSION 09 +#define MPT2SAS_DRIVER_VERSION "10.100.00.00" +#define MPT2SAS_MAJOR_VERSION 10 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 00 -#define MPT2SAS_RELEASE_VERSION 01 +#define MPT2SAS_RELEASE_VERSION 00 /* * Set MPT2SAS_SG_DEPTH value based on user input. @@ -655,7 +655,12 @@ enum mutex_type { * @ignore_loginfos: ignore loginfos during task management * @remove_host: flag for when driver unloads, to avoid sending dev resets * @pci_error_recovery: flag to prevent ioc access until slot reset completes - * @wait_for_port_enable_to_complete: + * @wait_for_discovery_to_complete: flag set at driver load time when + * waiting on reporting devices + * @is_driver_loading: flag set at driver load time + * @port_enable_failed: flag set when port enable has failed + * @start_scan: flag set from scan_start callback, cleared from _mpt2sas_fw_work + * @start_scan_failed: means port enable failed, return's the ioc_status * @msix_enable: flag indicating msix is enabled * @msix_vector_count: number msix vectors * @cpu_msix_table: table for mapping cpus to msix index @@ -790,15 +795,20 @@ struct MPT2SAS_ADAPTER { u8 shost_recovery; struct mutex reset_in_progress_mutex; - struct completion shost_recovery_done; spinlock_t ioc_reset_in_progress_lock; u8 ioc_link_reset_in_progress; - int ioc_reset_in_progress_status; + u8 ioc_reset_in_progress_status; u8 ignore_loginfos; u8 remove_host; u8 pci_error_recovery; - u8 wait_for_port_enable_to_complete; + u8 wait_for_discovery_to_complete; + struct completion port_enable_done; + u8 is_driver_loading; + u8 port_enable_failed; + + u8 start_scan; + u16 start_scan_failed; u8 msix_enable; u16 msix_vector_count; @@ -814,11 +824,13 @@ struct MPT2SAS_ADAPTER { u8 scsih_cb_idx; u8 ctl_cb_idx; u8 base_cb_idx; + u8 port_enable_cb_idx; u8 config_cb_idx; u8 tm_tr_cb_idx; u8 tm_tr_volume_cb_idx; u8 tm_sas_control_cb_idx; struct _internal_cmd base_cmds; + struct _internal_cmd port_enable_cmds; struct _internal_cmd transport_cmds; struct _internal_cmd scsih_cmds; struct _internal_cmd tm_cmds; @@ -1001,6 +1013,8 @@ void mpt2sas_base_release_callback_handler(u8 cb_idx); u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); +u8 mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, + u8 msix_index, u32 reply); void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr); u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked); @@ -1015,6 +1029,8 @@ void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_ty void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); +int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc); + /* scsih shared API */ u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply); @@ -1032,6 +1048,8 @@ struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAP struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address( struct MPT2SAS_ADAPTER *ioc, u64 sas_address); +void mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc); + void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); /* config shared API */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index 2b1101076cfe..36ea0b2d8020 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -1356,6 +1356,9 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, Mpi2ConfigReply_t mpi_reply; int r, i, config_page_sz; u16 ioc_status; + int config_num; + u16 element_type; + u16 phys_disk_dev_handle; *volume_handle = 0; memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); @@ -1371,35 +1374,53 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, if (r) goto out; - mpi_request.PageAddress = - cpu_to_le32(MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4); config_page = kmalloc(config_page_sz, GFP_KERNEL); - if (!config_page) - goto out; - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - config_page_sz); - if (r) + if (!config_page) { + r = -1; goto out; - - r = -1; - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - goto out; - for (i = 0; i < config_page->NumElements; i++) { - if ((le16_to_cpu(config_page->ConfigElement[i].ElementFlags) & - MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) != - MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT) - continue; - if (le16_to_cpu(config_page->ConfigElement[i]. - PhysDiskDevHandle) == pd_handle) { - *volume_handle = le16_to_cpu(config_page-> - ConfigElement[i].VolDevHandle); - r = 0; + } + config_num = 0xff; + while (1) { + mpi_request.PageAddress = cpu_to_le32(config_num + + MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM); + r = _config_request(ioc, &mpi_request, &mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + config_page_sz); + if (r) + goto out; + r = -1; + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) goto out; + for (i = 0; i < config_page->NumElements; i++) { + element_type = le16_to_cpu(config_page-> + ConfigElement[i].ElementFlags) & + MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE; + if (element_type == + MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT || + element_type == + MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) { + phys_disk_dev_handle = + le16_to_cpu(config_page->ConfigElement[i]. + PhysDiskDevHandle); + if (phys_disk_dev_handle == pd_handle) { + *volume_handle = + le16_to_cpu(config_page-> + ConfigElement[i].VolDevHandle); + r = 0; + goto out; + } + } else if (element_type == + MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) { + *volume_handle = 0; + r = 0; + goto out; + } } + config_num = config_page->ConfigNum; } out: kfree(config_page); diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 9adb0133d6fb..aabcb911706e 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -1207,6 +1207,9 @@ _ctl_do_reset(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; + if (ioc->shost_recovery || ioc->pci_error_recovery || + ioc->is_driver_loading) + return -EAGAIN; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); @@ -2178,7 +2181,8 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) !ioc) return -ENODEV; - if (ioc->shost_recovery || ioc->pci_error_recovery) + if (ioc->shost_recovery || ioc->pci_error_recovery || + ioc->is_driver_loading) return -EAGAIN; if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { @@ -2297,7 +2301,8 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - if (ioc->shost_recovery || ioc->pci_error_recovery) + if (ioc->shost_recovery || ioc->pci_error_recovery || + ioc->is_driver_loading) return -EAGAIN; memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 1da1aa1a11e2..8889b1babcac 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -71,6 +71,9 @@ static void _firmware_event_work(struct work_struct *work); static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid); +static void _scsih_scan_start(struct Scsi_Host *shost); +static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time); + /* global parameters */ LIST_HEAD(mpt2sas_ioc_list); @@ -79,6 +82,7 @@ static u8 scsi_io_cb_idx = -1; static u8 tm_cb_idx = -1; static u8 ctl_cb_idx = -1; static u8 base_cb_idx = -1; +static u8 port_enable_cb_idx = -1; static u8 transport_cb_idx = -1; static u8 scsih_cb_idx = -1; static u8 config_cb_idx = -1; @@ -103,6 +107,18 @@ static int max_lun = MPT2SAS_MAX_LUN; module_param(max_lun, int, 0); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); +/* diag_buffer_enable is bitwise + * bit 0 set = TRACE + * bit 1 set = SNAPSHOT + * bit 2 set = EXTENDED + * + * Either bit can be set, or both + */ +static int diag_buffer_enable = -1; +module_param(diag_buffer_enable, int, 0); +MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " + "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); + /** * struct sense_info - common structure for obtaining sense keys * @skey: sense key @@ -117,8 +133,8 @@ struct sense_info { #define MPT2SAS_TURN_ON_FAULT_LED (0xFFFC) -#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF) - +#define MPT2SAS_PORT_ENABLE_COMPLETE (0xFFFD) +#define MPT2SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF) /** * struct fw_event_work - firmware event struct * @list: link list framework @@ -372,31 +388,34 @@ _scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle, Mpi2SasDevicePage0_t sas_device_pg0; Mpi2ConfigReply_t mpi_reply; u32 ioc_status; + *sas_address = 0; if (handle <= ioc->sas_hba.num_phys) { *sas_address = ioc->sas_hba.sas_address; return 0; - } else - *sas_address = 0; + } if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, + __FILE__, __LINE__, __func__); return -ENXIO; } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)" - "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, - __FILE__, __LINE__, __func__); - return -EIO; + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { + *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + return 0; } - *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - return 0; + /* we hit this becuase the given parent handle doesn't exist */ + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + return -ENXIO; + /* else error case */ + printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x), " + "failure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, + __FILE__, __LINE__, __func__); + return -EIO; } /** @@ -424,7 +443,11 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, u16 slot; /* only process this function when driver loads */ - if (!ioc->wait_for_port_enable_to_complete) + if (!ioc->is_driver_loading) + return; + + /* no Bios, return immediately */ + if (!ioc->bios_pg3.BiosVersion) return; if (!is_raid) { @@ -587,8 +610,15 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) + sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); + } else if (!sas_device->starget) { + if (!ioc->is_driver_loading) + mpt2sas_transport_port_remove(ioc, + sas_device->sas_address, + sas_device->sas_address_parent); + _scsih_sas_device_remove(ioc, sas_device); + } } /** @@ -1400,6 +1430,10 @@ _scsih_slave_destroy(struct scsi_device *sdev) { struct MPT2SAS_TARGET *sas_target_priv_data; struct scsi_target *starget; + struct Scsi_Host *shost; + struct MPT2SAS_ADAPTER *ioc; + struct _sas_device *sas_device; + unsigned long flags; if (!sdev->hostdata) return; @@ -1407,6 +1441,19 @@ _scsih_slave_destroy(struct scsi_device *sdev) starget = scsi_target(sdev); sas_target_priv_data = starget->hostdata; sas_target_priv_data->num_luns--; + + shost = dev_to_shost(&starget->dev); + ioc = shost_priv(shost); + + if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_target_priv_data->sas_address); + if (sas_device) + sas_device->starget = NULL; + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } + kfree(sdev->hostdata); sdev->hostdata = NULL; } @@ -1598,8 +1645,10 @@ _scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device) * _scsih_get_volume_capabilities - volume capabilities * @ioc: per adapter object * @sas_device: the raid_device object + * + * Returns 0 for success, else 1 */ -static void +static int _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, struct _raid_device *raid_device) { @@ -1612,9 +1661,10 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, &num_pds)) || !num_pds) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT + "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, + __func__)); + return 1; } raid_device->num_pds = num_pds; @@ -1622,17 +1672,19 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, sizeof(Mpi2RaidVol0PhysDisk_t)); vol_pg0 = kzalloc(sz, GFP_KERNEL); if (!vol_pg0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT + "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, + __func__)); + return 1; } if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT + "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, + __func__)); kfree(vol_pg0); - return; + return 1; } raid_device->volume_type = vol_pg0->VolumeType; @@ -1652,6 +1704,7 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, } kfree(vol_pg0); + return 0; } /** * _scsih_disable_ddio - Disable direct I/O for all the volumes @@ -1922,13 +1975,20 @@ _scsih_slave_configure(struct scsi_device *sdev) sas_target_priv_data->handle); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (!raid_device) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return 0; + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT + "failure at %s:%d/%s()!\n", ioc->name, __FILE__, + __LINE__, __func__)); + return 1; } _scsih_get_volume_capabilities(ioc, raid_device); + if (_scsih_get_volume_capabilities(ioc, raid_device)) { + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT + "failure at %s:%d/%s()!\n", ioc->name, __FILE__, + __LINE__, __func__)); + return 1; + } /* * WARPDRIVE: Initialize the required data for Direct IO */ @@ -2002,11 +2062,22 @@ _scsih_slave_configure(struct scsi_device *sdev) if (sas_device) { if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - mpt2sas_config_get_volume_handle(ioc, - sas_device->handle, &sas_device->volume_handle); - mpt2sas_config_get_volume_wwid(ioc, + if (mpt2sas_config_get_volume_handle(ioc, + sas_device->handle, &sas_device->volume_handle)) { + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT + "failure at %s:%d/%s()!\n", ioc->name, + __FILE__, __LINE__, __func__)); + return 1; + } + if (sas_device->volume_handle && + mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle, - &sas_device->volume_wwid); + &sas_device->volume_wwid)) { + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT + "failure at %s:%d/%s()!\n", ioc->name, + __FILE__, __LINE__, __func__)); + return 1; + } } if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) { qdepth = MPT2SAS_SAS_QUEUE_DEPTH; @@ -2035,6 +2106,11 @@ _scsih_slave_configure(struct scsi_device *sdev) if (!ssp_target) _scsih_display_sata_capabilities(ioc, sas_device, sdev); + } else { + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT + "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, + __func__)); + return 1; } _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); @@ -2714,22 +2790,38 @@ _scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work /** - * _scsih_queue_rescan - queue a topology rescan from user context + * _scsih_error_recovery_delete_devices - remove devices not responding * @ioc: per adapter object * * Return nothing. */ static void -_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc) +_scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc) { struct fw_event_work *fw_event; - if (ioc->wait_for_port_enable_to_complete) + if (ioc->is_driver_loading) return; + fw_event->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES; + fw_event->ioc = ioc; + _scsih_fw_event_add(ioc, fw_event); +} + +/** + * mpt2sas_port_enable_complete - port enable completed (fake event) + * @ioc: per adapter object + * + * Return nothing. + */ +void +mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc) +{ + struct fw_event_work *fw_event; + fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); if (!fw_event) return; - fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET; + fw_event->event = MPT2SAS_PORT_ENABLE_COMPLETE; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); } @@ -2977,14 +3069,27 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) Mpi2SCSITaskManagementRequest_t *mpi_request; u16 smid; struct _sas_device *sas_device; - struct MPT2SAS_TARGET *sas_target_priv_data; + struct MPT2SAS_TARGET *sas_target_priv_data = NULL; + u64 sas_address = 0; unsigned long flags; struct _tr_list *delayed_tr; + u32 ioc_state; - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " - "progress!\n", __func__, ioc->name)); + if (ioc->remove_host) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been " + "removed: handle(0x%04x)\n", __func__, ioc->name, handle)); + return; + } else if (ioc->pci_error_recovery) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci " + "error recovery: handle(0x%04x)\n", __func__, ioc->name, + handle)); + return; + } + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not " + "operational: handle(0x%04x)\n", __func__, ioc->name, + handle)); return; } @@ -2998,13 +3103,18 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) sas_device->starget->hostdata) { sas_target_priv_data = sas_device->starget->hostdata; sas_target_priv_data->deleted = 1; - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "setting delete flag: handle(0x%04x), " - "sas_addr(0x%016llx)\n", ioc->name, handle, - (unsigned long long) sas_device->sas_address)); + sas_address = sas_device->sas_address; } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_target_priv_data) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: " + "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle, + (unsigned long long)sas_address)); + _scsih_ublock_io_device(ioc, handle); + sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE; + } + smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); if (!smid) { delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); @@ -3185,11 +3295,21 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, mpt2sas_base_get_reply_virt_addr(ioc, reply); Mpi2SasIoUnitControlRequest_t *mpi_request; u16 smid_sas_ctrl; + u32 ioc_state; - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " - "progress!\n", __func__, ioc->name)); + if (ioc->remove_host) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been " + "removed\n", __func__, ioc->name)); + return 1; + } else if (ioc->pci_error_recovery) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci " + "error recovery\n", __func__, ioc->name)); + return 1; + } + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not " + "operational\n", __func__, ioc->name)); return 1; } @@ -5099,7 +5219,7 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) /* get device name */ sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName); - if (ioc->wait_for_port_enable_to_complete) + if (ioc->wait_for_discovery_to_complete) _scsih_sas_device_init_add(ioc, sas_device); else _scsih_sas_device_add(ioc, sas_device); @@ -5135,6 +5255,9 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, if (sas_device_backup.starget && sas_device_backup.starget->hostdata) { sas_target_priv_data = sas_device_backup.starget->hostdata; sas_target_priv_data->deleted = 1; + _scsih_ublock_io_device(ioc, sas_device_backup.handle); + sas_target_priv_data->handle = + MPT2SAS_INVALID_DEVICE_HANDLE; } _scsih_ublock_io_device(ioc, sas_device_backup.handle); @@ -5288,7 +5411,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, _scsih_sas_topology_change_event_debug(ioc, event_data); #endif - if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) + if (ioc->remove_host || ioc->pci_error_recovery) return; if (!ioc->sas_hba.num_phys) @@ -5349,6 +5472,9 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, switch (reason_code) { case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: + if (ioc->shost_recovery) + break; + if (link_rate == prev_link_rate) break; @@ -5362,6 +5488,9 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, break; case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: + if (ioc->shost_recovery) + break; + mpt2sas_transport_update_links(ioc, sas_address, handle, phy_number, link_rate); @@ -5622,7 +5751,7 @@ broadcast_aen_retry: termination_count = 0; query_count = 0; for (smid = 1; smid <= ioc->scsiio_depth; smid++) { - if (ioc->ioc_reset_in_progress_status) + if (ioc->shost_recovery) goto out; scmd = _scsih_scsi_lookup_get(ioc, smid); if (!scmd) @@ -5644,7 +5773,7 @@ broadcast_aen_retry: lun = sas_device_priv_data->lun; query_count++; - if (ioc->ioc_reset_in_progress_status) + if (ioc->shost_recovery) goto out; spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -5686,7 +5815,7 @@ broadcast_aen_retry: goto broadcast_aen_retry; } - if (ioc->ioc_reset_in_progress_status) + if (ioc->shost_recovery) goto out_no_lock; r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id, @@ -5725,7 +5854,7 @@ broadcast_aen_retry: ioc->name, __func__, query_count, termination_count)); ioc->broadcast_aen_busy = 0; - if (!ioc->ioc_reset_in_progress_status) + if (!ioc->shost_recovery) _scsih_ublock_io_all_device(ioc); mutex_unlock(&ioc->tm_cmds.mutex); } @@ -5789,8 +5918,11 @@ _scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach) static void _scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach) { - struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata; + struct MPT2SAS_TARGET *sas_target_priv_data; + if (starget == NULL) + return; + sas_target_priv_data = starget->hostdata; if (no_uld_attach) sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT; else @@ -5845,7 +5977,7 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc, raid_device->handle = handle; raid_device->wwid = wwid; _scsih_raid_device_add(ioc, raid_device); - if (!ioc->wait_for_port_enable_to_complete) { + if (!ioc->wait_for_discovery_to_complete) { rc = scsi_add_device(ioc->shost, RAID_CHANNEL, raid_device->id, 0); if (rc) @@ -6127,6 +6259,10 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, _scsih_sas_ir_config_change_event_debug(ioc, event_data); #endif + + if (ioc->shost_recovery) + return; + foreign_config = (le32_to_cpu(event_data->Flags) & MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; @@ -6185,6 +6321,9 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, int rc; Mpi2EventDataIrVolume_t *event_data = fw_event->event_data; + if (ioc->shost_recovery) + return; + if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) return; @@ -6267,6 +6406,9 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data; u64 sas_address; + if (ioc->shost_recovery) + return; + if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED) return; @@ -6510,10 +6652,10 @@ _scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc) u32 device_info; u16 slot; - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); + printk(MPT2SAS_INFO_FMT "search for end-devices: start\n", ioc->name); if (list_empty(&ioc->sas_device_list)) - return; + goto out; handle = 0xFFFF; while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, @@ -6532,6 +6674,9 @@ _scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc) _scsih_mark_responding_sas_device(ioc, sas_address, slot, handle); } +out: + printk(MPT2SAS_INFO_FMT "search for end-devices: complete\n", + ioc->name); } /** @@ -6607,10 +6752,14 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) u16 handle; u8 phys_disk_num; - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); + if (!ioc->ir_firmware) + return; + + printk(MPT2SAS_INFO_FMT "search for raid volumes: start\n", + ioc->name); if (list_empty(&ioc->raid_device_list)) - return; + goto out; handle = 0xFFFF; while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, @@ -6649,6 +6798,9 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) set_bit(handle, ioc->pd_handles); } } +out: + printk(MPT2SAS_INFO_FMT "search for responding raid volumes: " + "complete\n", ioc->name); } /** @@ -6708,10 +6860,10 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc) u64 sas_address; u16 handle; - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); + printk(MPT2SAS_INFO_FMT "search for expanders: start\n", ioc->name); if (list_empty(&ioc->sas_expander_list)) - return; + goto out; handle = 0xFFFF; while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, @@ -6730,6 +6882,8 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc) _scsih_mark_responding_expander(ioc, sas_address, handle); } + out: + printk(MPT2SAS_INFO_FMT "search for expanders: complete\n", ioc->name); } /** @@ -6745,6 +6899,8 @@ _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) struct _sas_node *sas_expander; struct _raid_device *raid_device, *raid_device_next; + printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n", + ioc->name); list_for_each_entry_safe(sas_device, sas_device_next, &ioc->sas_device_list, list) { @@ -6764,6 +6920,9 @@ _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) _scsih_remove_device(ioc, sas_device); } + if (!ioc->ir_firmware) + goto retry_expander_search; + list_for_each_entry_safe(raid_device, raid_device_next, &ioc->raid_device_list, list) { if (raid_device->responding) { @@ -6790,52 +6949,170 @@ _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) mpt2sas_expander_remove(ioc, sas_expander->sas_address); goto retry_expander_search; } + printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n", + ioc->name); + /* unblock devices */ + _scsih_ublock_io_all_device(ioc); +} + +static void +_scsih_refresh_expander_links(struct MPT2SAS_ADAPTER *ioc, + struct _sas_node *sas_expander, u16 handle) +{ + Mpi2ExpanderPage1_t expander_pg1; + Mpi2ConfigReply_t mpi_reply; + int i; + + for (i = 0 ; i < sas_expander->num_phys ; i++) { + if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, + &expander_pg1, i, handle))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + + mpt2sas_transport_update_links(ioc, sas_expander->sas_address, + le16_to_cpu(expander_pg1.AttachedDevHandle), i, + expander_pg1.NegotiatedLinkRate >> 4); + } } /** - * _scsih_hide_unhide_sas_devices - add/remove device to/from OS + * _scsih_scan_for_devices_after_reset - scan for devices after host reset * @ioc: per adapter object * * Return nothing. */ static void -_scsih_hide_unhide_sas_devices(struct MPT2SAS_ADAPTER *ioc) +_scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) { - struct _sas_device *sas_device, *sas_device_next; + Mpi2ExpanderPage0_t expander_pg0; + Mpi2SasDevicePage0_t sas_device_pg0; + Mpi2RaidVolPage1_t volume_pg1; + Mpi2RaidVolPage0_t volume_pg0; + Mpi2RaidPhysDiskPage0_t pd_pg0; + Mpi2EventIrConfigElement_t element; + Mpi2ConfigReply_t mpi_reply; + u8 phys_disk_num; + u16 ioc_status; + u16 handle, parent_handle; + u64 sas_address; + struct _sas_device *sas_device; + struct _sas_node *expander_device; + static struct _raid_device *raid_device; - if (!ioc->is_warpdrive || ioc->mfg_pg10_hide_flag != - MFG_PAGE10_HIDE_IF_VOL_PRESENT) - return; + printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name); - if (ioc->hide_drives) { - if (_scsih_get_num_volumes(ioc)) - return; - ioc->hide_drives = 0; - list_for_each_entry_safe(sas_device, sas_device_next, - &ioc->sas_device_list, list) { - if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); - } else if (!sas_device->starget) { - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - _scsih_sas_device_remove(ioc, sas_device); - } + _scsih_sas_host_refresh(ioc); + + /* expanders */ + handle = 0xFFFF; + while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, + MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + handle = le16_to_cpu(expander_pg0.DevHandle); + expander_device = mpt2sas_scsih_expander_find_by_sas_address( + ioc, le64_to_cpu(expander_pg0.SASAddress)); + if (expander_device) + _scsih_refresh_expander_links(ioc, expander_device, + handle); + else + _scsih_expander_add(ioc, handle); + } + + if (!ioc->ir_firmware) + goto skip_to_sas; + + /* phys disk */ + phys_disk_num = 0xFF; + while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, + &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, + phys_disk_num))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + phys_disk_num = pd_pg0.PhysDiskNum; + handle = le16_to_cpu(pd_pg0.DevHandle); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + if (sas_device) + continue; + if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, + &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, + handle) != 0) + continue; + parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); + if (!_scsih_get_sas_address(ioc, parent_handle, + &sas_address)) { + mpt2sas_transport_update_links(ioc, sas_address, + handle, sas_device_pg0.PhyNum, + MPI2_SAS_NEG_LINK_RATE_1_5); + set_bit(handle, ioc->pd_handles); + _scsih_add_device(ioc, handle, 0, 1); } - } else { - if (!_scsih_get_num_volumes(ioc)) - return; - ioc->hide_drives = 1; - list_for_each_entry_safe(sas_device, sas_device_next, - &ioc->sas_device_list, list) { - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); + } + + /* volumes */ + handle = 0xFFFF; + while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + handle = le16_to_cpu(volume_pg1.DevHandle); + raid_device = _scsih_raid_device_find_by_wwid(ioc, + le64_to_cpu(volume_pg1.WWID)); + if (raid_device) + continue; + if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, + &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, + sizeof(Mpi2RaidVolPage0_t))) + continue; + if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || + volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || + volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { + memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t)); + element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED; + element.VolDevHandle = volume_pg1.DevHandle; + _scsih_sas_volume_add(ioc, &element); } } + + skip_to_sas: + + /* sas devices */ + handle = 0xFFFF; + while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, + &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, + handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + handle = le16_to_cpu(sas_device_pg0.DevHandle); + if (!(_scsih_is_end_device( + le32_to_cpu(sas_device_pg0.DeviceInfo)))) + continue; + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + le64_to_cpu(sas_device_pg0.SASAddress)); + if (sas_device) + continue; + parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); + if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { + mpt2sas_transport_update_links(ioc, sas_address, handle, + sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); + _scsih_add_device(ioc, handle, 0, 0); + } + } + + printk(MPT2SAS_INFO_FMT "scan devices: complete\n", ioc->name); } + /** * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) * @ioc: per adapter object @@ -6871,7 +7148,6 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) } _scsih_fw_event_cleanup_queue(ioc); _scsih_flush_running_cmds(ioc); - _scsih_queue_rescan(ioc); break; case MPT2_IOC_DONE_RESET: dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " @@ -6881,6 +7157,13 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) _scsih_search_responding_sas_devices(ioc); _scsih_search_responding_raid_devices(ioc); _scsih_search_responding_expanders(ioc); + if (!ioc->is_driver_loading) { + _scsih_prep_device_scan(ioc); + _scsih_search_responding_sas_devices(ioc); + _scsih_search_responding_raid_devices(ioc); + _scsih_search_responding_expanders(ioc); + _scsih_error_recovery_delete_devices(ioc); + } break; } } @@ -6898,7 +7181,6 @@ _firmware_event_work(struct work_struct *work) { struct fw_event_work *fw_event = container_of(work, struct fw_event_work, delayed_work.work); - unsigned long flags; struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; /* the queue is being flushed so ignore this event */ @@ -6908,23 +7190,21 @@ _firmware_event_work(struct work_struct *work) return; } - if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) { - _scsih_fw_event_free(ioc, fw_event); - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->shost_recovery) { - init_completion(&ioc->shost_recovery_done); - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, - flags); - wait_for_completion(&ioc->shost_recovery_done); - } else - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, - flags); + switch (fw_event->event) { + case MPT2SAS_REMOVE_UNRESPONDING_DEVICES: + while (scsi_host_in_recovery(ioc->shost)) + ssleep(1); _scsih_remove_unresponding_sas_devices(ioc); - _scsih_hide_unhide_sas_devices(ioc); - return; - } + _scsih_scan_for_devices_after_reset(ioc); + break; + case MPT2SAS_PORT_ENABLE_COMPLETE: + ioc->start_scan = 0; - switch (fw_event->event) { + + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "port enable: complete " + "from worker thread\n", ioc->name)); + break; case MPT2SAS_TURN_ON_FAULT_LED: _scsih_turn_on_fault_led(ioc, fw_event->device_handle); break; @@ -7121,6 +7401,8 @@ static struct scsi_host_template scsih_driver_template = { .slave_configure = _scsih_slave_configure, .target_destroy = _scsih_target_destroy, .slave_destroy = _scsih_slave_destroy, + .scan_finished = _scsih_scan_finished, + .scan_start = _scsih_scan_start, .change_queue_depth = _scsih_change_queue_depth, .change_queue_type = _scsih_change_queue_type, .eh_abort_handler = _scsih_abort, @@ -7381,7 +7663,12 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) unsigned long flags; int rc; + /* no Bios, return immediately */ + if (!ioc->bios_pg3.BiosVersion) + return; + device = NULL; + is_raid = 0; if (ioc->req_boot_device.device) { device = ioc->req_boot_device.device; is_raid = ioc->req_boot_device.is_raid; @@ -7417,8 +7704,9 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); } else if (!sas_device->starget) { - mpt2sas_transport_port_remove(ioc, sas_address, - sas_address_parent); + if (!ioc->is_driver_loading) + mpt2sas_transport_port_remove(ioc, sas_address, + sas_address_parent); _scsih_sas_device_remove(ioc, sas_device); } } @@ -7462,22 +7750,28 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) /* SAS Device List */ list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list, list) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_move_tail(&sas_device->list, &ioc->sas_device_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (ioc->hide_drives) continue; if (!mpt2sas_transport_port_add(ioc, sas_device->handle, sas_device->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); + list_del(&sas_device->list); + kfree(sas_device); + continue; } else if (!sas_device->starget) { - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - _scsih_sas_device_remove(ioc, sas_device); + if (!ioc->is_driver_loading) + mpt2sas_transport_port_remove(ioc, + sas_device->sas_address, + sas_device->sas_address_parent); + list_del(&sas_device->list); + kfree(sas_device); + continue; + } + spin_lock_irqsave(&ioc->sas_device_lock, flags); + list_move_tail(&sas_device->list, &ioc->sas_device_list); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } } @@ -7490,9 +7784,7 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) static void _scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc) { - u16 volume_mapping_flags = - le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) & - MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + u16 volume_mapping_flags; if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR)) return; /* return when IOC doesn't support initiator mode */ @@ -7500,18 +7792,93 @@ _scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc) _scsih_probe_boot_devices(ioc); if (ioc->ir_firmware) { - if ((volume_mapping_flags & - MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) { - _scsih_probe_sas(ioc); + volume_mapping_flags = + le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + if (volume_mapping_flags == + MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { _scsih_probe_raid(ioc); + _scsih_probe_sas(ioc); } else { - _scsih_probe_raid(ioc); _scsih_probe_sas(ioc); + _scsih_probe_raid(ioc); } } else _scsih_probe_sas(ioc); } + +/** + * _scsih_scan_start - scsi lld callback for .scan_start + * @shost: SCSI host pointer + * + * The shost has the ability to discover targets on its own instead + * of scanning the entire bus. In our implemention, we will kick off + * firmware discovery. + */ +static void +_scsih_scan_start(struct Scsi_Host *shost) +{ + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + int rc; + + if (diag_buffer_enable != -1 && diag_buffer_enable != 0) + mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); + + ioc->start_scan = 1; + rc = mpt2sas_port_enable(ioc); + + if (rc != 0) + printk(MPT2SAS_INFO_FMT "port enable: FAILED\n", ioc->name); +} + +/** + * _scsih_scan_finished - scsi lld callback for .scan_finished + * @shost: SCSI host pointer + * @time: elapsed time of the scan in jiffies + * + * This function will be called periodically until it returns 1 with the + * scsi_host and the elapsed time of the scan in jiffies. In our implemention, + * we wait for firmware discovery to complete, then return 1. + */ +static int +_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) +{ + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + if (time >= (300 * HZ)) { + ioc->base_cmds.status = MPT2_CMD_NOT_USED; + printk(MPT2SAS_INFO_FMT "port enable: FAILED with timeout " + "(timeout=300s)\n", ioc->name); + ioc->is_driver_loading = 0; + return 1; + } + + if (ioc->start_scan) + return 0; + + if (ioc->start_scan_failed) { + printk(MPT2SAS_INFO_FMT "port enable: FAILED with " + "(ioc_status=0x%08x)\n", ioc->name, ioc->start_scan_failed); + ioc->is_driver_loading = 0; + ioc->wait_for_discovery_to_complete = 0; + ioc->remove_host = 1; + return 1; + } + + printk(MPT2SAS_INFO_FMT "port enable: SUCCESS\n", ioc->name); + ioc->base_cmds.status = MPT2_CMD_NOT_USED; + + if (ioc->wait_for_discovery_to_complete) { + ioc->wait_for_discovery_to_complete = 0; + _scsih_probe_devices(ioc); + } + mpt2sas_base_start_watchdog(ioc); + ioc->is_driver_loading = 0; + return 1; +} + + /** * _scsih_probe - attach and add scsi host * @pdev: PCI device struct @@ -7548,6 +7915,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->tm_cb_idx = tm_cb_idx; ioc->ctl_cb_idx = ctl_cb_idx; ioc->base_cb_idx = base_cb_idx; + ioc->port_enable_cb_idx = port_enable_cb_idx; ioc->transport_cb_idx = transport_cb_idx; ioc->scsih_cb_idx = scsih_cb_idx; ioc->config_cb_idx = config_cb_idx; @@ -7620,14 +7988,14 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_thread_fail; } - ioc->wait_for_port_enable_to_complete = 1; + ioc->is_driver_loading = 1; if ((mpt2sas_base_attach(ioc))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); goto out_attach_fail; } - ioc->wait_for_port_enable_to_complete = 0; + scsi_scan_host(shost); if (ioc->is_warpdrive) { if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) ioc->hide_drives = 0; @@ -7650,6 +8018,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) out_thread_fail: list_del(&ioc->list); scsi_remove_host(shost); + scsi_host_put(shost); out_add_shost_fail: return -ENODEV; } @@ -7896,6 +8265,8 @@ _scsih_init(void) /* base internal commands callback handler */ base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done); + port_enable_cb_idx = mpt2sas_base_register_callback_handler( + mpt2sas_port_enable_done); /* transport internal commands callback handler */ transport_cb_idx = mpt2sas_base_register_callback_handler( @@ -7950,6 +8321,7 @@ _scsih_exit(void) mpt2sas_base_release_callback_handler(scsi_io_cb_idx); mpt2sas_base_release_callback_handler(tm_cb_idx); mpt2sas_base_release_callback_handler(base_cb_idx); + mpt2sas_base_release_callback_handler(port_enable_cb_idx); mpt2sas_base_release_callback_handler(transport_cb_idx); mpt2sas_base_release_callback_handler(scsih_cb_idx); mpt2sas_base_release_callback_handler(config_cb_idx); diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 621b5e072758..6f589195746c 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -732,6 +732,16 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = { .class_mask = 0, .driver_data = chip_9485, }, + { PCI_VDEVICE(OCZ, 0x1021), chip_9485}, /* OCZ RevoDrive3 */ + { PCI_VDEVICE(OCZ, 0x1022), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1040), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1041), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1042), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1043), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1044), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1080), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1083), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1084), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ { } /* terminate list */ }; diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 86afb13f1e79..c06b8e5aa2cf 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -40,6 +40,7 @@ */ #include <linux/slab.h> +#include <linux/module.h> #include <scsi/osd_initiator.h> #include <scsi/osd_sec.h> diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index b86db84d6f32..5163edb925cb 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -4102,7 +4102,7 @@ static long pmcraid_chr_ioctl( struct pmcraid_ioctl_header *hdr = NULL; int retval = -ENOTTY; - hdr = kmalloc(GFP_KERNEL, sizeof(struct pmcraid_ioctl_header)); + hdr = kmalloc(sizeof(struct pmcraid_ioctl_header), GFP_KERNEL); if (!hdr) { pmcraid_err("faile to allocate memory for ioctl header\n"); diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c index cd178b9e40cd..959f10055be7 100644 --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -20,6 +20,7 @@ #include <linux/cdrom.h> #include <linux/highmem.h> +#include <linux/module.h> #include <linux/slab.h> #include <scsi/scsi.h> diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 3474e86e98ab..2516adf1aeea 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2279,7 +2279,7 @@ qla25xx_msix_rsp_q(int irq, void *dev_id) ha = rsp->hw; /* Clear the interrupt, if enabled, for this response queue */ - if (rsp->options & ~BIT_6) { + if (!ha->flags.disable_msix_handshake) { reg = &ha->iobase->isp24; spin_lock_irqsave(&ha->hardware_lock, flags); WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index fc3f168decb4..06bc26554a67 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -12,6 +12,7 @@ #include <linux/blkdev.h> #include <linux/completion.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/mempool.h> #include <linux/slab.h> #include <linux/init.h> @@ -1698,6 +1699,15 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) void scsi_free_queue(struct request_queue *q) { + unsigned long flags; + + WARN_ON(q->queuedata); + + /* cause scsi_request_fn() to kill all non-finished requests */ + spin_lock_irqsave(q->queue_lock, flags); + q->request_fn(q); + spin_unlock_irqrestore(q->queue_lock, flags); + blk_cleanup_queue(q); } diff --git a/drivers/scsi/scsi_lib_dma.c b/drivers/scsi/scsi_lib_dma.c index dcd128583b89..2ac3f3975f78 100644 --- a/drivers/scsi/scsi_lib_dma.c +++ b/drivers/scsi/scsi_lib_dma.c @@ -4,6 +4,7 @@ #include <linux/blkdev.h> #include <linux/device.h> +#include <linux/export.h> #include <linux/kernel.h> #include <scsi/scsi.h> diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 26a8a45584ef..44f76e8b58af 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -23,6 +23,7 @@ #include <linux/security.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/export.h> #include <net/sock.h> #include <net/netlink.h> diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index d82a023a9015..d329f8b12e2b 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -6,6 +6,7 @@ */ #include <linux/pm_runtime.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 44e8ca398efa..72273a0e5666 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -322,6 +322,7 @@ out_device_destroy: scsi_device_set_state(sdev, SDEV_DEL); transport_destroy_device(&sdev->sdev_gendev); put_device(&sdev->sdev_dev); + scsi_free_queue(sdev->request_queue); put_device(&sdev->sdev_gendev); out: if (display_failure_msg) diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c index 0172de197008..6209110f295d 100644 --- a/drivers/scsi/scsi_tgt_if.c +++ b/drivers/scsi/scsi_tgt_if.c @@ -22,6 +22,7 @@ #include <linux/miscdevice.h> #include <linux/gfp.h> #include <linux/file.h> +#include <linux/export.h> #include <net/tcp.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 1bcd65a509e6..96029e6d027f 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -520,7 +520,7 @@ fail_host_msg: /** * iscsi_bsg_host_add - Create and add the bsg hooks to receive requests * @shost: shost for iscsi_host - * @cls_host: iscsi_cls_host adding the structures to + * @ihost: iscsi_cls_host adding the structures to */ static int iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a7942e5c8be8..fa3a5918009c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2590,18 +2590,16 @@ static int sd_probe(struct device *dev) spin_unlock(&sd_index_lock); } while (error == -EAGAIN); - if (error) + if (error) { + sdev_printk(KERN_WARNING, sdp, "sd_probe: memory exhausted.\n"); goto out_put; - - if (index >= SD_MAX_DISKS) { - error = -ENODEV; - sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name space exhausted.\n"); - goto out_free_index; } error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN); - if (error) + if (error) { + sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name length exceeded.\n"); goto out_free_index; + } sdkp->device = sdp; sdkp->driver = &sd_template; diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 6ad798bfd52a..4163f2910e3d 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -9,12 +9,6 @@ #define SD_MAJORS 16 /* - * This is limited by the naming scheme enforced in sd_probe, - * add another character to it if you really need more disks. - */ -#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26) - -/* * Time out in seconds for disks and Magneto-opticals (which are slower). */ #define SD_TIMEOUT (30 * HZ) diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 8be30554119b..a3911c39ea50 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -4,6 +4,7 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/blkdev.h> +#include <linux/module.h> #include <linux/blkpg.h> #include <linux/cdrom.h> #include <linux/delay.h> diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 1871b8ae83ae..9b28f39bac26 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -462,14 +462,16 @@ static void st_scsi_execute_end(struct request *req, int uptodate) { struct st_request *SRpnt = req->end_io_data; struct scsi_tape *STp = SRpnt->stp; + struct bio *tmp; STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; STp->buffer->cmdstat.residual = req->resid_len; + tmp = SRpnt->bio; if (SRpnt->waiting) complete(SRpnt->waiting); - blk_rq_unmap_user(SRpnt->bio); + blk_rq_unmap_user(tmp); __blk_put_request(req->q, req); } diff --git a/drivers/sfi/sfi_core.h b/drivers/sfi/sfi_core.h index b7cf220d44ec..1d5cfe854cf7 100644 --- a/drivers/sfi/sfi_core.h +++ b/drivers/sfi/sfi_core.h @@ -55,6 +55,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include <linux/sysfs.h> + struct sfi_table_key{ char *sig; char *oem_id; diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c index e0ada3773786..7b246efa94ea 100644 --- a/drivers/sh/intc/chip.c +++ b/drivers/sh/intc/chip.c @@ -186,7 +186,7 @@ static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { !defined(CONFIG_CPU_SUBTYPE_SH7709) [IRQ_TYPE_LEVEL_HIGH] = VALID(3), #endif -#if defined(CONFIG_ARCH_SH7372) +#if defined(CONFIG_ARM) /* all recent SH-Mobile / R-Mobile ARM support this */ [IRQ_TYPE_EDGE_BOTH] = VALID(4), #endif }; diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index c6ca115c71df..8b7a141ff35e 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -22,6 +22,7 @@ #include <linux/irq.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/stat.h> #include <linux/interrupt.h> #include <linux/sh_intc.h> #include <linux/sysdev.h> @@ -29,6 +30,7 @@ #include <linux/list.h> #include <linux/spinlock.h> #include <linux/radix-tree.h> +#include <linux/export.h> #include "internals.h" LIST_HEAD(intc_list); diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c index a3677c9dfe36..5fea1ee8799a 100644 --- a/drivers/sh/intc/dynamic.c +++ b/drivers/sh/intc/dynamic.c @@ -14,6 +14,7 @@ #include <linux/irq.h> #include <linux/bitmap.h> #include <linux/spinlock.h> +#include <linux/module.h> #include "internals.h" /* only for activate_irq() damage.. */ /* diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c index 1e6e2d0353ea..c7ec49ffd9f6 100644 --- a/drivers/sh/intc/virq.c +++ b/drivers/sh/intc/virq.c @@ -14,6 +14,7 @@ #include <linux/list.h> #include <linux/radix-tree.h> #include <linux/spinlock.h> +#include <linux/export.h> #include "internals.h" static struct intc_map_entry intc_irq_xlate[NR_IRQS]; diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index 1e20604257af..bec81c2404f7 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c @@ -20,6 +20,7 @@ #include <linux/maple.h> #include <linux/dma-mapping.h> #include <linux/delay.h> +#include <linux/module.h> #include <asm/cacheflush.h> #include <asm/dma.h> #include <asm/io.h> diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index 881c1967741d..c00d00e96ee4 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -16,6 +16,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/errno.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index bddee5f516b2..5784c8799616 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -25,6 +25,7 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/errno.h> +#include <linux/module.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/resource.h> diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 02d57fbba295..aef59b1a15f7 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -20,6 +20,7 @@ #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/platform_device.h> diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c index 9f907ec52def..5ed08e537433 100644 --- a/drivers/spi/spi-butterfly.c +++ b/drivers/spi/spi-butterfly.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/device.h> #include <linux/parport.h> diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index fac399c3022c..db2f1ba06eab 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/scatterlist.h> +#include <linux/module.h> #include "spi-dw.h" diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index c5f37f03ac8b..f64250ea1611 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -21,6 +21,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/spi/spi.h> +#include <linux/module.h> #include "spi-dw.h" diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 296d94f4cf72..082458d73ce9 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -19,6 +19,7 @@ #include <linux/dma-mapping.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/highmem.h> #include <linux/delay.h> #include <linux/slab.h> diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 635ff08b377f..e093d3ec41ba 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -18,6 +18,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/gpio.h> diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 897274e8715c..698018fd992b 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -18,6 +18,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/errno.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 00a8e9d7dbe4..610f7391456e 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -45,6 +45,7 @@ #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> +#include <linux/module.h> #include <asm/system.h> #include <asm/irq.h> diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 9421a390a5e3..13448c832c44 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -17,6 +17,7 @@ #include <linux/io.h> #include <linux/spi/spi.h> #include <linux/spi/orion_spi.h> +#include <linux/module.h> #include <asm/unaligned.h> #define DRIVER_NAME "orion_spi" diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 378e504f89eb..8caa07d58e69 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -5,6 +5,7 @@ #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/of_device.h> +#include <linux/module.h> #include <linux/spi/pxa2xx_spi.h> struct ce4100_info { diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index b857a3e7af94..fc064535f4fc 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -24,6 +24,7 @@ #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> +#include <linux/module.h> #include <plat/regs-spi.h> #include <mach/spi.h> diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 595dacc7645f..019a7163572f 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -131,6 +131,12 @@ #define RXBUSY (1<<2) #define TXBUSY (1<<3) +struct s3c64xx_spi_dma_data { + unsigned ch; + enum dma_data_direction direction; + enum dma_ch dmach; +}; + /** * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver. * @clk: Pointer to the spi clock. @@ -164,13 +170,14 @@ struct s3c64xx_spi_driver_data { struct work_struct work; struct list_head queue; spinlock_t lock; - enum dma_ch rx_dmach; - enum dma_ch tx_dmach; unsigned long sfr_start; struct completion xfer_completion; unsigned state; unsigned cur_mode, cur_bpw; unsigned cur_speed; + struct s3c64xx_spi_dma_data rx_dma; + struct s3c64xx_spi_dma_data tx_dma; + struct samsung_dma_ops *ops; }; static struct s3c2410_dma_client s3c64xx_spi_dma_client = { @@ -226,6 +233,78 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) writel(val, regs + S3C64XX_SPI_CH_CFG); } +static void s3c64xx_spi_dmacb(void *data) +{ + struct s3c64xx_spi_driver_data *sdd; + struct s3c64xx_spi_dma_data *dma = data; + unsigned long flags; + + if (dma->direction == DMA_FROM_DEVICE) + sdd = container_of(data, + struct s3c64xx_spi_driver_data, rx_dma); + else + sdd = container_of(data, + struct s3c64xx_spi_driver_data, tx_dma); + + spin_lock_irqsave(&sdd->lock, flags); + + if (dma->direction == DMA_FROM_DEVICE) { + sdd->state &= ~RXBUSY; + if (!(sdd->state & TXBUSY)) + complete(&sdd->xfer_completion); + } else { + sdd->state &= ~TXBUSY; + if (!(sdd->state & RXBUSY)) + complete(&sdd->xfer_completion); + } + + spin_unlock_irqrestore(&sdd->lock, flags); +} + +static void prepare_dma(struct s3c64xx_spi_dma_data *dma, + unsigned len, dma_addr_t buf) +{ + struct s3c64xx_spi_driver_data *sdd; + struct samsung_dma_prep_info info; + + if (dma->direction == DMA_FROM_DEVICE) + sdd = container_of((void *)dma, + struct s3c64xx_spi_driver_data, rx_dma); + else + sdd = container_of((void *)dma, + struct s3c64xx_spi_driver_data, tx_dma); + + info.cap = DMA_SLAVE; + info.len = len; + info.fp = s3c64xx_spi_dmacb; + info.fp_param = dma; + info.direction = dma->direction; + info.buf = buf; + + sdd->ops->prepare(dma->ch, &info); + sdd->ops->trigger(dma->ch); +} + +static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) +{ + struct samsung_dma_info info; + + sdd->ops = samsung_dma_get_ops(); + + info.cap = DMA_SLAVE; + info.client = &s3c64xx_spi_dma_client; + info.width = sdd->cur_bpw / 8; + + info.direction = sdd->rx_dma.direction; + info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA; + sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &info); + info.direction = sdd->tx_dma.direction; + info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA; + sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &info); + + return 1; +} + static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi, struct spi_transfer *xfer, int dma_mode) @@ -258,10 +337,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, chcfg |= S3C64XX_SPI_CH_TXCH_ON; if (dma_mode) { modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; - s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8); - s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd, - xfer->tx_dma, xfer->len); - s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START); + prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma); } else { switch (sdd->cur_bpw) { case 32: @@ -293,10 +369,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | S3C64XX_SPI_PACKET_CNT_EN, regs + S3C64XX_SPI_PACKET_CNT); - s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8); - s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd, - xfer->rx_dma, xfer->len); - s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START); + prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma); } } @@ -482,46 +555,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) } } -static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, - int size, enum s3c2410_dma_buffresult res) -{ - struct s3c64xx_spi_driver_data *sdd = buf_id; - unsigned long flags; - - spin_lock_irqsave(&sdd->lock, flags); - - if (res == S3C2410_RES_OK) - sdd->state &= ~RXBUSY; - else - dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size); - - /* If the other done */ - if (!(sdd->state & TXBUSY)) - complete(&sdd->xfer_completion); - - spin_unlock_irqrestore(&sdd->lock, flags); -} - -static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id, - int size, enum s3c2410_dma_buffresult res) -{ - struct s3c64xx_spi_driver_data *sdd = buf_id; - unsigned long flags; - - spin_lock_irqsave(&sdd->lock, flags); - - if (res == S3C2410_RES_OK) - sdd->state &= ~TXBUSY; - else - dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size); - - /* If the other done */ - if (!(sdd->state & RXBUSY)) - complete(&sdd->xfer_completion); - - spin_unlock_irqrestore(&sdd->lock, flags); -} - #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32) static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, @@ -696,12 +729,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, if (use_dma) { if (xfer->tx_buf != NULL && (sdd->state & TXBUSY)) - s3c2410_dma_ctrl(sdd->tx_dmach, - S3C2410_DMAOP_FLUSH); + sdd->ops->stop(sdd->tx_dma.ch); if (xfer->rx_buf != NULL && (sdd->state & RXBUSY)) - s3c2410_dma_ctrl(sdd->rx_dmach, - S3C2410_DMAOP_FLUSH); + sdd->ops->stop(sdd->rx_dma.ch); } goto out; @@ -739,30 +770,6 @@ out: msg->complete(msg->context); } -static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) -{ - if (s3c2410_dma_request(sdd->rx_dmach, - &s3c64xx_spi_dma_client, NULL) < 0) { - dev_err(&sdd->pdev->dev, "cannot get RxDMA\n"); - return 0; - } - s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb); - s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW, - sdd->sfr_start + S3C64XX_SPI_RX_DATA); - - if (s3c2410_dma_request(sdd->tx_dmach, - &s3c64xx_spi_dma_client, NULL) < 0) { - dev_err(&sdd->pdev->dev, "cannot get TxDMA\n"); - s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client); - return 0; - } - s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb); - s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM, - sdd->sfr_start + S3C64XX_SPI_TX_DATA); - - return 1; -} - static void s3c64xx_spi_work(struct work_struct *work) { struct s3c64xx_spi_driver_data *sdd = container_of(work, @@ -799,8 +806,8 @@ static void s3c64xx_spi_work(struct work_struct *work) spin_unlock_irqrestore(&sdd->lock, flags); /* Free DMA channels */ - s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client); - s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client); + sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client); + sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client); } static int s3c64xx_spi_transfer(struct spi_device *spi, @@ -1017,8 +1024,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) sdd->cntrlr_info = sci; sdd->pdev = pdev; sdd->sfr_start = mem_res->start; - sdd->tx_dmach = dmatx_res->start; - sdd->rx_dmach = dmarx_res->start; + sdd->tx_dma.dmach = dmatx_res->start; + sdd->tx_dma.direction = DMA_TO_DEVICE; + sdd->rx_dma.dmach = dmarx_res->start; + sdd->rx_dma.direction = DMA_FROM_DEVICE; sdd->cur_bpw = 8; @@ -1106,7 +1115,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) pdev->id, master->num_chipselect); dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n", mem_res->end, mem_res->start, - sdd->rx_dmach, sdd->tx_dmach); + sdd->rx_dma.dmach, sdd->tx_dma.dmach); return 0; diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 0f4834ae28cd..1f466bc66d9d 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -19,6 +19,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 8844bc342782..097e506042be 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -22,6 +22,7 @@ #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> +#include <linux/module.h> #include <asm/spi.h> #include <asm/io.h> diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c index 7963c60063d6..3f6f6e81c655 100644 --- a/drivers/spi/spi-ti-ssp.c +++ b/drivers/spi/spi-ti-ssp.c @@ -22,6 +22,7 @@ #include <linux/err.h> #include <linux/completion.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/mfd/ti_ssp.h> diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c index 940e73d1cf09..0ce5c12aab55 100644 --- a/drivers/spi/spi-tle62x0.c +++ b/drivers/spi/spi-tle62x0.c @@ -11,6 +11,7 @@ #include <linux/device.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/spi/spi.h> diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index f0a2ab0428a3..d5a3cbb646cb 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -25,6 +25,7 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/module.h> #include <asm/gpio.h> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4d1b9f517ce8..77eae99af11c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -29,6 +29,7 @@ #include <linux/spi/spi.h> #include <linux/of_spi.h> #include <linux/pm_runtime.h> +#include <linux/export.h> static void spidev_release(struct device *dev) { diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c index bf53e44c82a1..bad7ba517a1c 100644 --- a/drivers/ssb/b43_pci_bridge.c +++ b/drivers/ssb/b43_pci_bridge.c @@ -11,6 +11,7 @@ */ #include <linux/pci.h> +#include <linux/module.h> #include <linux/ssb/ssb.h> #include "ssb_private.h" diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 5d9c97c24797..e9d2ca11283b 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -10,6 +10,7 @@ #include <linux/ssb/ssb.h> #include <linux/ssb/ssb_regs.h> +#include <linux/export.h> #include <linux/pci.h> #include "ssb_private.h" diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index 52901c14c68b..e5a2e0e9bc19 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -12,6 +12,7 @@ #include <linux/ssb/ssb_regs.h> #include <linux/ssb/ssb_driver_chipcommon.h> #include <linux/delay.h> +#include <linux/export.h> #include "ssb_private.h" diff --git a/drivers/ssb/driver_gige.c b/drivers/ssb/driver_gige.c index 3adb98dad70c..f30ea689933a 100644 --- a/drivers/ssb/driver_gige.c +++ b/drivers/ssb/driver_gige.c @@ -10,6 +10,7 @@ #include <linux/ssb/ssb.h> #include <linux/ssb/ssb_driver_gige.h> +#include <linux/export.h> #include <linux/pci.h> #include <linux/pci_regs.h> #include <linux/slab.h> diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index e6ac3177fbbe..84c934c0a545 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -10,6 +10,7 @@ #include <linux/ssb/ssb.h> #include <linux/pci.h> +#include <linux/export.h> #include <linux/delay.h> #include <linux/ssb/ssb_embedded.h> diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c index eec3e267be4d..9ef124f9ee2d 100644 --- a/drivers/ssb/embedded.c +++ b/drivers/ssb/embedded.c @@ -8,6 +8,7 @@ * Licensed under the GNU/GPL. See COPYING for details. */ +#include <linux/export.h> #include <linux/ssb/ssb.h> #include <linux/ssb/ssb_embedded.h> #include <linux/ssb/ssb_driver_pci.h> diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index d0cbdb0cf9d5..bb6317fb925c 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -12,6 +12,7 @@ #include <linux/delay.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/ssb/ssb.h> #include <linux/ssb/ssb_regs.h> #include <linux/ssb/ssb_driver_gige.h> diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c index 116a8116984b..af5448f5e2d2 100644 --- a/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c @@ -12,6 +12,7 @@ */ #include <linux/pci.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/ssb/ssb.h> diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c index 24e009c0149b..911c0e4375fd 100644 --- a/drivers/staging/cxt1e1/linux.c +++ b/drivers/staging/cxt1e1/linux.c @@ -16,6 +16,7 @@ #include <linux/types.h> #include <linux/netdevice.h> +#include <linux/module.h> #include <linux/hdlc.h> #include <linux/if_arp.h> #include <linux/init.h> diff --git a/drivers/staging/gma500/intel_i2c.c b/drivers/staging/gma500/intel_i2c.c index e33432df510c..51cbf65268e6 100644 --- a/drivers/staging/gma500/intel_i2c.c +++ b/drivers/staging/gma500/intel_i2c.c @@ -20,6 +20,7 @@ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> +#include <linux/export.h> #include "psb_drv.h" #include "psb_intel_reg.h" diff --git a/drivers/staging/gma500/mdfld_dsi_output.c b/drivers/staging/gma500/mdfld_dsi_output.c index 9050c0f78b15..3f979db2c3a5 100644 --- a/drivers/staging/gma500/mdfld_dsi_output.c +++ b/drivers/staging/gma500/mdfld_dsi_output.c @@ -32,6 +32,7 @@ #include <asm/intel_scu_ipc.h> #include "mdfld_dsi_pkg_sender.h" #include <linux/pm_runtime.h> +#include <linux/moduleparam.h> #define MDFLD_DSI_BRIGHTNESS_MAX_LEVEL 100 diff --git a/drivers/staging/gma500/mdfld_output.c b/drivers/staging/gma500/mdfld_output.c index ee55f87ba1fd..eabf53d58f92 100644 --- a/drivers/staging/gma500/mdfld_output.c +++ b/drivers/staging/gma500/mdfld_output.c @@ -26,6 +26,7 @@ */ #include <linux/init.h> +#include <linux/moduleparam.h> #include "mdfld_dsi_dbi.h" #include "mdfld_dsi_dpi.h" #include "mdfld_dsi_output.h" @@ -167,4 +168,4 @@ void mdfld_output_setup(struct drm_device *dev) else mdfld_dbi_dsr_init(dev); } -}
\ No newline at end of file +} diff --git a/drivers/staging/gma500/mid_bios.c b/drivers/staging/gma500/mid_bios.c index 8cfe301f8fb2..ee3c0368e320 100644 --- a/drivers/staging/gma500/mid_bios.c +++ b/drivers/staging/gma500/mid_bios.c @@ -23,6 +23,7 @@ * - Check ioremap failures */ +#include <linux/moduleparam.h> #include <drm/drmP.h> #include <drm/drm.h> #include "psb_drm.h" diff --git a/drivers/staging/gma500/mrst_hdmi_i2c.c b/drivers/staging/gma500/mrst_hdmi_i2c.c index 351b9d897b9f..36e7edc4d14c 100644 --- a/drivers/staging/gma500/mrst_hdmi_i2c.c +++ b/drivers/staging/gma500/mrst_hdmi_i2c.c @@ -29,6 +29,7 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/delay.h> +#include <linux/export.h> #include "psb_drv.h" #define HDMI_READ(reg) readl(hdmi_dev->regs + (reg)) diff --git a/drivers/staging/gma500/psb_drv.c b/drivers/staging/gma500/psb_drv.c index dc676c2ce810..986a04d16ba8 100644 --- a/drivers/staging/gma500/psb_drv.c +++ b/drivers/staging/gma500/psb_drv.c @@ -35,6 +35,7 @@ #include <linux/notifier.h> #include <linux/spinlock.h> #include <linux/pm_runtime.h> +#include <linux/module.h> #include <acpi/video.h> static int drm_psb_trap_pagefaults; diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c index dbd883294d6c..0016ed378e3a 100644 --- a/drivers/staging/iio/accel/adis16201_ring.c +++ b/drivers/staging/iio/accel/adis16201_ring.c @@ -1,3 +1,4 @@ +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/kernel.h> diff --git a/drivers/staging/iio/accel/adis16201_trigger.c b/drivers/staging/iio/accel/adis16201_trigger.c index f448258884c5..bce505e716d0 100644 --- a/drivers/staging/iio/accel/adis16201_trigger.c +++ b/drivers/staging/iio/accel/adis16201_trigger.c @@ -1,6 +1,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spi/spi.h> +#include <linux/export.h> #include "../iio.h" #include "../trigger.h" diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c index 838d3012c87b..1fdfe6f6ac6e 100644 --- a/drivers/staging/iio/accel/adis16203_ring.c +++ b/drivers/staging/iio/accel/adis16203_ring.c @@ -1,3 +1,4 @@ +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/kernel.h> diff --git a/drivers/staging/iio/accel/adis16203_trigger.c b/drivers/staging/iio/accel/adis16203_trigger.c index 50165f9ddc52..24bcb8e15c55 100644 --- a/drivers/staging/iio/accel/adis16203_trigger.c +++ b/drivers/staging/iio/accel/adis16203_trigger.c @@ -1,6 +1,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spi/spi.h> +#include <linux/export.h> #include "../iio.h" #include "../trigger.h" diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c index 08551bb48f18..6fd3d8f51f2c 100644 --- a/drivers/staging/iio/accel/adis16204_ring.c +++ b/drivers/staging/iio/accel/adis16204_ring.c @@ -1,3 +1,4 @@ +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/kernel.h> diff --git a/drivers/staging/iio/accel/adis16204_trigger.c b/drivers/staging/iio/accel/adis16204_trigger.c index 55b661c98d2d..6e542af02c09 100644 --- a/drivers/staging/iio/accel/adis16204_trigger.c +++ b/drivers/staging/iio/accel/adis16204_trigger.c @@ -1,6 +1,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spi/spi.h> +#include <linux/export.h> #include "../iio.h" #include "../trigger.h" diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c index bb66364bef04..d17e39d95459 100644 --- a/drivers/staging/iio/accel/adis16209_ring.c +++ b/drivers/staging/iio/accel/adis16209_ring.c @@ -1,3 +1,4 @@ +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/kernel.h> diff --git a/drivers/staging/iio/accel/adis16209_trigger.c b/drivers/staging/iio/accel/adis16209_trigger.c index 8df8a9791d5e..c5d82c1a55d9 100644 --- a/drivers/staging/iio/accel/adis16209_trigger.c +++ b/drivers/staging/iio/accel/adis16209_trigger.c @@ -1,6 +1,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spi/spi.h> +#include <linux/export.h> #include "../iio.h" #include "../trigger.h" diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c index 34f1e7e6a56f..b907ca3f4fdf 100644 --- a/drivers/staging/iio/accel/adis16240_ring.c +++ b/drivers/staging/iio/accel/adis16240_ring.c @@ -1,3 +1,4 @@ +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/kernel.h> diff --git a/drivers/staging/iio/accel/adis16240_trigger.c b/drivers/staging/iio/accel/adis16240_trigger.c index 13f1d142eea3..8e0ce568e64c 100644 --- a/drivers/staging/iio/accel/adis16240_trigger.c +++ b/drivers/staging/iio/accel/adis16240_trigger.c @@ -1,6 +1,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spi/spi.h> +#include <linux/export.h> #include "../iio.h" #include "../trigger.h" diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index 5c542dd04616..89527af8f4c5 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -4,6 +4,7 @@ #include <linux/kernel.h> #include <linux/spi/spi.h> #include <linux/slab.h> +#include <linux/export.h> #include "../iio.h" #include "../ring_sw.h" diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c index a831b92cd082..999f8f746cff 100644 --- a/drivers/staging/iio/adc/ad7793.c +++ b/drivers/staging/iio/adc/ad7793.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/sched.h> #include <linux/delay.h> +#include <linux/module.h> #include "../iio.h" #include "../sysfs.h" diff --git a/drivers/staging/iio/dac/ad5686.c b/drivers/staging/iio/dac/ad5686.c index 48389e1c19f1..974c6f5b60c4 100644 --- a/drivers/staging/iio/dac/ad5686.c +++ b/drivers/staging/iio/dac/ad5686.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/sysfs.h> #include <linux/regulator/consumer.h> +#include <linux/module.h> #include "../iio.h" #include "../sysfs.h" diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c index 38cf3f4bf726..ff1b5a82b3d6 100644 --- a/drivers/staging/iio/gyro/adis16060_core.c +++ b/drivers/staging/iio/gyro/adis16060_core.c @@ -6,6 +6,7 @@ * Licensed under the GPL-2 or later. */ +#include <linux/module.h> #include <linux/delay.h> #include <linux/mutex.h> #include <linux/device.h> diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c index 679c15155716..52a9e784e7c8 100644 --- a/drivers/staging/iio/gyro/adis16260_ring.c +++ b/drivers/staging/iio/gyro/adis16260_ring.c @@ -1,3 +1,4 @@ +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/kernel.h> diff --git a/drivers/staging/iio/gyro/adis16260_trigger.c b/drivers/staging/iio/gyro/adis16260_trigger.c index 2f2b2160f44d..8299cd18d705 100644 --- a/drivers/staging/iio/gyro/adis16260_trigger.c +++ b/drivers/staging/iio/gyro/adis16260_trigger.c @@ -1,6 +1,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spi/spi.h> +#include <linux/export.h> #include "../iio.h" #include "../trigger.h" diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c index f0b36d25414d..edad0e7b4f4d 100644 --- a/drivers/staging/iio/iio_simple_dummy_buffer.c +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c @@ -12,6 +12,7 @@ */ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/irq.h> diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index c3682458d78d..fd886bf51a6d 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -4,6 +4,7 @@ #include <linux/spi/spi.h> #include <linux/slab.h> #include <linux/bitops.h> +#include <linux/export.h> #include "../iio.h" #include "../ring_sw.h" diff --git a/drivers/staging/iio/imu/adis16400_trigger.c b/drivers/staging/iio/imu/adis16400_trigger.c index bf991531e0d6..5bf000757522 100644 --- a/drivers/staging/iio/imu/adis16400_trigger.c +++ b/drivers/staging/iio/imu/adis16400_trigger.c @@ -1,6 +1,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spi/spi.h> +#include <linux/export.h> #include "../iio.h" #include "../trigger.h" diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/staging/iio/industrialio-buffer.c index 6dd5d7d629a1..9df0ce81dade 100644 --- a/drivers/staging/iio/industrialio-buffer.c +++ b/drivers/staging/iio/industrialio-buffer.c @@ -14,6 +14,7 @@ * - Alternative access techniques? */ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/device.h> #include <linux/fs.h> #include <linux/cdev.h> diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c index 99ade658a2dc..00fa2ac5c459 100644 --- a/drivers/staging/iio/meter/ade7758_ring.c +++ b/drivers/staging/iio/meter/ade7758_ring.c @@ -5,6 +5,7 @@ * * Licensed under the GPL-2. */ +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spi/spi.h> diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c index 392dfe302443..b6569c706651 100644 --- a/drivers/staging/iio/meter/ade7758_trigger.c +++ b/drivers/staging/iio/meter/ade7758_trigger.c @@ -9,6 +9,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/spi/spi.h> +#include <linux/export.h> #include "../iio.h" #include "../trigger.h" diff --git a/drivers/staging/intel_sst/intel_sst.c b/drivers/staging/intel_sst/intel_sst.c index c303d85011b0..ff9aaec0557f 100644 --- a/drivers/staging/intel_sst/intel_sst.c +++ b/drivers/staging/intel_sst/intel_sst.c @@ -37,6 +37,7 @@ #include <linux/firmware.h> #include <linux/miscdevice.h> #include <linux/pm_runtime.h> +#include <linux/module.h> #include <asm/mrst.h> #include "intel_sst.h" #include "intel_sst_ioctl.h" diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c index 69daa1404b68..22bd29c0c439 100644 --- a/drivers/staging/intel_sst/intel_sst_drv_interface.c +++ b/drivers/staging/intel_sst/intel_sst_drv_interface.c @@ -33,6 +33,7 @@ #include <linux/fs.h> #include <linux/firmware.h> #include <linux/pm_runtime.h> +#include <linux/export.h> #include "intel_sst.h" #include "intel_sst_ioctl.h" #include "intel_sst_fw_ipc.h" diff --git a/drivers/staging/line6/audio.c b/drivers/staging/line6/audio.c index 61db1f99b0c8..8e7398393a59 100644 --- a/drivers/staging/line6/audio.c +++ b/drivers/staging/line6/audio.c @@ -11,6 +11,7 @@ #include <sound/core.h> #include <sound/initval.h> +#include <linux/export.h> #include "driver.h" #include "audio.h" diff --git a/drivers/staging/media/solo6x10/g723.c b/drivers/staging/media/solo6x10/g723.c index 59274bfca95b..2cd0de28a633 100644 --- a/drivers/staging/media/solo6x10/g723.c +++ b/drivers/staging/media/solo6x10/g723.c @@ -23,6 +23,7 @@ #include <linux/kthread.h> #include <linux/slab.h> #include <linux/freezer.h> +#include <linux/export.h> #include <sound/core.h> #include <sound/initval.h> #include <sound/pcm.h> diff --git a/drivers/staging/rts5139/rts51x_scsi.c b/drivers/staging/rts5139/rts51x_scsi.c index 3b32f9e6e4f0..87c9cdc8bd29 100644 --- a/drivers/staging/rts5139/rts51x_scsi.c +++ b/drivers/staging/rts5139/rts51x_scsi.c @@ -28,6 +28,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_eh.h> diff --git a/drivers/staging/spectra/lld_mtd.c b/drivers/staging/spectra/lld_mtd.c index 2bd34662beb5..a9c309a167c2 100644 --- a/drivers/staging/spectra/lld_mtd.c +++ b/drivers/staging/spectra/lld_mtd.c @@ -340,7 +340,7 @@ u16 mtd_Read_Page_Main_Spare(u8 *read_data, u32 Block, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = read_data; ops.len = DeviceInfo.wPageDataSize; ops.oobbuf = read_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET; @@ -400,7 +400,7 @@ u16 mtd_Write_Page_Main_Spare(u8 *write_data, u32 Block, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = write_data; ops.len = DeviceInfo.wPageDataSize; ops.oobbuf = write_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET; @@ -473,7 +473,7 @@ u16 mtd_Read_Page_Spare(u8 *read_data, u32 Block, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = NULL; ops.len = 0; ops.oobbuf = read_data; diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index f4b53d103c54..3b7a847f4657 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -22,6 +22,7 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/module.h> #include <net/sock.h> #include "usbip_common.h" diff --git a/drivers/staging/usbip/usbip_event.c b/drivers/staging/usbip/usbip_event.c index ecd1862539cd..d332a34ddb6d 100644 --- a/drivers/staging/usbip/usbip_event.c +++ b/drivers/staging/usbip/usbip_event.c @@ -18,6 +18,7 @@ */ #include <linux/kthread.h> +#include <linux/export.h> #include "usbip_common.h" diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index a2e8bd452ed9..f958eb4f0d81 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -11,6 +11,7 @@ */ #include <net/mac80211.h> #include <linux/usb.h> +#include <linux/module.h> #include "core.h" #include "mds_f.h" diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c index 321580267fed..2faee2dd4bb1 100644 --- a/drivers/staging/wlags49_h2/wl_cs.c +++ b/drivers/staging/wlags49_h2/wl_cs.c @@ -82,6 +82,7 @@ #include <linux/skbuff.h> #include <linux/if_arp.h> #include <linux/ioport.h> +#include <linux/module.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index b9926ee0052c..09de99fbb7e0 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -556,7 +556,7 @@ static inline int valid_io_request(struct zram *zram, struct bio *bio) /* * Handler function for all zram I/O requests. */ -static int zram_make_request(struct request_queue *queue, struct bio *bio) +static void zram_make_request(struct request_queue *queue, struct bio *bio) { struct zram *zram = queue->queuedata; @@ -575,13 +575,12 @@ static int zram_make_request(struct request_queue *queue, struct bio *bio) __zram_make_request(zram, bio, bio_data_dir(bio)); up_read(&zram->init_lock); - return 0; + return; error_unlock: up_read(&zram->init_lock); error: bio_io_error(bio); - return 0; } void __zram_reset_device(struct zram *zram) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 4d01768fcd90..0fd96c10271d 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -22,6 +22,7 @@ #include <linux/kthread.h> #include <linux/crypto.h> #include <linux/completion.h> +#include <linux/module.h> #include <asm/unaligned.h> #include <scsi/scsi_device.h> #include <scsi/iscsi_proto.h> @@ -1079,7 +1080,9 @@ attach_cmd: */ if (!cmd->immediate_data) { cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); - if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) + if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) + return 0; + else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) return iscsit_add_reject_from_cmd( ISCSI_REASON_PROTOCOL_ERROR, 1, 0, buf, cmd); @@ -1819,17 +1822,16 @@ attach: int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) out_of_order_cmdsn = 1; - else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { + else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) return 0; - } else { /* (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) */ + else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) return iscsit_add_reject_from_cmd( ISCSI_REASON_PROTOCOL_ERROR, 1, 0, buf, cmd); - } } iscsit_ack_from_expstatsn(conn, hdr->exp_statsn); - if (out_of_order_cmdsn) + if (out_of_order_cmdsn || !(hdr->opcode & ISCSI_OP_IMMEDIATE)) return 0; /* * Found the referenced task, send to transport for processing. diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index f1643dbf6a92..db327845e46b 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -20,6 +20,7 @@ ****************************************************************************/ #include <linux/configfs.h> +#include <linux/export.h> #include <target/target_core_base.h> #include <target/target_core_transport.h> #include <target/target_core_fabric_ops.h> diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index bbdbe9301b27..f1db83077e0a 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c @@ -20,6 +20,7 @@ ******************************************************************************/ #include <linux/configfs.h> +#include <linux/export.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> #include <target/target_core_transport.h> diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index b15d8cbf630b..3df1c9b8ae6b 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -174,6 +174,24 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) sgl_bidi = sdb->table.sgl; sgl_bidi_count = sdb->table.nents; } + /* + * Because some userspace code via scsi-generic do not memset their + * associated read buffers, go ahead and do that here for type + * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently + * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB + * by target core in transport_generic_allocate_tasks() -> + * transport_generic_cmd_sequencer(). + */ + if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB && + se_cmd->data_direction == DMA_FROM_DEVICE) { + struct scatterlist *sg = scsi_sglist(sc); + unsigned char *buf = kmap(sg_page(sg)) + sg->offset; + + if (buf != NULL) { + memset(buf, 0, sg->length); + kunmap(sg_page(sg)); + } + } /* Tell the core about our preallocated memory */ ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc), @@ -187,7 +205,7 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) /* * Called from struct target_core_fabric_ops->check_stop_free() */ -static void tcm_loop_check_stop_free(struct se_cmd *se_cmd) +static int tcm_loop_check_stop_free(struct se_cmd *se_cmd) { /* * Do not release struct se_cmd's containing a valid TMR @@ -195,12 +213,13 @@ static void tcm_loop_check_stop_free(struct se_cmd *se_cmd) * with transport_generic_free_cmd(). */ if (se_cmd->se_tmr_req) - return; + return 0; /* * Release the struct se_cmd, which will make a callback to release * struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd() */ transport_generic_free_cmd(se_cmd, 0); + return 1; } static void tcm_loop_release_cmd(struct se_cmd *se_cmd) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 8f4447749c71..88f2ad43ec8b 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/configfs.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -58,8 +59,9 @@ struct t10_alua_lu_gp *default_lu_gp; * * See spc4r17 section 6.27 */ -int core_emulate_report_target_port_groups(struct se_cmd *cmd) +int target_emulate_report_target_port_groups(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; struct se_port *port; struct t10_alua_tg_pt_gp *tg_pt_gp; @@ -164,6 +166,8 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd) transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -172,8 +176,9 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd) * * See spc4r17 section 6.35 */ -int core_emulate_set_target_port_groups(struct se_cmd *cmd) +int target_emulate_set_target_port_groups(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; struct se_subsystem_dev *su_dev = dev->se_sub_dev; struct se_port *port, *l_port = cmd->se_lun->lun_sep; @@ -341,7 +346,8 @@ int core_emulate_set_target_port_groups(struct se_cmd *cmd) out: transport_kunmap_first_data_page(cmd); - + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index c86f97a081ed..c5b4ecd3e745 100644 --- a/drivers/target/target_core_alua.h +++ b/drivers/target/target_core_alua.h @@ -66,8 +66,8 @@ extern struct kmem_cache *t10_alua_lu_gp_mem_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -extern int core_emulate_report_target_port_groups(struct se_cmd *); -extern int core_emulate_set_target_port_groups(struct se_cmd *); +extern int target_emulate_report_target_port_groups(struct se_task *); +extern int target_emulate_set_target_port_groups(struct se_task *); extern int core_alua_check_nonop_delay(struct se_cmd *); extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *, struct se_device *, struct se_port *, diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 38535eb13929..683ba02b8247 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -32,6 +32,7 @@ #include <target/target_core_transport.h> #include <target/target_core_fabric_ops.h> #include "target_core_ua.h" +#include "target_core_cdb.h" static void target_fill_alua_data(struct se_port *port, unsigned char *buf) @@ -679,16 +680,18 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) return 0; } -static int -target_emulate_inquiry(struct se_cmd *cmd) +int target_emulate_inquiry(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned char *cdb = cmd->t_task_cdb; int p, ret; - if (!(cdb[1] & 0x1)) - return target_emulate_inquiry_std(cmd); + if (!(cdb[1] & 0x1)) { + ret = target_emulate_inquiry_std(cmd); + goto out; + } /* * Make sure we at least have 4 bytes of INQUIRY response @@ -707,22 +710,30 @@ target_emulate_inquiry(struct se_cmd *cmd) buf[0] = dev->transport->get_device_type(dev); - for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) + for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) { if (cdb[2] == evpd_handlers[p].page) { buf[1] = cdb[2]; ret = evpd_handlers[p].emulate(cmd, buf); - transport_kunmap_first_data_page(cmd); - return ret; + goto out_unmap; } + } - transport_kunmap_first_data_page(cmd); pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]); - return -EINVAL; + ret = -EINVAL; + +out_unmap: + transport_kunmap_first_data_page(cmd); +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } -static int -target_emulate_readcapacity(struct se_cmd *cmd) +int target_emulate_readcapacity(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned long long blocks_long = dev->transport->get_blocks(dev); @@ -751,12 +762,14 @@ target_emulate_readcapacity(struct se_cmd *cmd) transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } -static int -target_emulate_readcapacity_16(struct se_cmd *cmd) +int target_emulate_readcapacity_16(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned long long blocks = dev->transport->get_blocks(dev); @@ -784,6 +797,8 @@ target_emulate_readcapacity_16(struct se_cmd *cmd) transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -922,14 +937,15 @@ target_modesense_dpofua(unsigned char *buf, int type) } } -static int -target_emulate_modesense(struct se_cmd *cmd, int ten) +int target_emulate_modesense(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; char *cdb = cmd->t_task_cdb; unsigned char *rbuf; int type = dev->transport->get_device_type(dev); - int offset = (ten) ? 8 : 4; + int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10); + int offset = ten ? 8 : 4; int length = 0; unsigned char buf[SE_MODE_PAGE_BUF]; @@ -995,12 +1011,14 @@ target_emulate_modesense(struct se_cmd *cmd, int ten) memcpy(rbuf, buf, offset); transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } -static int -target_emulate_request_sense(struct se_cmd *cmd) +int target_emulate_request_sense(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; unsigned char *cdb = cmd->t_task_cdb; unsigned char *buf; u8 ua_asc = 0, ua_ascq = 0; @@ -1059,7 +1077,8 @@ target_emulate_request_sense(struct se_cmd *cmd) end: transport_kunmap_first_data_page(cmd); - + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -1067,8 +1086,7 @@ end: * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. * Note this is not used for TCM/pSCSI passthrough */ -static int -target_emulate_unmap(struct se_task *task) +int target_emulate_unmap(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; @@ -1079,6 +1097,12 @@ target_emulate_unmap(struct se_task *task) int ret = 0, offset; unsigned short dl, bd_dl; + if (!dev->transport->do_discard) { + pr_err("UNMAP emulation not supported for: %s\n", + dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + /* First UNMAP block descriptor starts at 8 byte offset */ offset = 8; size -= 8; @@ -1110,7 +1134,10 @@ target_emulate_unmap(struct se_task *task) err: transport_kunmap_first_data_page(cmd); - + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } return ret; } @@ -1118,14 +1145,28 @@ err: * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. * Note this is not used for TCM/pSCSI passthrough */ -static int -target_emulate_write_same(struct se_task *task, u32 num_blocks) +int target_emulate_write_same(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; sector_t range; sector_t lba = cmd->t_task_lba; + u32 num_blocks; int ret; + + if (!dev->transport->do_discard) { + pr_err("WRITE_SAME emulation not supported" + " for: %s\n", dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + + if (cmd->t_task_cdb[0] == WRITE_SAME) + num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]); + else if (cmd->t_task_cdb[0] == WRITE_SAME_16) + num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]); + else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */ + num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]); + /* * Use the explicit range when non zero is supplied, otherwise calculate * the remaining range based on ->get_blocks() - starting LBA. @@ -1144,127 +1185,30 @@ target_emulate_write_same(struct se_task *task, u32 num_blocks) return ret; } + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } -int -transport_emulate_control_cdb(struct se_task *task) +int target_emulate_synchronize_cache(struct se_task *task) { - struct se_cmd *cmd = task->task_se_cmd; - struct se_device *dev = cmd->se_dev; - unsigned short service_action; - int ret = 0; + struct se_device *dev = task->task_se_cmd->se_dev; - switch (cmd->t_task_cdb[0]) { - case INQUIRY: - ret = target_emulate_inquiry(cmd); - break; - case READ_CAPACITY: - ret = target_emulate_readcapacity(cmd); - break; - case MODE_SENSE: - ret = target_emulate_modesense(cmd, 0); - break; - case MODE_SENSE_10: - ret = target_emulate_modesense(cmd, 1); - break; - case SERVICE_ACTION_IN: - switch (cmd->t_task_cdb[1] & 0x1f) { - case SAI_READ_CAPACITY_16: - ret = target_emulate_readcapacity_16(cmd); - break; - default: - pr_err("Unsupported SA: 0x%02x\n", - cmd->t_task_cdb[1] & 0x1f); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - break; - case REQUEST_SENSE: - ret = target_emulate_request_sense(cmd); - break; - case UNMAP: - if (!dev->transport->do_discard) { - pr_err("UNMAP emulation not supported for: %s\n", - dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_unmap(task); - break; - case WRITE_SAME: - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME emulation not supported" - " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_write_same(task, - get_unaligned_be16(&cmd->t_task_cdb[7])); - break; - case WRITE_SAME_16: - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME_16 emulation not supported" - " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_write_same(task, - get_unaligned_be32(&cmd->t_task_cdb[10])); - break; - case VARIABLE_LENGTH_CMD: - service_action = - get_unaligned_be16(&cmd->t_task_cdb[8]); - switch (service_action) { - case WRITE_SAME_32: - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME_32 SA emulation not" - " supported for: %s\n", - dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_write_same(task, - get_unaligned_be32(&cmd->t_task_cdb[28])); - break; - default: - pr_err("Unsupported VARIABLE_LENGTH_CMD SA:" - " 0x%02x\n", service_action); - break; - } - break; - case SYNCHRONIZE_CACHE: - case 0x91: /* SYNCHRONIZE_CACHE_16: */ - if (!dev->transport->do_sync_cache) { - pr_err("SYNCHRONIZE_CACHE emulation not supported" - " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - dev->transport->do_sync_cache(task); - break; - case ALLOW_MEDIUM_REMOVAL: - case ERASE: - case REZERO_UNIT: - case SEEK_10: - case SPACE: - case START_STOP: - case TEST_UNIT_READY: - case VERIFY: - case WRITE_FILEMARKS: - break; - default: - pr_err("Unsupported SCSI Opcode: 0x%02x for %s\n", - cmd->t_task_cdb[0], dev->transport->name); + if (!dev->transport->do_sync_cache) { + pr_err("SYNCHRONIZE_CACHE emulation not supported" + " for: %s\n", dev->transport->name); return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; } - if (ret < 0) - return ret; - /* - * Handle the successful completion here unless a caller - * has explictly requested an asychronous completion. - */ - if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } + dev->transport->do_sync_cache(task); + return 0; +} - return PYX_TRANSPORT_SENT_TO_TRANSPORT; +int target_emulate_noop(struct se_task *task) +{ + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + return 0; } /* diff --git a/drivers/target/target_core_cdb.h b/drivers/target/target_core_cdb.h new file mode 100644 index 000000000000..ad6b1e393001 --- /dev/null +++ b/drivers/target/target_core_cdb.h @@ -0,0 +1,14 @@ +#ifndef TARGET_CORE_CDB_H +#define TARGET_CORE_CDB_H + +int target_emulate_inquiry(struct se_task *task); +int target_emulate_readcapacity(struct se_task *task); +int target_emulate_readcapacity_16(struct se_task *task); +int target_emulate_modesense(struct se_task *task); +int target_emulate_request_sense(struct se_task *task); +int target_emulate_unmap(struct se_task *task); +int target_emulate_write_same(struct se_task *task); +int target_emulate_synchronize_cache(struct se_task *task); +int target_emulate_noop(struct se_task *task); + +#endif /* TARGET_CORE_CDB_H */ diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index f870c3bcfd82..ba5edec2c5f8 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -35,6 +35,7 @@ #include <linux/spinlock.h> #include <linux/kthread.h> #include <linux/in.h> +#include <linux/export.h> #include <net/sock.h> #include <net/tcp.h> #include <scsi/scsi.h> @@ -651,23 +652,15 @@ void core_dev_unexport( lun->lun_se_dev = NULL; } -int transport_core_report_lun_response(struct se_cmd *se_cmd) +int target_report_luns(struct se_task *se_task) { + struct se_cmd *se_cmd = se_task->task_se_cmd; struct se_dev_entry *deve; struct se_lun *se_lun; struct se_session *se_sess = se_cmd->se_sess; - struct se_task *se_task; unsigned char *buf; u32 cdb_offset = 0, lun_count = 0, offset = 8, i; - list_for_each_entry(se_task, &se_cmd->t_task_list, t_list) - break; - - if (!se_task) { - pr_err("Unable to locate struct se_task for struct se_cmd\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; - } - buf = transport_kmap_first_data_page(se_cmd); /* @@ -713,6 +706,8 @@ done: buf[2] = ((lun_count >> 8) & 0xff); buf[3] = (lun_count & 0xff); + se_task->task_scsi_status = GOOD; + transport_complete_task(se_task, 1); return PYX_TRANSPORT_SENT_TO_TRANSPORT; } diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 39f021b855ef..ec4249be617e 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -29,6 +29,7 @@ #include <linux/string.h> #include <linux/ctype.h> #include <linux/spinlock.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 19a0be9c6570..67cd6fe05bfa 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -32,6 +32,7 @@ #include <linux/blkdev.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index 0639b975d6f5..c68019d6c406 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -32,6 +32,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/in.h> +#include <linux/module.h> #include <net/sock.h> #include <net/tcp.h> diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 41ad02b5fb87..7698efe29262 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -37,6 +37,7 @@ #include <linux/bio.h> #include <linux/genhd.h> #include <linux/file.h> +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 0c4f783f924c..5a4ebfc3a54f 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -116,114 +116,21 @@ static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type) return ret; } -static int core_scsi2_reservation_release(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - struct se_session *sess = cmd->se_sess; - struct se_portal_group *tpg = sess->se_tpg; - - if (!sess || !tpg) - return 0; - - spin_lock(&dev->dev_reservation_lock); - if (!dev->dev_reserved_node_acl || !sess) { - spin_unlock(&dev->dev_reservation_lock); - return 0; - } - - if (dev->dev_reserved_node_acl != sess->se_node_acl) { - spin_unlock(&dev->dev_reservation_lock); - return 0; - } - dev->dev_reserved_node_acl = NULL; - dev->dev_flags &= ~DF_SPC2_RESERVATIONS; - if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) { - dev->dev_res_bin_isid = 0; - dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID; - } - pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" - " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), - cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, - sess->se_node_acl->initiatorname); - spin_unlock(&dev->dev_reservation_lock); - - return 0; -} - -static int core_scsi2_reservation_reserve(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - struct se_session *sess = cmd->se_sess; - struct se_portal_group *tpg = sess->se_tpg; - - if ((cmd->t_task_cdb[1] & 0x01) && - (cmd->t_task_cdb[1] & 0x02)) { - pr_err("LongIO and Obselete Bits set, returning" - " ILLEGAL_REQUEST\n"); - return PYX_TRANSPORT_ILLEGAL_REQUEST; - } - /* - * This is currently the case for target_core_mod passthrough struct se_cmd - * ops - */ - if (!sess || !tpg) - return 0; - - spin_lock(&dev->dev_reservation_lock); - if (dev->dev_reserved_node_acl && - (dev->dev_reserved_node_acl != sess->se_node_acl)) { - pr_err("SCSI-2 RESERVATION CONFLIFT for %s fabric\n", - tpg->se_tpg_tfo->get_fabric_name()); - pr_err("Original reserver LUN: %u %s\n", - cmd->se_lun->unpacked_lun, - dev->dev_reserved_node_acl->initiatorname); - pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u" - " from %s \n", cmd->se_lun->unpacked_lun, - cmd->se_deve->mapped_lun, - sess->se_node_acl->initiatorname); - spin_unlock(&dev->dev_reservation_lock); - return PYX_TRANSPORT_RESERVATION_CONFLICT; - } - - dev->dev_reserved_node_acl = sess->se_node_acl; - dev->dev_flags |= DF_SPC2_RESERVATIONS; - if (sess->sess_bin_isid != 0) { - dev->dev_res_bin_isid = sess->sess_bin_isid; - dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID; - } - pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" - " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), - cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, - sess->se_node_acl->initiatorname); - spin_unlock(&dev->dev_reservation_lock); - - return 0; -} - static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, struct se_node_acl *, struct se_session *); static void core_scsi3_put_pr_reg(struct t10_pr_registration *); -/* - * Setup in target_core_transport.c:transport_generic_cmd_sequencer() - * and called via struct se_cmd->transport_emulate_cdb() in TCM processing - * thread context. - */ -int core_scsi2_emulate_crh(struct se_cmd *cmd) +static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret) { struct se_session *se_sess = cmd->se_sess; struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; struct t10_pr_registration *pr_reg; struct t10_reservation *pr_tmpl = &su_dev->t10_pr; - unsigned char *cdb = &cmd->t_task_cdb[0]; int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS); int conflict = 0; - if (!se_sess) - return 0; - if (!crh) - goto after_crh; + return false; pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, se_sess); @@ -251,14 +158,16 @@ int core_scsi2_emulate_crh(struct se_cmd *cmd) */ if (pr_reg->pr_res_holder) { core_scsi3_put_pr_reg(pr_reg); - return 0; + *ret = 0; + return false; } if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) || (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { core_scsi3_put_pr_reg(pr_reg); - return 0; + *ret = 0; + return true; } core_scsi3_put_pr_reg(pr_reg); conflict = 1; @@ -282,18 +191,118 @@ int core_scsi2_emulate_crh(struct se_cmd *cmd) pr_err("Received legacy SPC-2 RESERVE/RELEASE" " while active SPC-3 registrations exist," " returning RESERVATION_CONFLICT\n"); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + *ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + return true; } -after_crh: - if ((cdb[0] == RESERVE) || (cdb[0] == RESERVE_10)) - return core_scsi2_reservation_reserve(cmd); - else if ((cdb[0] == RELEASE) || (cdb[0] == RELEASE_10)) - return core_scsi2_reservation_release(cmd); - else - return PYX_TRANSPORT_INVALID_CDB_FIELD; + return false; +} + +int target_scsi2_reservation_release(struct se_task *task) +{ + struct se_cmd *cmd = task->task_se_cmd; + struct se_device *dev = cmd->se_dev; + struct se_session *sess = cmd->se_sess; + struct se_portal_group *tpg = sess->se_tpg; + int ret = 0; + + if (!sess || !tpg) + goto out; + if (target_check_scsi2_reservation_conflict(cmd, &ret)) + goto out; + + ret = 0; + spin_lock(&dev->dev_reservation_lock); + if (!dev->dev_reserved_node_acl || !sess) + goto out_unlock; + + if (dev->dev_reserved_node_acl != sess->se_node_acl) + goto out_unlock; + + dev->dev_reserved_node_acl = NULL; + dev->dev_flags &= ~DF_SPC2_RESERVATIONS; + if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) { + dev->dev_res_bin_isid = 0; + dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID; + } + pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" + " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), + cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, + sess->se_node_acl->initiatorname); + +out_unlock: + spin_unlock(&dev->dev_reservation_lock); +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; +} + +int target_scsi2_reservation_reserve(struct se_task *task) +{ + struct se_cmd *cmd = task->task_se_cmd; + struct se_device *dev = cmd->se_dev; + struct se_session *sess = cmd->se_sess; + struct se_portal_group *tpg = sess->se_tpg; + int ret = 0; + + if ((cmd->t_task_cdb[1] & 0x01) && + (cmd->t_task_cdb[1] & 0x02)) { + pr_err("LongIO and Obselete Bits set, returning" + " ILLEGAL_REQUEST\n"); + ret = PYX_TRANSPORT_ILLEGAL_REQUEST; + goto out; + } + /* + * This is currently the case for target_core_mod passthrough struct se_cmd + * ops + */ + if (!sess || !tpg) + goto out; + if (target_check_scsi2_reservation_conflict(cmd, &ret)) + goto out; + + ret = 0; + spin_lock(&dev->dev_reservation_lock); + if (dev->dev_reserved_node_acl && + (dev->dev_reserved_node_acl != sess->se_node_acl)) { + pr_err("SCSI-2 RESERVATION CONFLIFT for %s fabric\n", + tpg->se_tpg_tfo->get_fabric_name()); + pr_err("Original reserver LUN: %u %s\n", + cmd->se_lun->unpacked_lun, + dev->dev_reserved_node_acl->initiatorname); + pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u" + " from %s \n", cmd->se_lun->unpacked_lun, + cmd->se_deve->mapped_lun, + sess->se_node_acl->initiatorname); + ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + goto out_unlock; + } + + dev->dev_reserved_node_acl = sess->se_node_acl; + dev->dev_flags |= DF_SPC2_RESERVATIONS; + if (sess->sess_bin_isid != 0) { + dev->dev_res_bin_isid = sess->sess_bin_isid; + dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID; + } + pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" + " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), + cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, + sess->se_node_acl->initiatorname); + +out_unlock: + spin_unlock(&dev->dev_reservation_lock); +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } + /* * Begin SPC-3/SPC-4 Persistent Reservations emulation support * @@ -418,12 +427,12 @@ static int core_scsi3_pr_seq_non_holder( break; case RELEASE: case RELEASE_10: - /* Handled by CRH=1 in core_scsi2_emulate_crh() */ + /* Handled by CRH=1 in target_scsi2_reservation_release() */ ret = 0; break; case RESERVE: case RESERVE_10: - /* Handled by CRH=1 in core_scsi2_emulate_crh() */ + /* Handled by CRH=1 in target_scsi2_reservation_reserve() */ ret = 0; break; case TEST_UNIT_READY: @@ -3739,12 +3748,33 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb) /* * See spc4r17 section 6.14 Table 170 */ -static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) +int target_scsi3_emulate_pr_out(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; + unsigned char *cdb = &cmd->t_task_cdb[0]; unsigned char *buf; u64 res_key, sa_res_key; int sa, scope, type, aptpl; int spec_i_pt = 0, all_tg_pt = 0, unreg = 0; + int ret; + + /* + * Following spc2r20 5.5.1 Reservations overview: + * + * If a logical unit has been reserved by any RESERVE command and is + * still reserved by any initiator, all PERSISTENT RESERVE IN and all + * PERSISTENT RESERVE OUT commands shall conflict regardless of + * initiator or service action and shall terminate with a RESERVATION + * CONFLICT status. + */ + if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { + pr_err("Received PERSISTENT_RESERVE CDB while legacy" + " SPC-2 reservation is held, returning" + " RESERVATION_CONFLICT\n"); + ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + goto out; + } + /* * FIXME: A NULL struct se_session pointer means an this is not coming from * a $FABRIC_MOD's nexus, but from internal passthrough ops. @@ -3755,7 +3785,8 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) if (cmd->data_length < 24) { pr_warn("SPC-PR: Received PR OUT parameter list" " length too small: %u\n", cmd->data_length); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; } /* * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB) @@ -3788,8 +3819,11 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) /* * SPEC_I_PT=1 is only valid for Service action: REGISTER */ - if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) { + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + /* * From spc4r17 section 6.14: * @@ -3803,7 +3837,8 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) (cmd->data_length != 24)) { pr_warn("SPC-PR: Received PR OUT illegal parameter" " list length: %u\n", cmd->data_length); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; } /* * (core_scsi3_emulate_pro_* function parameters @@ -3812,35 +3847,47 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) */ switch (sa) { case PRO_REGISTER: - return core_scsi3_emulate_pro_register(cmd, + ret = core_scsi3_emulate_pro_register(cmd, res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0); + break; case PRO_RESERVE: - return core_scsi3_emulate_pro_reserve(cmd, - type, scope, res_key); + ret = core_scsi3_emulate_pro_reserve(cmd, type, scope, res_key); + break; case PRO_RELEASE: - return core_scsi3_emulate_pro_release(cmd, - type, scope, res_key); + ret = core_scsi3_emulate_pro_release(cmd, type, scope, res_key); + break; case PRO_CLEAR: - return core_scsi3_emulate_pro_clear(cmd, res_key); + ret = core_scsi3_emulate_pro_clear(cmd, res_key); + break; case PRO_PREEMPT: - return core_scsi3_emulate_pro_preempt(cmd, type, scope, + ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, res_key, sa_res_key, 0); + break; case PRO_PREEMPT_AND_ABORT: - return core_scsi3_emulate_pro_preempt(cmd, type, scope, + ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, res_key, sa_res_key, 1); + break; case PRO_REGISTER_AND_IGNORE_EXISTING_KEY: - return core_scsi3_emulate_pro_register(cmd, + ret = core_scsi3_emulate_pro_register(cmd, 0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1); + break; case PRO_REGISTER_AND_MOVE: - return core_scsi3_emulate_pro_register_and_move(cmd, res_key, + ret = core_scsi3_emulate_pro_register_and_move(cmd, res_key, sa_res_key, aptpl, unreg); + break; default: pr_err("Unknown PERSISTENT_RESERVE_OUT service" " action: 0x%02x\n", cdb[1] & 0x1f); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + ret = PYX_TRANSPORT_INVALID_CDB_FIELD; + break; } - return PYX_TRANSPORT_INVALID_CDB_FIELD; +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } /* @@ -4190,29 +4237,11 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) return 0; } -static int core_scsi3_emulate_pr_in(struct se_cmd *cmd, unsigned char *cdb) +int target_scsi3_emulate_pr_in(struct se_task *task) { - switch (cdb[1] & 0x1f) { - case PRI_READ_KEYS: - return core_scsi3_pri_read_keys(cmd); - case PRI_READ_RESERVATION: - return core_scsi3_pri_read_reservation(cmd); - case PRI_REPORT_CAPABILITIES: - return core_scsi3_pri_report_capabilities(cmd); - case PRI_READ_FULL_STATUS: - return core_scsi3_pri_read_full_status(cmd); - default: - pr_err("Unknown PERSISTENT_RESERVE_IN service" - " action: 0x%02x\n", cdb[1] & 0x1f); - return PYX_TRANSPORT_INVALID_CDB_FIELD; - } - -} + struct se_cmd *cmd = task->task_se_cmd; + int ret; -int core_scsi3_emulate_pr(struct se_cmd *cmd) -{ - unsigned char *cdb = &cmd->t_task_cdb[0]; - struct se_device *dev = cmd->se_dev; /* * Following spc2r20 5.5.1 Reservations overview: * @@ -4222,16 +4251,38 @@ int core_scsi3_emulate_pr(struct se_cmd *cmd) * initiator or service action and shall terminate with a RESERVATION * CONFLICT status. */ - if (dev->dev_flags & DF_SPC2_RESERVATIONS) { + if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { pr_err("Received PERSISTENT_RESERVE CDB while legacy" " SPC-2 reservation is held, returning" " RESERVATION_CONFLICT\n"); return PYX_TRANSPORT_RESERVATION_CONFLICT; } - return (cdb[0] == PERSISTENT_RESERVE_OUT) ? - core_scsi3_emulate_pr_out(cmd, cdb) : - core_scsi3_emulate_pr_in(cmd, cdb); + switch (cmd->t_task_cdb[1] & 0x1f) { + case PRI_READ_KEYS: + ret = core_scsi3_pri_read_keys(cmd); + break; + case PRI_READ_RESERVATION: + ret = core_scsi3_pri_read_reservation(cmd); + break; + case PRI_REPORT_CAPABILITIES: + ret = core_scsi3_pri_report_capabilities(cmd); + break; + case PRI_READ_FULL_STATUS: + ret = core_scsi3_pri_read_full_status(cmd); + break; + default: + pr_err("Unknown PERSISTENT_RESERVE_IN service" + " action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); + ret = PYX_TRANSPORT_INVALID_CDB_FIELD; + break; + } + + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type) diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index c8f47d064584..b97f6940dd05 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -47,7 +47,8 @@ extern struct kmem_cache *t10_pr_reg_cache; extern int core_pr_dump_initiator_port(struct t10_pr_registration *, char *, u32); -extern int core_scsi2_emulate_crh(struct se_cmd *); +extern int target_scsi2_reservation_release(struct se_task *task); +extern int target_scsi2_reservation_reserve(struct se_task *task); extern int core_scsi3_alloc_aptpl_registration( struct t10_reservation *, u64, unsigned char *, unsigned char *, u32, @@ -61,7 +62,9 @@ extern void core_scsi3_free_all_registrations(struct se_device *); extern unsigned char *core_scsi3_pr_dump_type(int); extern int core_scsi3_check_cdb_abort_and_preempt(struct list_head *, struct se_cmd *); -extern int core_scsi3_emulate_pr(struct se_cmd *); + +extern int target_scsi3_emulate_pr_in(struct se_task *task); +extern int target_scsi3_emulate_pr_out(struct se_task *task); extern int core_setup_reservations(struct se_device *, int); #endif /* TARGET_CORE_PR_H */ diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index dad671dee9e9..ed32e1efe429 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -36,6 +36,7 @@ #include <linux/genhd.h> #include <linux/cdrom.h> #include <linux/file.h> +#include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> #include <scsi/scsi_cmnd.h> @@ -1091,7 +1092,7 @@ static int pscsi_do_task(struct se_task *task) req = blk_make_request(pdv->pdv_sd->request_queue, hbio, GFP_KERNEL); - if (!req) { + if (IS_ERR(req)) { pr_err("pSCSI: blk_make_request() failed\n"); goto fail; } diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 570b144a1edb..217e29df6297 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/list.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -118,7 +119,7 @@ static void core_tmr_drain_tmr_list( /* * Allow the received TMR to return with FUNCTION_COMPLETE. */ - if (tmr && (tmr_p == tmr)) + if (tmr_p == tmr) continue; cmd = tmr_p->task_cmd; @@ -147,19 +148,18 @@ static void core_tmr_drain_tmr_list( } spin_unlock(&cmd->t_state_lock); - list_move_tail(&tmr->tmr_list, &drain_tmr_list); + list_move_tail(&tmr_p->tmr_list, &drain_tmr_list); } spin_unlock_irqrestore(&dev->se_tmr_lock, flags); - while (!list_empty(&drain_tmr_list)) { - tmr = list_entry(drain_tmr_list.next, struct se_tmr_req, tmr_list); - list_del(&tmr->tmr_list); + list_for_each_entry_safe(tmr_p, tmr_pp, &drain_tmr_list, tmr_list) { + list_del_init(&tmr_p->tmr_list); cmd = tmr_p->task_cmd; pr_debug("LUN_RESET: %s releasing TMR %p Function: 0x%02x," " Response: 0x%02x, t_state: %d\n", - (preempt_and_abort_list) ? "Preempt" : "", tmr, - tmr->function, tmr->response, cmd->t_state); + (preempt_and_abort_list) ? "Preempt" : "", tmr_p, + tmr_p->function, tmr_p->response, cmd->t_state); transport_cmd_finish_abort(cmd, 1); } @@ -330,16 +330,6 @@ static void core_tmr_drain_cmd_list( */ if (prout_cmd == cmd) continue; - /* - * Skip direct processing of TRANSPORT_FREE_CMD_INTR for - * HW target mode fabrics. - */ - spin_lock(&cmd->t_state_lock); - if (cmd->t_state == TRANSPORT_FREE_CMD_INTR) { - spin_unlock(&cmd->t_state_lock); - continue; - } - spin_unlock(&cmd->t_state_lock); atomic_set(&cmd->t_transport_queue_active, 0); atomic_dec(&qobj->queue_cnt); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 49fd0a9b0a56..8ddd133025b9 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -32,6 +32,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/in.h> +#include <linux/export.h> #include <net/sock.h> #include <net/tcp.h> #include <scsi/scsi.h> diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index d75255804481..3400ae6e93f8 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -36,6 +36,7 @@ #include <linux/kthread.h> #include <linux/in.h> #include <linux/cdrom.h> +#include <linux/module.h> #include <asm/unaligned.h> #include <net/sock.h> #include <net/tcp.h> @@ -52,6 +53,7 @@ #include <target/target_core_configfs.h> #include "target_core_alua.h" +#include "target_core_cdb.h" #include "target_core_hba.h" #include "target_core_pr.h" #include "target_core_ua.h" @@ -268,6 +270,9 @@ struct se_session *transport_init_session(void) } INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); + INIT_LIST_HEAD(&se_sess->sess_cmd_list); + INIT_LIST_HEAD(&se_sess->sess_wait_list); + spin_lock_init(&se_sess->sess_cmd_lock); return se_sess; } @@ -514,13 +519,16 @@ static int transport_cmd_check_stop( * Some fabric modules like tcm_loop can release * their internally allocated I/O reference now and * struct se_cmd now. + * + * Fabric modules are expected to return '1' here if the + * se_cmd being passed is released at this point, + * or zero if not being released. */ if (cmd->se_tfo->check_stop_free != NULL) { spin_unlock_irqrestore( &cmd->t_state_lock, flags); - cmd->se_tfo->check_stop_free(cmd); - return 1; + return cmd->se_tfo->check_stop_free(cmd); } } spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -730,6 +738,10 @@ void transport_complete_task(struct se_task *task, int success) complete(&task->task_stop_comp); return; } + + if (!success) + cmd->t_tasks_failed = 1; + /* * Decrement the outstanding t_task_cdbs_left count. The last * struct se_task from struct se_cmd will complete itself into the @@ -740,7 +752,7 @@ void transport_complete_task(struct se_task *task, int success) return; } - if (!success || cmd->t_tasks_failed) { + if (cmd->t_tasks_failed) { if (!task->task_error_status) { task->task_error_status = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; @@ -908,7 +920,7 @@ void transport_remove_task_from_execute_queue( } /* - * Handle QUEUE_FULL / -EAGAIN status + * Handle QUEUE_FULL / -EAGAIN and -ENOMEM status */ static void target_qf_do_work(struct work_struct *work) @@ -1498,11 +1510,12 @@ void transport_init_se_cmd( INIT_LIST_HEAD(&cmd->se_ordered_node); INIT_LIST_HEAD(&cmd->se_qf_node); INIT_LIST_HEAD(&cmd->se_queue_node); - + INIT_LIST_HEAD(&cmd->se_cmd_list); INIT_LIST_HEAD(&cmd->t_task_list); init_completion(&cmd->transport_lun_fe_stop_comp); init_completion(&cmd->transport_lun_stop_comp); init_completion(&cmd->t_transport_stop_comp); + init_completion(&cmd->cmd_wait_comp); spin_lock_init(&cmd->t_state_lock); atomic_set(&cmd->transport_dev_active, 1); @@ -1645,9 +1658,7 @@ int transport_handle_cdb_direct( * and call transport_generic_request_failure() if necessary.. */ ret = transport_generic_new_cmd(cmd); - if (ret == -EAGAIN) - return 0; - else if (ret < 0) { + if (ret < 0) { cmd->transport_error_status = ret; transport_generic_request_failure(cmd, 0, (cmd->data_direction != DMA_TO_DEVICE)); @@ -1717,13 +1728,6 @@ int transport_generic_handle_tmr( } EXPORT_SYMBOL(transport_generic_handle_tmr); -void transport_generic_free_cmd_intr( - struct se_cmd *cmd) -{ - transport_add_cmd_to_queue(cmd, TRANSPORT_FREE_CMD_INTR, false); -} -EXPORT_SYMBOL(transport_generic_free_cmd_intr); - /* * If the task is active, request it to be stopped and sleep until it * has completed. @@ -1886,7 +1890,7 @@ static void transport_generic_request_failure( ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS); ret = cmd->se_tfo->queue_status(cmd); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; goto check_stop; case PYX_TRANSPORT_USE_SENSE_REASON: @@ -1913,7 +1917,7 @@ static void transport_generic_request_failure( else { ret = transport_send_check_condition_and_sense(cmd, cmd->scsi_sense_reason, 0); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; } @@ -2153,62 +2157,20 @@ check_depth: atomic_set(&cmd->t_transport_sent, 1); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - /* - * The struct se_cmd->transport_emulate_cdb() function pointer is used - * to grab REPORT_LUNS and other CDBs we want to handle before they hit the - * struct se_subsystem_api->do_task() caller below. - */ - if (cmd->transport_emulate_cdb) { - error = cmd->transport_emulate_cdb(cmd); - if (error != 0) { - cmd->transport_error_status = error; - spin_lock_irqsave(&cmd->t_state_lock, flags); - task->task_flags &= ~TF_ACTIVE; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - atomic_set(&cmd->t_transport_sent, 0); - transport_stop_tasks_for_cmd(cmd); - atomic_inc(&dev->depth_left); - transport_generic_request_failure(cmd, 0, 1); - goto check_depth; - } - /* - * Handle the successful completion for transport_emulate_cdb() - * for synchronous operation, following SCF_EMULATE_CDB_ASYNC - * Otherwise the caller is expected to complete the task with - * proper status. - */ - if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) { - cmd->scsi_status = SAM_STAT_GOOD; - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } - } else { - /* - * Currently for all virtual TCM plugins including IBLOCK, FILEIO and - * RAMDISK we use the internal transport_emulate_control_cdb() logic - * with struct se_subsystem_api callers for the primary SPC-3 TYPE_DISK - * LUN emulation code. - * - * For TCM/pSCSI and all other SCF_SCSI_DATA_SG_IO_CDB I/O tasks we - * call ->do_task() directly and let the underlying TCM subsystem plugin - * code handle the CDB emulation. - */ - if ((dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) && - (!(task->task_se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) - error = transport_emulate_control_cdb(task); - else - error = dev->transport->do_task(task); - if (error != 0) { - cmd->transport_error_status = error; - spin_lock_irqsave(&cmd->t_state_lock, flags); - task->task_flags &= ~TF_ACTIVE; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - atomic_set(&cmd->t_transport_sent, 0); - transport_stop_tasks_for_cmd(cmd); - atomic_inc(&dev->depth_left); - transport_generic_request_failure(cmd, 0, 1); - } + if (cmd->execute_task) + error = cmd->execute_task(task); + else + error = dev->transport->do_task(task); + if (error != 0) { + cmd->transport_error_status = error; + spin_lock_irqsave(&cmd->t_state_lock, flags); + task->task_flags &= ~TF_ACTIVE; + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + atomic_set(&cmd->t_transport_sent, 0); + transport_stop_tasks_for_cmd(cmd); + atomic_inc(&dev->depth_left); + transport_generic_request_failure(cmd, 0, 1); } goto check_depth; @@ -2642,6 +2604,13 @@ static int transport_generic_cmd_sequencer( */ } + /* + * If we operate in passthrough mode we skip most CDB emulation and + * instead hand the commands down to the physical SCSI device. + */ + passthrough = + (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV); + switch (cdb[0]) { case READ_6: sectors = transport_get_sectors_6(cdb, cmd, §or_ret); @@ -2721,9 +2690,12 @@ static int transport_generic_cmd_sequencer( cmd->t_task_lba = transport_lba_32(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - if (dev->transport->transport_type == - TRANSPORT_PLUGIN_PHBA_PDEV) + /* + * Do now allow BIDI commands for passthrough mode. + */ + if (passthrough) goto out_unsupported_cdb; + /* * Setup BIDI XOR callback to be run after I/O completion. */ @@ -2732,13 +2704,6 @@ static int transport_generic_cmd_sequencer( break; case VARIABLE_LENGTH_CMD: service_action = get_unaligned_be16(&cdb[8]); - /* - * Determine if this is TCM/PSCSI device and we should disable - * internal emulation for this CDB. - */ - passthrough = (dev->transport->transport_type == - TRANSPORT_PLUGIN_PHBA_PDEV); - switch (service_action) { case XDWRITEREAD_32: sectors = transport_get_sectors_32(cdb, cmd, §or_ret); @@ -2752,8 +2717,12 @@ static int transport_generic_cmd_sequencer( cmd->t_task_lba = transport_lba_64_ext(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + /* + * Do now allow BIDI commands for passthrough mode. + */ if (passthrough) goto out_unsupported_cdb; + /* * Setup BIDI XOR callback to be run during after I/O * completion. @@ -2779,7 +2748,8 @@ static int transport_generic_cmd_sequencer( if (target_check_write_same_discard(&cdb[10], dev) < 0) goto out_invalid_cdb_field; - + if (!passthrough) + cmd->execute_task = target_emulate_write_same; break; default: pr_err("VARIABLE_LENGTH_CMD service action" @@ -2793,12 +2763,10 @@ static int transport_generic_cmd_sequencer( /* * Check for emulated MI_REPORT_TARGET_PGS. */ - if (cdb[1] == MI_REPORT_TARGET_PGS) { - cmd->transport_emulate_cdb = - (su_dev->t10_alua.alua_type == - SPC3_ALUA_EMULATED) ? - core_emulate_report_target_port_groups : - NULL; + if (cdb[1] == MI_REPORT_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_task = + target_emulate_report_target_port_groups; } size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; @@ -2819,8 +2787,15 @@ static int transport_generic_cmd_sequencer( case MODE_SENSE: size = cdb[4]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_modesense; break; case MODE_SENSE_10: + size = (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_modesense; + break; case GPCMD_READ_BUFFER_CAPACITY: case GPCMD_SEND_OPC: case LOG_SELECT: @@ -2840,11 +2815,14 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case PERSISTENT_RESERVE_IN: + if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) + cmd->execute_task = target_scsi3_emulate_pr_in; + size = (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + break; case PERSISTENT_RESERVE_OUT: - cmd->transport_emulate_cdb = - (su_dev->t10_pr.res_type == - SPC3_PERSISTENT_RESERVATIONS) ? - core_scsi3_emulate_pr : NULL; + if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) + cmd->execute_task = target_scsi3_emulate_pr_out; size = (cdb[7] << 8) + cdb[8]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; @@ -2863,12 +2841,10 @@ static int transport_generic_cmd_sequencer( * * Check for emulated MO_SET_TARGET_PGS. */ - if (cdb[1] == MO_SET_TARGET_PGS) { - cmd->transport_emulate_cdb = - (su_dev->t10_alua.alua_type == - SPC3_ALUA_EMULATED) ? - core_emulate_set_target_port_groups : - NULL; + if (cdb[1] == MO_SET_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_task = + target_emulate_set_target_port_groups; } size = (cdb[6] << 24) | (cdb[7] << 16) | @@ -2888,6 +2864,8 @@ static int transport_generic_cmd_sequencer( if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) cmd->sam_task_attr = MSG_HEAD_TAG; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_inquiry; break; case READ_BUFFER: size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; @@ -2896,6 +2874,8 @@ static int transport_generic_cmd_sequencer( case READ_CAPACITY: size = READ_CAP_LEN; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_readcapacity; break; case READ_MEDIA_SERIAL_NUMBER: case SECURITY_PROTOCOL_IN: @@ -2904,6 +2884,21 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case SERVICE_ACTION_IN: + switch (cmd->t_task_cdb[1] & 0x1f) { + case SAI_READ_CAPACITY_16: + if (!passthrough) + cmd->execute_task = + target_emulate_readcapacity_16; + break; + default: + if (passthrough) + break; + + pr_err("Unsupported SA: 0x%02x\n", + cmd->t_task_cdb[1] & 0x1f); + goto out_unsupported_cdb; + } + /*FALLTHROUGH*/ case ACCESS_CONTROL_IN: case ACCESS_CONTROL_OUT: case EXTENDED_COPY: @@ -2934,6 +2929,8 @@ static int transport_generic_cmd_sequencer( case REQUEST_SENSE: size = cdb[4]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_request_sense; break; case READ_ELEMENT_STATUS: size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; @@ -2961,10 +2958,8 @@ static int transport_generic_cmd_sequencer( * is running in SPC_PASSTHROUGH, and wants reservations * emulation disabled. */ - cmd->transport_emulate_cdb = - (su_dev->t10_pr.res_type != - SPC_PASSTHROUGH) ? - core_scsi2_emulate_crh : NULL; + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) + cmd->execute_task = target_scsi2_reservation_reserve; cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case RELEASE: @@ -2978,10 +2973,8 @@ static int transport_generic_cmd_sequencer( else size = cmd->data_length; - cmd->transport_emulate_cdb = - (su_dev->t10_pr.res_type != - SPC_PASSTHROUGH) ? - core_scsi2_emulate_crh : NULL; + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) + cmd->execute_task = target_scsi2_reservation_release; cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case SYNCHRONIZE_CACHE: @@ -3002,16 +2995,9 @@ static int transport_generic_cmd_sequencer( size = transport_get_size(sectors, cdb, cmd); cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; - /* - * For TCM/pSCSI passthrough, skip cmd->transport_emulate_cdb() - */ - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (passthrough) break; - /* - * Set SCF_EMULATE_CDB_ASYNC to ensure asynchronous operation - * for SYNCHRONIZE_CACHE* Immed=1 case in __transport_execute_tasks() - */ - cmd->se_cmd_flags |= SCF_EMULATE_CDB_ASYNC; + /* * Check to ensure that LBA + Range does not exceed past end of * device for IBLOCK and FILEIO ->do_sync_cache() backend calls @@ -3020,10 +3006,13 @@ static int transport_generic_cmd_sequencer( if (transport_cmd_get_valid_sectors(cmd) < 0) goto out_invalid_cdb_field; } + cmd->execute_task = target_emulate_synchronize_cache; break; case UNMAP: size = get_unaligned_be16(&cdb[7]); cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_unmap; break; case WRITE_SAME_16: sectors = transport_get_sectors_16(cdb, cmd, §or_ret); @@ -3042,6 +3031,8 @@ static int transport_generic_cmd_sequencer( if (target_check_write_same_discard(&cdb[1], dev) < 0) goto out_invalid_cdb_field; + if (!passthrough) + cmd->execute_task = target_emulate_write_same; break; case WRITE_SAME: sectors = transport_get_sectors_10(cdb, cmd, §or_ret); @@ -3063,26 +3054,31 @@ static int transport_generic_cmd_sequencer( */ if (target_check_write_same_discard(&cdb[1], dev) < 0) goto out_invalid_cdb_field; + if (!passthrough) + cmd->execute_task = target_emulate_write_same; break; case ALLOW_MEDIUM_REMOVAL: - case GPCMD_CLOSE_TRACK: case ERASE: - case INITIALIZE_ELEMENT_STATUS: - case GPCMD_LOAD_UNLOAD: case REZERO_UNIT: case SEEK_10: - case GPCMD_SET_SPEED: case SPACE: case START_STOP: case TEST_UNIT_READY: case VERIFY: case WRITE_FILEMARKS: + cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_noop; + break; + case GPCMD_CLOSE_TRACK: + case INITIALIZE_ELEMENT_STATUS: + case GPCMD_LOAD_UNLOAD: + case GPCMD_SET_SPEED: case MOVE_MEDIUM: cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case REPORT_LUNS: - cmd->transport_emulate_cdb = - transport_core_report_lun_response; + cmd->execute_task = target_report_luns; size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; /* * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS @@ -3134,6 +3130,11 @@ static int transport_generic_cmd_sequencer( cmd->data_length = size; } + /* reject any command that we don't have a handler for */ + if (!(passthrough || cmd->execute_task || + (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) + goto out_unsupported_cdb; + /* Let's limit control cdbs to a page, for simplicity's sake. */ if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && size > PAGE_SIZE) @@ -3308,7 +3309,7 @@ static void target_complete_ok_work(struct work_struct *work) if (cmd->scsi_status) { ret = transport_send_check_condition_and_sense( cmd, reason, 1); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; transport_lun_remove_cmd(cmd); @@ -3333,7 +3334,7 @@ static void target_complete_ok_work(struct work_struct *work) spin_unlock(&cmd->se_lun->lun_sep_lock); ret = cmd->se_tfo->queue_data_in(cmd); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; break; case DMA_TO_DEVICE: @@ -3354,14 +3355,14 @@ static void target_complete_ok_work(struct work_struct *work) } spin_unlock(&cmd->se_lun->lun_sep_lock); ret = cmd->se_tfo->queue_data_in(cmd); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; break; } /* Fall through for DMA_TO_DEVICE */ case DMA_NONE: ret = cmd->se_tfo->queue_status(cmd); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; break; default: @@ -3890,7 +3891,10 @@ EXPORT_SYMBOL(transport_generic_process_write); static void transport_write_pending_qf(struct se_cmd *cmd) { - if (cmd->se_tfo->write_pending(cmd) == -EAGAIN) { + int ret; + + ret = cmd->se_tfo->write_pending(cmd); + if (ret == -EAGAIN || ret == -ENOMEM) { pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); transport_handle_queue_full(cmd, cmd->se_dev); @@ -3920,7 +3924,7 @@ static int transport_generic_write_pending(struct se_cmd *cmd) * frontend know that WRITE buffers are ready. */ ret = cmd->se_tfo->write_pending(cmd); - if (ret == -EAGAIN) + if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; else if (ret < 0) return ret; @@ -3931,7 +3935,7 @@ queue_full: pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); cmd->t_state = TRANSPORT_COMPLETE_QF_WP; transport_handle_queue_full(cmd, cmd->se_dev); - return ret; + return 0; } /** @@ -3949,6 +3953,14 @@ void transport_release_cmd(struct se_cmd *cmd) core_tmr_release_req(cmd->se_tmr_req); if (cmd->t_task_cdb != cmd->__t_task_cdb) kfree(cmd->t_task_cdb); + /* + * Check if target_wait_for_sess_cmds() is expecting to + * release se_cmd directly here.. + */ + if (cmd->check_release != 0 && cmd->se_tfo->check_release_cmd) + if (cmd->se_tfo->check_release_cmd(cmd) != 0) + return; + cmd->se_tfo->release_cmd(cmd); } EXPORT_SYMBOL(transport_release_cmd); @@ -3976,6 +3988,114 @@ void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) } EXPORT_SYMBOL(transport_generic_free_cmd); +/* target_get_sess_cmd - Add command to active ->sess_cmd_list + * @se_sess: session to reference + * @se_cmd: command descriptor to add + */ +void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +{ + unsigned long flags; + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); + se_cmd->check_release = 1; + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); +} +EXPORT_SYMBOL(target_get_sess_cmd); + +/* target_put_sess_cmd - Check for active I/O shutdown or list delete + * @se_sess: session to reference + * @se_cmd: command descriptor to drop + */ +int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +{ + unsigned long flags; + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + if (list_empty(&se_cmd->se_cmd_list)) { + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + WARN_ON(1); + return 0; + } + + if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + complete(&se_cmd->cmd_wait_comp); + return 1; + } + list_del(&se_cmd->se_cmd_list); + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + + return 0; +} +EXPORT_SYMBOL(target_put_sess_cmd); + +/* target_splice_sess_cmd_list - Split active cmds into sess_wait_list + * @se_sess: session to split + */ +void target_splice_sess_cmd_list(struct se_session *se_sess) +{ + struct se_cmd *se_cmd; + unsigned long flags; + + WARN_ON(!list_empty(&se_sess->sess_wait_list)); + INIT_LIST_HEAD(&se_sess->sess_wait_list); + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + se_sess->sess_tearing_down = 1; + + list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); + + list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) + se_cmd->cmd_wait_set = 1; + + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); +} +EXPORT_SYMBOL(target_splice_sess_cmd_list); + +/* target_wait_for_sess_cmds - Wait for outstanding descriptors + * @se_sess: session to wait for active I/O + * @wait_for_tasks: Make extra transport_wait_for_tasks call + */ +void target_wait_for_sess_cmds( + struct se_session *se_sess, + int wait_for_tasks) +{ + struct se_cmd *se_cmd, *tmp_cmd; + bool rc = false; + + list_for_each_entry_safe(se_cmd, tmp_cmd, + &se_sess->sess_wait_list, se_cmd_list) { + list_del(&se_cmd->se_cmd_list); + + pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" + " %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + + if (wait_for_tasks) { + pr_debug("Calling transport_wait_for_tasks se_cmd: %p t_state: %d," + " fabric state: %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + + rc = transport_wait_for_tasks(se_cmd); + + pr_debug("After transport_wait_for_tasks se_cmd: %p t_state: %d," + " fabric state: %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + } + + if (!rc) { + wait_for_completion(&se_cmd->cmd_wait_comp); + pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d" + " fabric state: %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + } + + se_cmd->se_tfo->release_cmd(se_cmd); + } +} +EXPORT_SYMBOL(target_wait_for_sess_cmds); + /* transport_lun_wait_for_tasks(): * * Called from ConfigFS context to stop the passed struct se_cmd to allow @@ -4152,14 +4272,14 @@ int transport_clear_lun_from_sessions(struct se_lun *lun) * Called from frontend fabric context to wait for storage engine * to pause and/or release frontend generated struct se_cmd. */ -void transport_wait_for_tasks(struct se_cmd *cmd) +bool transport_wait_for_tasks(struct se_cmd *cmd) { unsigned long flags; spin_lock_irqsave(&cmd->t_state_lock, flags); if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; + return false; } /* * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE @@ -4167,7 +4287,7 @@ void transport_wait_for_tasks(struct se_cmd *cmd) */ if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !cmd->se_tmr_req) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; + return false; } /* * If we are already stopped due to an external event (ie: LUN shutdown) @@ -4210,7 +4330,7 @@ void transport_wait_for_tasks(struct se_cmd *cmd) if (!atomic_read(&cmd->t_transport_active) || atomic_read(&cmd->t_transport_aborted)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; + return false; } atomic_set(&cmd->t_transport_stop, 1); @@ -4235,6 +4355,8 @@ void transport_wait_for_tasks(struct se_cmd *cmd) cmd->se_tfo->get_task_tag(cmd)); spin_unlock_irqrestore(&cmd->t_state_lock, flags); + + return true; } EXPORT_SYMBOL(transport_wait_for_tasks); @@ -4583,9 +4705,7 @@ get_cmd: break; } ret = transport_generic_new_cmd(cmd); - if (ret == -EAGAIN) - break; - else if (ret < 0) { + if (ret < 0) { cmd->transport_error_status = ret; transport_generic_request_failure(cmd, 0, (cmd->data_direction != @@ -4595,9 +4715,6 @@ get_cmd: case TRANSPORT_PROCESS_WRITE: transport_generic_process_write(cmd); break; - case TRANSPORT_FREE_CMD_INTR: - transport_generic_free_cmd(cmd, 0); - break; case TRANSPORT_PROCESS_TMR: transport_generic_do_tmr(cmd); break; diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index 3749d8b4b423..e05c55100ec6 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -156,7 +156,7 @@ int ft_lport_notify(struct notifier_block *, unsigned long, void *); /* * IO methods. */ -void ft_check_stop_free(struct se_cmd *); +int ft_check_stop_free(struct se_cmd *); void ft_release_cmd(struct se_cmd *); int ft_queue_status(struct se_cmd *); int ft_queue_data_in(struct se_cmd *); diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 6195026cc7b0..4fac37c4c615 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -112,9 +112,10 @@ void ft_release_cmd(struct se_cmd *se_cmd) ft_free_cmd(cmd); } -void ft_check_stop_free(struct se_cmd *se_cmd) +int ft_check_stop_free(struct se_cmd *se_cmd) { transport_generic_free_cmd(se_cmd, 0); + return 1; } /* diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 708f8e92771a..dd9a5743fa99 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -678,10 +678,10 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, return; if (delay > 1000) - schedule_delayed_work(&(tz->poll_queue), + queue_delayed_work(system_freezable_wq, &(tz->poll_queue), round_jiffies(msecs_to_jiffies(delay))); else - schedule_delayed_work(&(tz->poll_queue), + queue_delayed_work(system_freezable_wq, &(tz->poll_queue), msecs_to_jiffies(delay)); } diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig index e371753ba921..4222035acfb7 100644 --- a/drivers/tty/hvc/Kconfig +++ b/drivers/tty/hvc/Kconfig @@ -34,6 +34,15 @@ config HVC_ISERIES help iSeries machines support a hypervisor virtual console. +config HVC_OPAL + bool "OPAL Console support" + depends on PPC_POWERNV + select HVC_DRIVER + select HVC_IRQ + default y + help + PowerNV machines running under OPAL need that driver to get a console + config HVC_RTAS bool "IBM RTAS Console support" depends on PPC_RTAS diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile index e29205316376..89abf40bc73d 100644 --- a/drivers/tty/hvc/Makefile +++ b/drivers/tty/hvc/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi_lib.o +obj-$(CONFIG_HVC_OPAL) += hvc_opal.o hvsi_lib.o obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 7430bc3c8d53..b6b2d18fa38d 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -852,7 +852,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, * find index to use: * see if this vterm id matches one registered for console. */ - for (i = 0; i < MAX_NR_HVC_CONSOLES; i++) + for (i=0; i < MAX_NR_HVC_CONSOLES; i++) if (vtermnos[i] == hp->vtermno && cons_ops[i] == hp->ops) break; @@ -862,13 +862,9 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, i = ++last_hvc; hp->index = i; - hvc_console.index = i; - vtermnos[i] = vtermno; - cons_ops[i] = ops; list_add_tail(&(hp->next), &hvc_structs); spin_unlock(&hvc_structs_lock); - register_console(&hvc_console); return hp; } @@ -879,7 +875,6 @@ int hvc_remove(struct hvc_struct *hp) unsigned long flags; struct tty_struct *tty; - unregister_console(&hvc_console); spin_lock_irqsave(&hp->lock, flags); tty = tty_kref_get(hp->tty); diff --git a/drivers/tty/hvc/hvc_iseries.c b/drivers/tty/hvc/hvc_iseries.c index 21c54955084e..3f4a897bf4d7 100644 --- a/drivers/tty/hvc/hvc_iseries.c +++ b/drivers/tty/hvc/hvc_iseries.c @@ -23,6 +23,7 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/spinlock.h> #include <linux/console.h> diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c new file mode 100644 index 000000000000..ced26c8ccd57 --- /dev/null +++ b/drivers/tty/hvc/hvc_opal.c @@ -0,0 +1,425 @@ +/* + * opal driver interface to hvc_console.c + * + * Copyright 2011 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. + * + * 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 + * + */ + +#undef DEBUG + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/console.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/export.h> + +#include <asm/hvconsole.h> +#include <asm/prom.h> +#include <asm/firmware.h> +#include <asm/hvsi.h> +#include <asm/udbg.h> +#include <asm/opal.h> + +#include "hvc_console.h" + +static const char hvc_opal_name[] = "hvc_opal"; + +static struct of_device_id hvc_opal_match[] __devinitdata = { + { .name = "serial", .compatible = "ibm,opal-console-raw" }, + { .name = "serial", .compatible = "ibm,opal-console-hvsi" }, + { }, +}; + +typedef enum hv_protocol { + HV_PROTOCOL_RAW, + HV_PROTOCOL_HVSI +} hv_protocol_t; + +struct hvc_opal_priv { + hv_protocol_t proto; /* Raw data or HVSI packets */ + struct hvsi_priv hvsi; /* HVSI specific data */ +}; +static struct hvc_opal_priv *hvc_opal_privs[MAX_NR_HVC_CONSOLES]; + +/* For early boot console */ +static struct hvc_opal_priv hvc_opal_boot_priv; +static u32 hvc_opal_boot_termno; + +static const struct hv_ops hvc_opal_raw_ops = { + .get_chars = opal_get_chars, + .put_chars = opal_put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, + .notifier_hangup = notifier_hangup_irq, +}; + +static int hvc_opal_hvsi_get_chars(uint32_t vtermno, char *buf, int count) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[vtermno]; + + if (WARN_ON(!pv)) + return -ENODEV; + + return hvsilib_get_chars(&pv->hvsi, buf, count); +} + +static int hvc_opal_hvsi_put_chars(uint32_t vtermno, const char *buf, int count) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[vtermno]; + + if (WARN_ON(!pv)) + return -ENODEV; + + return hvsilib_put_chars(&pv->hvsi, buf, count); +} + +static int hvc_opal_hvsi_open(struct hvc_struct *hp, int data) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; + int rc; + + pr_devel("HVSI@%x: do open !\n", hp->vtermno); + + rc = notifier_add_irq(hp, data); + if (rc) + return rc; + + return hvsilib_open(&pv->hvsi, hp); +} + +static void hvc_opal_hvsi_close(struct hvc_struct *hp, int data) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; + + pr_devel("HVSI@%x: do close !\n", hp->vtermno); + + hvsilib_close(&pv->hvsi, hp); + + notifier_del_irq(hp, data); +} + +void hvc_opal_hvsi_hangup(struct hvc_struct *hp, int data) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; + + pr_devel("HVSI@%x: do hangup !\n", hp->vtermno); + + hvsilib_close(&pv->hvsi, hp); + + notifier_hangup_irq(hp, data); +} + +static int hvc_opal_hvsi_tiocmget(struct hvc_struct *hp) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; + + if (!pv) + return -EINVAL; + return pv->hvsi.mctrl; +} + +static int hvc_opal_hvsi_tiocmset(struct hvc_struct *hp, unsigned int set, + unsigned int clear) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; + + pr_devel("HVSI@%x: Set modem control, set=%x,clr=%x\n", + hp->vtermno, set, clear); + + if (set & TIOCM_DTR) + hvsilib_write_mctrl(&pv->hvsi, 1); + else if (clear & TIOCM_DTR) + hvsilib_write_mctrl(&pv->hvsi, 0); + + return 0; +} + +static const struct hv_ops hvc_opal_hvsi_ops = { + .get_chars = hvc_opal_hvsi_get_chars, + .put_chars = hvc_opal_hvsi_put_chars, + .notifier_add = hvc_opal_hvsi_open, + .notifier_del = hvc_opal_hvsi_close, + .notifier_hangup = hvc_opal_hvsi_hangup, + .tiocmget = hvc_opal_hvsi_tiocmget, + .tiocmset = hvc_opal_hvsi_tiocmset, +}; + +static int __devinit hvc_opal_probe(struct platform_device *dev) +{ + const struct hv_ops *ops; + struct hvc_struct *hp; + struct hvc_opal_priv *pv; + hv_protocol_t proto; + unsigned int termno, boot = 0; + const __be32 *reg; + + if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) { + proto = HV_PROTOCOL_RAW; + ops = &hvc_opal_raw_ops; + } else if (of_device_is_compatible(dev->dev.of_node, + "ibm,opal-console-hvsi")) { + proto = HV_PROTOCOL_HVSI; + ops = &hvc_opal_hvsi_ops; + } else { + pr_err("hvc_opal: Unkown protocol for %s\n", + dev->dev.of_node->full_name); + return -ENXIO; + } + + reg = of_get_property(dev->dev.of_node, "reg", NULL); + termno = reg ? be32_to_cpup(reg) : 0; + + /* Is it our boot one ? */ + if (hvc_opal_privs[termno] == &hvc_opal_boot_priv) { + pv = hvc_opal_privs[termno]; + boot = 1; + } else if (hvc_opal_privs[termno] == NULL) { + pv = kzalloc(sizeof(struct hvc_opal_priv), GFP_KERNEL); + if (!pv) + return -ENOMEM; + pv->proto = proto; + hvc_opal_privs[termno] = pv; + if (proto == HV_PROTOCOL_HVSI) + hvsilib_init(&pv->hvsi, opal_get_chars, opal_put_chars, + termno, 0); + + /* Instanciate now to establish a mapping index==vtermno */ + hvc_instantiate(termno, termno, ops); + } else { + pr_err("hvc_opal: Device %s has duplicate terminal number #%d\n", + dev->dev.of_node->full_name, termno); + return -ENXIO; + } + + pr_info("hvc%d: %s protocol on %s%s\n", termno, + proto == HV_PROTOCOL_RAW ? "raw" : "hvsi", + dev->dev.of_node->full_name, + boot ? " (boot console)" : ""); + + /* We don't do IRQ yet */ + hp = hvc_alloc(termno, 0, ops, MAX_VIO_PUT_CHARS); + if (IS_ERR(hp)) + return PTR_ERR(hp); + dev_set_drvdata(&dev->dev, hp); + + return 0; +} + +static int __devexit hvc_opal_remove(struct platform_device *dev) +{ + struct hvc_struct *hp = dev_get_drvdata(&dev->dev); + int rc, termno; + + termno = hp->vtermno; + rc = hvc_remove(hp); + if (rc == 0) { + if (hvc_opal_privs[termno] != &hvc_opal_boot_priv) + kfree(hvc_opal_privs[termno]); + hvc_opal_privs[termno] = NULL; + } + return rc; +} + +static struct platform_driver hvc_opal_driver = { + .probe = hvc_opal_probe, + .remove = __devexit_p(hvc_opal_remove), + .driver = { + .name = hvc_opal_name, + .owner = THIS_MODULE, + .of_match_table = hvc_opal_match, + } +}; + +static int __init hvc_opal_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_OPAL)) + return -ENODEV; + + /* Register as a vio device to receive callbacks */ + return platform_driver_register(&hvc_opal_driver); +} +module_init(hvc_opal_init); + +static void __exit hvc_opal_exit(void) +{ + platform_driver_unregister(&hvc_opal_driver); +} +module_exit(hvc_opal_exit); + +static void udbg_opal_putc(char c) +{ + unsigned int termno = hvc_opal_boot_termno; + int count = -1; + + if (c == '\n') + udbg_opal_putc('\r'); + + do { + switch(hvc_opal_boot_priv.proto) { + case HV_PROTOCOL_RAW: + count = opal_put_chars(termno, &c, 1); + break; + case HV_PROTOCOL_HVSI: + count = hvc_opal_hvsi_put_chars(termno, &c, 1); + break; + } + } while(count == 0 || count == -EAGAIN); +} + +static int udbg_opal_getc_poll(void) +{ + unsigned int termno = hvc_opal_boot_termno; + int rc = 0; + char c; + + switch(hvc_opal_boot_priv.proto) { + case HV_PROTOCOL_RAW: + rc = opal_get_chars(termno, &c, 1); + break; + case HV_PROTOCOL_HVSI: + rc = hvc_opal_hvsi_get_chars(termno, &c, 1); + break; + } + if (!rc) + return -1; + return c; +} + +static int udbg_opal_getc(void) +{ + int ch; + for (;;) { + ch = udbg_opal_getc_poll(); + if (ch == -1) { + /* This shouldn't be needed...but... */ + volatile unsigned long delay; + for (delay=0; delay < 2000000; delay++) + ; + } else { + return ch; + } + } +} + +static void udbg_init_opal_common(void) +{ + udbg_putc = udbg_opal_putc; + udbg_getc = udbg_opal_getc; + udbg_getc_poll = udbg_opal_getc_poll; + tb_ticks_per_usec = 0x200; /* Make udelay not suck */ +} + +void __init hvc_opal_init_early(void) +{ + struct device_node *stdout_node = NULL; + const u32 *termno; + const char *name = NULL; + const struct hv_ops *ops; + u32 index; + + /* find the boot console from /chosen/stdout */ + if (of_chosen) + name = of_get_property(of_chosen, "linux,stdout-path", NULL); + if (name) { + stdout_node = of_find_node_by_path(name); + if (!stdout_node) { + pr_err("hvc_opal: Failed to locate default console!\n"); + return; + } + } else { + struct device_node *opal, *np; + + /* Current OPAL takeover doesn't provide the stdout + * path, so we hard wire it + */ + opal = of_find_node_by_path("/ibm,opal/consoles"); + if (opal) + pr_devel("hvc_opal: Found consoles in new location\n"); + if (!opal) { + opal = of_find_node_by_path("/ibm,opal"); + if (opal) + pr_devel("hvc_opal: " + "Found consoles in old location\n"); + } + if (!opal) + return; + for_each_child_of_node(opal, np) { + if (!strcmp(np->name, "serial")) { + stdout_node = np; + break; + } + } + of_node_put(opal); + } + if (!stdout_node) + return; + termno = of_get_property(stdout_node, "reg", NULL); + index = termno ? *termno : 0; + if (index >= MAX_NR_HVC_CONSOLES) + return; + hvc_opal_privs[index] = &hvc_opal_boot_priv; + + /* Check the protocol */ + if (of_device_is_compatible(stdout_node, "ibm,opal-console-raw")) { + hvc_opal_boot_priv.proto = HV_PROTOCOL_RAW; + ops = &hvc_opal_raw_ops; + pr_devel("hvc_opal: Found RAW console\n"); + } + else if (of_device_is_compatible(stdout_node,"ibm,opal-console-hvsi")) { + hvc_opal_boot_priv.proto = HV_PROTOCOL_HVSI; + ops = &hvc_opal_hvsi_ops; + hvsilib_init(&hvc_opal_boot_priv.hvsi, opal_get_chars, + opal_put_chars, index, 1); + /* HVSI, perform the handshake now */ + hvsilib_establish(&hvc_opal_boot_priv.hvsi); + pr_devel("hvc_opal: Found HVSI console\n"); + } else + goto out; + hvc_opal_boot_termno = index; + udbg_init_opal_common(); + add_preferred_console("hvc", index, NULL); + hvc_instantiate(index, index, ops); +out: + of_node_put(stdout_node); +} + +#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_RAW +void __init udbg_init_debug_opal(void) +{ + u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO; + hvc_opal_privs[index] = &hvc_opal_boot_priv; + hvc_opal_boot_priv.proto = HV_PROTOCOL_RAW; + hvc_opal_boot_termno = index; + udbg_init_opal_common(); +} +#endif /* CONFIG_PPC_EARLY_DEBUG_OPAL_RAW */ + +#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI +void __init udbg_init_debug_opal_hvsi(void) +{ + u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO; + hvc_opal_privs[index] = &hvc_opal_boot_priv; + hvc_opal_boot_termno = index; + udbg_init_opal_common(); + hvsilib_init(&hvc_opal_boot_priv.hvsi, opal_get_chars, opal_put_chars, + index, 1); + hvsilib_establish(&hvc_opal_boot_priv.hvsi); +} +#endif /* CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI */ diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index 130aace67f31..fc3c3ad6c072 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -41,6 +41,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/console.h> +#include <linux/module.h> #include <asm/hvconsole.h> #include <asm/vio.h> diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 55882b5930a6..b9040bec36bd 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1532,7 +1532,7 @@ static int __devinit hvcs_initialize(void) goto register_fail; } - hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); + hvcs_pi_buff = (unsigned long *) __get_free_page(GFP_KERNEL); if (!hvcs_pi_buff) { rc = -ENOMEM; goto buff_alloc_fail; @@ -1548,7 +1548,7 @@ static int __devinit hvcs_initialize(void) return 0; kthread_fail: - kfree(hvcs_pi_buff); + free_page((unsigned long)hvcs_pi_buff); buff_alloc_fail: tty_unregister_driver(hvcs_tty_driver); register_fail: @@ -1597,7 +1597,7 @@ static void __exit hvcs_module_exit(void) kthread_stop(hvcs_task); spin_lock(&hvcs_pi_lock); - kfree(hvcs_pi_buff); + free_page((unsigned long)hvcs_pi_buff); hvcs_pi_buff = NULL; spin_unlock(&hvcs_pi_lock); diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index bd9b09827b24..6f4dd83d8695 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -183,7 +183,7 @@ int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count) unsigned int tries, read = 0; if (WARN_ON(!pv)) - return 0; + return -ENXIO; /* If we aren't open, don't do anything in order to avoid races * with connection establishment. The hvc core will call this @@ -234,7 +234,7 @@ int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count) int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA); if (WARN_ON(!pv)) - return 0; + return -ENODEV; dp.hdr.type = VS_DATA_PACKET_HEADER; dp.hdr.len = adjcount + sizeof(struct hvsi_header); diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index a87a56cb5417..eeadf1b8e093 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c @@ -450,24 +450,6 @@ static void au_serial_out(struct uart_port *p, int offset, int value) __raw_writel(value, p->membase + offset); } -static unsigned int tsi_serial_in(struct uart_port *p, int offset) -{ - unsigned int tmp; - offset = map_8250_in_reg(p, offset) << p->regshift; - if (offset == UART_IIR) { - tmp = readl(p->membase + (UART_IIR & ~3)); - return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ - } else - return readb(p->membase + offset); -} - -static void tsi_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - if (!((offset == UART_IER) && (value & UART_IER_UUE))) - writeb(value, p->membase + offset); -} - static unsigned int io_serial_in(struct uart_port *p, int offset) { offset = map_8250_in_reg(p, offset) << p->regshift; @@ -508,11 +490,6 @@ static void set_io_from_upio(struct uart_port *p) p->serial_out = au_serial_out; break; - case UPIO_TSI: - p->serial_in = tsi_serial_in; - p->serial_out = tsi_serial_out; - break; - default: p->serial_in = io_serial_in; p->serial_out = io_serial_out; diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 648b6a3efa32..7c867a046c97 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -24,7 +24,7 @@ * * ***********************************************************************/ -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/slab.h> diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 87e7e6c876d4..2b42a01a81c6 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -19,6 +19,7 @@ #include <linux/console.h> #include <linux/vt_kern.h> #include <linux/input.h> +#include <linux/module.h> #define MAX_CONFIG_LEN 40 diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 2af5aa5f3a80..8a6cc8c30b5a 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -43,6 +43,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/device.h> +#include <linux/module.h> #include <linux/serial_core.h> #include <linux/serial.h> #include <linux/spi/spi.h> diff --git a/drivers/tty/serial/max3107-aava.c b/drivers/tty/serial/max3107-aava.c index d73aadd7a9ad..90c40f22ec70 100644 --- a/drivers/tty/serial/max3107-aava.c +++ b/drivers/tty/serial/max3107-aava.c @@ -36,6 +36,7 @@ #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/sfi.h> +#include <linux/module.h> #include <asm/mrst.h> #include "max3107.h" diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c index db00b595cab0..7827000db4f5 100644 --- a/drivers/tty/serial/max3107.c +++ b/drivers/tty/serial/max3107.c @@ -36,6 +36,7 @@ #include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/freezer.h> +#include <linux/module.h> #include "max3107.h" static const struct baud_table brg26_ext[] = { diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c index 9beaff1cec24..dd4c31d1aee5 100644 --- a/drivers/tty/serial/nwpserial.c +++ b/drivers/tty/serial/nwpserial.c @@ -10,6 +10,7 @@ * */ #include <linux/init.h> +#include <linux/export.h> #include <linux/console.h> #include <linux/serial.h> #include <linux/serial_reg.h> diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 9871c57b348e..1945c70539c2 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1446,12 +1446,8 @@ static bool filter(struct dma_chan *chan, void *slave) dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__, param->slave_id); - if (param->dma_dev == chan->device->dev) { - chan->private = param; - return true; - } else { - return false; - } + chan->private = param; + return true; } static void rx_timer_fn(unsigned long arg) @@ -1477,10 +1473,10 @@ static void sci_request_dma(struct uart_port *port) dma_cap_mask_t mask; int nent; - dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__, - port->line, s->cfg->dma_dev); + dev_dbg(port->dev, "%s: port %d\n", __func__, + port->line); - if (!s->cfg->dma_dev) + if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0) return; dma_cap_zero(mask); @@ -1490,7 +1486,6 @@ static void sci_request_dma(struct uart_port *port) /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ param->slave_id = s->cfg->dma_slave_tx; - param->dma_dev = s->cfg->dma_dev; s->cookie_tx = -EINVAL; chan = dma_request_channel(mask, filter, param); @@ -1519,7 +1514,6 @@ static void sci_request_dma(struct uart_port *port) /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ param->slave_id = s->cfg->dma_slave_rx; - param->dma_dev = s->cfg->dma_dev; chan = dma_request_channel(mask, filter, param); dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); @@ -1564,9 +1558,6 @@ static void sci_free_dma(struct uart_port *port) { struct sci_port *s = to_sci_port(port); - if (!s->cfg->dma_dev) - return; - if (s->chan_tx) sci_tx_dma_release(s, false); if (s->chan_rx) @@ -1981,9 +1972,9 @@ static int __devinit sci_init_single(struct platform_device *dev, port->serial_in = sci_serial_in; port->serial_out = sci_serial_out; - if (p->dma_dev) - dev_dbg(port->dev, "DMA device %p, tx %d, rx %d\n", - p->dma_dev, p->dma_slave_tx, p->dma_slave_rx); + if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) + dev_dbg(port->dev, "DMA tx %d, rx %d\n", + p->dma_slave_tx, p->dma_slave_rx); return 0; } diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index a4b63bfeaa2f..e76c8b747fb8 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -29,6 +29,7 @@ #include <linux/platform_device.h> #include <linux/ioport.h> #include <linux/slab.h> +#include <linux/module.h> #include "timbuart.h" diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 8c03b127fd03..b627363352e5 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -20,6 +20,7 @@ #include <linux/irq.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/module.h> #define XUARTPS_TTY_NAME "ttyPS" #define XUARTPS_NAME "xuartps" diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 66825c9f516a..7a367ff5122b 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -22,6 +22,7 @@ #include <linux/kernel.h> #include <linux/major.h> #include <linux/errno.h> +#include <linux/export.h> #include <linux/tty.h> #include <linux/interrupt.h> #include <linux/mm.h> diff --git a/drivers/uio/uio_pdrv.c b/drivers/uio/uio_pdrv.c index bdc3db946122..ff5059517351 100644 --- a/drivers/uio/uio_pdrv.c +++ b/drivers/uio/uio_pdrv.c @@ -11,6 +11,7 @@ #include <linux/platform_device.h> #include <linux/uio_driver.h> #include <linux/stringify.h> +#include <linux/module.h> #include <linux/slab.h> #define DRIVER_NAME "uio_pdrv" diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 0b2ed71e3bfa..25de302009a1 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -18,6 +18,7 @@ #include <linux/uio_driver.h> #include <linux/spinlock.h> #include <linux/bitops.h> +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/stringify.h> #include <linux/pm_runtime.h> diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c index 62050f7a4f97..57ae44cd0b88 100644 --- a/drivers/usb/c67x00/c67x00-drv.c +++ b/drivers/usb/c67x00/c67x00-drv.c @@ -38,6 +38,7 @@ #include <linux/io.h> #include <linux/list.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/usb.h> #include <linux/usb/c67x00.h> diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 3b029a0a4787..45887a0ff873 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -24,6 +24,7 @@ #include <linux/device.h> #include <linux/slab.h> +#include <linux/export.h> #include <linux/usb.h> #include <linux/usb/quirks.h> #include <linux/usb/hcd.h> @@ -1667,6 +1668,11 @@ int usb_runtime_suspend(struct device *dev) return -EAGAIN; status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); + + /* Allow a retry if autosuspend failed temporarily */ + if (status == -EAGAIN || status == -EBUSY) + usb_mark_last_busy(udev); + /* The PM core reacts badly unless the return code is 0, * -EAGAIN, or -EBUSY, so always return -EBUSY on an error. */ diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index 7542dce3f5a1..7728c91dfa2e 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/notifier.h> #include <linux/usb.h> #include <linux/mutex.h> diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 672674c2fb3d..725550f06fab 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/utsname.h> +#include <linux/module.h> #include "u_ether.h" #include "u_serial.h" diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 8a5529d214fb..f71b0787983f 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -14,6 +14,7 @@ #include <linux/kallsyms.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/device.h> #include <linux/utsname.h> diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index f855ecf7a637..6256420089f3 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -9,6 +9,7 @@ /* verbose messages */ #include <linux/kernel.h> #include <linux/device.h> +#include <linux/module.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 6b1c20b6c9b2..acb38004eec0 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -20,6 +20,7 @@ #include <linux/blkdev.h> #include <linux/pagemap.h> +#include <linux/export.h> #include <asm/unaligned.h> #include <linux/usb/composite.h> diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index e3f74bf5da2d..5f400f66aa9b 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/device.h> +#include <linux/module.h> #include "u_serial.h" #include "gadget_chips.h" diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 168906d2b5d4..7aa7ac82c02c 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/device.h> +#include <linux/module.h> #include "g_zero.h" #include "gadget_chips.h" diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 3ac4f51cd0bb..f7e39b0365ce 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -243,6 +243,7 @@ #include <linux/kref.h> #include <linux/kthread.h> #include <linux/limits.h> +#include <linux/module.h> #include <linux/rwsem.h> #include <linux/slab.h> #include <linux/spinlock.h> diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index e593f2849fa9..74da206c8406 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -13,6 +13,7 @@ #include <linux/err.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 8fcde37aa6d4..681bd038b1d8 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/utsname.h> +#include <linux/module.h> #include <linux/device.h> #include <sound/core.h> diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 3a4a664bab44..6597a6813e43 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -25,6 +25,7 @@ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/slab.h> +#include <linux/export.h> #include "u_serial.h" diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 79a66d622f9c..9037035ad1e4 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -16,6 +16,7 @@ #include <linux/io.h> #include <linux/of_platform.h> #include <linux/clk.h> +#include <linux/module.h> struct fsl_usb2_dev_data { char *dr_mode; /* controller mode */ diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 2c7fc830c9e4..a7dc1e1d45f2 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -11,6 +11,7 @@ #include <linux/usb.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/usb/isp1760.h> #include <linux/usb/hcd.h> diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 629a96813fd6..27a3dec32fa2 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -13,6 +13,7 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/acpi.h> #include <linux/dmi.h> #include "pci-quirks.h" diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c index 767af265e002..ba61dae9e4d2 100644 --- a/drivers/usb/host/whci/debug.c +++ b/drivers/usb/host/whci/debug.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/export.h> #include "../../wusbcore/wusbhc.h" diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index 9546f6cd01f0..1e141f755b26 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -17,6 +17,7 @@ */ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/module.h> #include <linux/uwb/umc.h> #include "../../wusbcore/wusbhc.h" diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 431efe72b1f7..430e88fd3f6c 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -20,6 +20,7 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/gfp.h> #include <asm/unaligned.h> #include "xhci.h" diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 9f51f88cc0f5..ef98b38626fb 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -22,6 +22,7 @@ #include <linux/pci.h> #include <linux/slab.h> +#include <linux/module.h> #include "xhci.h" diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index a04b2ff9dd83..91cd85076a44 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -11,6 +11,7 @@ #include <linux/types.h> #include <linux/fs.h> #include <linux/cdev.h> +#include <linux/export.h> #include <linux/usb.h> #include <linux/poll.h> #include <linux/compat.h> diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c index e5ce42bd316e..ebd6189a5014 100644 --- a/drivers/usb/mon/mon_stat.c +++ b/drivers/usb/mon/mon_stat.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/export.h> #include <linux/usb.h> #include <linux/fs.h> #include <asm/uaccess.h> diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 1c3afcc11bd9..ad408251d955 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -9,6 +9,7 @@ #include <linux/usb.h> #include <linux/slab.h> #include <linux/time.h> +#include <linux/export.h> #include <linux/mutex.h> #include <linux/debugfs.h> #include <linux/scatterlist.h> diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c index 52733d9959b4..fb644c107ded 100644 --- a/drivers/usb/otg/gpio_vbus.c +++ b/drivers/usb/otg/gpio_vbus.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/gpio.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/usb.h> diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c index fb7adeff9ffa..307c27bc51eb 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/otg/otg.c @@ -10,6 +10,7 @@ */ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/device.h> #include <linux/usb/otg.h> diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c index 770d799d5afb..0b0466728fdc 100644 --- a/drivers/usb/otg/ulpi.c +++ b/drivers/usb/otg/ulpi.c @@ -25,6 +25,7 @@ #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/export.h> #include <linux/usb.h> #include <linux/usb/otg.h> #include <linux/usb/ulpi.h> diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index aba201cb872c..b43d07df4c44 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -47,6 +47,7 @@ #include <asm/unaligned.h> #include <linux/tty.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/tty_flip.h> #include <linux/usb.h> #include <linux/usb/serial.h> diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index b9bb24729c99..aa9367f5b421 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -13,6 +13,7 @@ #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/module.h> #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/slab.h> diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c index 89460181d122..e0f76bb05915 100644 --- a/drivers/usb/storage/option_ms.c +++ b/drivers/usb/storage/option_ms.c @@ -22,6 +22,7 @@ #include <linux/usb.h> #include <linux/slab.h> +#include <linux/module.h> #include "usb.h" #include "transport.h" diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c index fc310f75eada..93c1a4d86f51 100644 --- a/drivers/usb/storage/protocol.c +++ b/drivers/usb/storage/protocol.c @@ -43,6 +43,7 @@ */ #include <linux/highmem.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 1deca07c8265..37539c89e3ba 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -3,6 +3,7 @@ #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <linux/usb.h> +#include <linux/module.h> #include <linux/slab.h> #include "usb.h" diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index ff32390d61e5..0e5c91c6187f 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -46,6 +46,7 @@ #include <linux/sched.h> #include <linux/gfp.h> #include <linux/errno.h> +#include <linux/export.h> #include <linux/usb/quirks.h> diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 23f0dd9c36d4..1d10d5b8204c 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -11,6 +11,7 @@ #include <linux/blkdev.h> #include <linux/slab.h> #include <linux/types.h> +#include <linux/module.h> #include <linux/usb.h> #include <linux/usb/storage.h> diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index 7ec24e46b34b..231009af65a3 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -90,6 +90,7 @@ #include <linux/ctype.h> #include <linux/slab.h> #include <linux/workqueue.h> +#include <linux/export.h> #include "wusbhc.h" static void wusbhc_devconnect_acked_work(struct work_struct *work); diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c index 0a57ff0a0b0c..b8c72583c040 100644 --- a/drivers/usb/wusbcore/mmc.c +++ b/drivers/usb/wusbcore/mmc.c @@ -38,6 +38,7 @@ */ #include <linux/usb/wusb.h> #include <linux/slab.h> +#include <linux/export.h> #include "wusbhc.h" /* Initialize the MMCIEs handling mechanism */ diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c index 39de3900ad20..59ff254dfb6f 100644 --- a/drivers/usb/wusbcore/rh.c +++ b/drivers/usb/wusbcore/rh.c @@ -70,6 +70,7 @@ * wusbhc_rh_start_port_reset() ??? unimplemented */ #include <linux/slab.h> +#include <linux/export.h> #include "wusbhc.h" /* diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c index b60799b811c1..371f61733f05 100644 --- a/drivers/usb/wusbcore/security.c +++ b/drivers/usb/wusbcore/security.c @@ -26,6 +26,7 @@ #include <linux/slab.h> #include <linux/usb/ch9.h> #include <linux/random.h> +#include <linux/export.h> #include "wusbhc.h" static void wusbhc_set_gtk_callback(struct urb *urb); diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c index 0d1863c9edde..9e4a92461688 100644 --- a/drivers/usb/wusbcore/wa-hc.c +++ b/drivers/usb/wusbcore/wa-hc.c @@ -23,6 +23,7 @@ * FIXME: docs */ #include <linux/slab.h> +#include <linux/module.h> #include "wusbhc.h" #include "wa-hc.h" diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index 2acc7f504c51..f0d546c5a089 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c @@ -61,6 +61,7 @@ #include <linux/atomic.h> #include <linux/bitmap.h> #include <linux/slab.h> +#include <linux/export.h> #include "wusbhc.h" #include "wa-hc.h" diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 419334568be6..57c01ab09ad8 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -84,6 +84,7 @@ #include <linux/slab.h> #include <linux/hash.h> #include <linux/ratelimit.h> +#include <linux/export.h> #include "wa-hc.h" #include "wusbhc.h" diff --git a/drivers/uwb/est.c b/drivers/uwb/est.c index a2eaa3c33b0b..de81ebf51784 100644 --- a/drivers/uwb/est.c +++ b/drivers/uwb/est.c @@ -41,6 +41,7 @@ */ #include <linux/spinlock.h> #include <linux/slab.h> +#include <linux/export.h> #include "uwb-internal.h" diff --git a/drivers/uwb/i1480/dfu/dfu.c b/drivers/uwb/i1480/dfu/dfu.c index da7b1d08003c..b08d1c2ee3fa 100644 --- a/drivers/uwb/i1480/dfu/dfu.c +++ b/drivers/uwb/i1480/dfu/dfu.c @@ -33,6 +33,7 @@ #include <linux/device.h> #include <linux/uwb.h> #include <linux/random.h> +#include <linux/export.h> /* * i1480_rceb_check - Check RCEB for expected field values diff --git a/drivers/uwb/ie.c b/drivers/uwb/ie.c index 30acec740425..902b0f2f961e 100644 --- a/drivers/uwb/ie.c +++ b/drivers/uwb/ie.c @@ -25,6 +25,7 @@ */ #include <linux/slab.h> +#include <linux/export.h> #include "uwb-internal.h" /** diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c index 90113bafefca..5241f1d0ef7a 100644 --- a/drivers/uwb/lc-dev.c +++ b/drivers/uwb/lc-dev.c @@ -25,9 +25,11 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/device.h> +#include <linux/export.h> #include <linux/err.h> #include <linux/kdev_t.h> #include <linux/random.h> +#include <linux/stat.h> #include "uwb-internal.h" /* We initialize addresses to 0xff (invalid, as it is bcast) */ diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c index b4395f41a007..4d688c750801 100644 --- a/drivers/uwb/lc-rc.c +++ b/drivers/uwb/lc-rc.c @@ -36,6 +36,7 @@ #include <linux/etherdevice.h> #include <linux/usb.h> #include <linux/slab.h> +#include <linux/export.h> #include "uwb-internal.h" diff --git a/drivers/uwb/neh.c b/drivers/uwb/neh.c index 697e56a5bcdd..a269937be1b8 100644 --- a/drivers/uwb/neh.c +++ b/drivers/uwb/neh.c @@ -85,6 +85,7 @@ #include <linux/timer.h> #include <linux/slab.h> #include <linux/err.h> +#include <linux/export.h> #include "uwb-internal.h" diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c index 99a19c199095..8ee7d90a8c68 100644 --- a/drivers/uwb/pal.c +++ b/drivers/uwb/pal.c @@ -18,6 +18,7 @@ #include <linux/kernel.h> #include <linux/debugfs.h> #include <linux/uwb.h> +#include <linux/export.h> #include "uwb-internal.h" diff --git a/drivers/uwb/radio.c b/drivers/uwb/radio.c index f0d55495f5e9..d58dfecf9a79 100644 --- a/drivers/uwb/radio.c +++ b/drivers/uwb/radio.c @@ -17,6 +17,7 @@ */ #include <linux/kernel.h> #include <linux/uwb.h> +#include <linux/export.h> #include "uwb-internal.h" diff --git a/drivers/uwb/reset.c b/drivers/uwb/reset.c index 3de630b0f691..703228559e89 100644 --- a/drivers/uwb/reset.c +++ b/drivers/uwb/reset.c @@ -32,6 +32,7 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/export.h> #include "uwb-internal.h" diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c index 78c892233cf1..0b0d8bce842e 100644 --- a/drivers/uwb/rsv.c +++ b/drivers/uwb/rsv.c @@ -19,6 +19,7 @@ #include <linux/uwb.h> #include <linux/slab.h> #include <linux/random.h> +#include <linux/export.h> #include "uwb-internal.h" diff --git a/drivers/uwb/scan.c b/drivers/uwb/scan.c index 367aa12786b9..cbb6a5e703d2 100644 --- a/drivers/uwb/scan.c +++ b/drivers/uwb/scan.c @@ -36,6 +36,7 @@ #include <linux/device.h> #include <linux/err.h> #include <linux/slab.h> +#include <linux/stat.h> #include "uwb-internal.h" diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c index 5fad4e791b3e..82a84d53120f 100644 --- a/drivers/uwb/umc-bus.c +++ b/drivers/uwb/umc-bus.c @@ -8,6 +8,7 @@ #include <linux/kernel.h> #include <linux/sysfs.h> #include <linux/workqueue.h> +#include <linux/module.h> #include <linux/uwb/umc.h> #include <linux/pci.h> diff --git a/drivers/uwb/umc-dev.c b/drivers/uwb/umc-dev.c index b2948ec57878..4613c13cd851 100644 --- a/drivers/uwb/umc-dev.c +++ b/drivers/uwb/umc-dev.c @@ -6,6 +6,7 @@ * This file is released under the GNU GPL v2. */ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/uwb/umc.h> diff --git a/drivers/uwb/umc-drv.c b/drivers/uwb/umc-drv.c index 367b5eb85d60..26d0ae1816bd 100644 --- a/drivers/uwb/umc-drv.c +++ b/drivers/uwb/umc-drv.c @@ -6,6 +6,7 @@ * This file is released under the GNU GPL v2. */ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/uwb/umc.h> int __umc_driver_register(struct umc_driver *umc_drv, struct module *module, diff --git a/drivers/uwb/whci.c b/drivers/uwb/whci.c index b221142446a2..f48093e649e4 100644 --- a/drivers/uwb/whci.c +++ b/drivers/uwb/whci.c @@ -7,6 +7,7 @@ */ #include <linux/delay.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/slab.h> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 4ac48d9ee665..63409c122ae8 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/backlight.h> #include <linux/gfp.h> +#include <linux/module.h> #include <mach/board.h> #include <mach/cpu.h> diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index c04b94da81f7..1105fa1ed7f4 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -17,6 +17,7 @@ #include <linux/i2c.h> #include <linux/backlight.h> #include <linux/mfd/88pm860x.h> +#include <linux/module.h> #define MAX_BRIGHTNESS (0xFF) #define MIN_BRIGHTNESS (0) diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index d1aee730d7d8..dfb763e9147f 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -13,6 +13,7 @@ #include <linux/backlight.h> #include <linux/mfd/adp5520.h> #include <linux/slab.h> +#include <linux/module.h> struct adp5520_bl { struct device *master; diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c index 9f0a491e2a05..7838a23fbdd1 100644 --- a/drivers/video/backlight/ams369fg06.c +++ b/drivers/video/backlight/ams369fg06.c @@ -22,6 +22,7 @@ */ #include <linux/wait.h> +#include <linux/module.h> #include <linux/fb.h> #include <linux/delay.h> #include <linux/gpio.h> diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index 62043f12a5a4..d68f14bbb687 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -19,6 +19,7 @@ #include <linux/backlight.h> #include <linux/mfd/da903x.h> #include <linux/slab.h> +#include <linux/module.h> #define DA9030_WLED_CONTROL 0x25 #define DA9030_WLED_CP_EN (1 << 6) diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c index b0582917f0c8..c74a6f4baa12 100644 --- a/drivers/video/backlight/ep93xx_bl.c +++ b/drivers/video/backlight/ep93xx_bl.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/module.h> #include <linux/io.h> #include <linux/fb.h> #include <linux/backlight.h> diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 3543f1b7d5f1..4f5d1c4cb6ab 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -14,6 +14,7 @@ #include <linux/device.h> #include <linux/kernel.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/gpio.h> #include <linux/lcd.h> #include <linux/slab.h> diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c index 5934655eb1ff..da9a5ce0ccb8 100644 --- a/drivers/video/backlight/ld9040.c +++ b/drivers/video/backlight/ld9040.c @@ -30,6 +30,7 @@ #include <linux/kernel.h> #include <linux/lcd.h> #include <linux/backlight.h> +#include <linux/module.h> #include "ld9040_gamma.h" diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index 5d3cf33953ac..4ec78cfe26ea 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -17,6 +17,7 @@ #include <linux/spi/spi.h> #include <linux/spi/lms283gf05.h> +#include <linux/module.h> struct lms283gf05_state { struct spi_device *spi; diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 07e8e273ced0..7bbc802560ea 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -17,6 +17,7 @@ #include <linux/backlight.h> #include <linux/mfd/max8925.h> #include <linux/slab.h> +#include <linux/module.h> #define MAX_BRIGHTNESS (0xff) #define MIN_BRIGHTNESS (0) diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index 694e5aab0d69..e132157d8545 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c @@ -30,6 +30,7 @@ #include <linux/kernel.h> #include <linux/lcd.h> #include <linux/backlight.h> +#include <linux/module.h> #include "s6e63m0_gamma.h" diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index d4c6eb248ff9..fbe9e9316f3b 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/module.h> #include <linux/fb.h> #include <linux/backlight.h> #include <linux/slab.h> diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c index cb09aa1fa138..2c76fdf23f2a 100644 --- a/drivers/video/carminefb.c +++ b/drivers/video/carminefb.c @@ -12,6 +12,7 @@ #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/slab.h> +#include <linux/module.h> #include "carminefb.h" #include "carminefb_regs.h" diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c index e02764319ff7..f56699d8122a 100644 --- a/drivers/video/cobalt_lcdfb.c +++ b/drivers/video/cobalt_lcdfb.c @@ -24,6 +24,7 @@ #include <linux/ioport.h> #include <linux/uaccess.h> #include <linux/platform_device.h> +#include <linux/module.h> /* * Cursor position address diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index 40e5f17d1e4b..2e830ec52a5a 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c @@ -18,6 +18,7 @@ */ #include <linux/platform_device.h> +#include <linux/module.h> #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/clk.h> diff --git a/drivers/video/fb_ddc.c b/drivers/video/fb_ddc.c index 4a874c8d039c..2b106f046fde 100644 --- a/drivers/video/fb_ddc.c +++ b/drivers/video/fb_ddc.c @@ -1,5 +1,5 @@ /* - * driver/vide/fb_ddc.c - DDC/EDID read support. + * drivers/video/fb_ddc.c - DDC/EDID read support. * * Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com> * @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/device.h> +#include <linux/module.h> #include <linux/fb.h> #include <linux/i2c-algo-bit.h> #include <linux/slab.h> diff --git a/drivers/video/fb_notify.c b/drivers/video/fb_notify.c index 8c020389e4fa..74c2da528884 100644 --- a/drivers/video/fb_notify.c +++ b/drivers/video/fb_notify.c @@ -12,6 +12,7 @@ */ #include <linux/fb.h> #include <linux/notifier.h> +#include <linux/export.h> static BLOCKING_NOTIFIER_HEAD(fb_notifier_list); diff --git a/drivers/video/mb862xx/mb862xx-i2c.c b/drivers/video/mb862xx/mb862xx-i2c.c index 934081d2b7ae..273769bb8deb 100644 --- a/drivers/video/mb862xx/mb862xx-i2c.c +++ b/drivers/video/mb862xx/mb862xx-i2c.c @@ -13,6 +13,7 @@ #include <linux/i2c.h> #include <linux/io.h> #include <linux/delay.h> +#include <linux/export.h> #include "mb862xxfb.h" #include "mb862xx_reg.h" diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c index c16ff1d62e91..11a7a333701d 100644 --- a/drivers/video/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/mb862xx/mb862xxfbdrv.c @@ -17,6 +17,7 @@ #include <linux/fb.h> #include <linux/delay.h> #include <linux/uaccess.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index b9344772bac9..cb2ddf164c98 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -28,6 +28,7 @@ #include <mach/msm_iomap.h> #include <mach/msm_fb.h> #include <linux/platform_device.h> +#include <linux/export.h> #include "mdp_hw.h" diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c index 90e3bdd1b7ab..eb381db7fe51 100644 --- a/drivers/video/omap/lcd_mipid.c +++ b/drivers/video/omap/lcd_mipid.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/spi/spi.h> +#include <linux/module.h> #include <plat/lcd_mipid.h> diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index b3ddd743d8a6..25d8e5103193 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -28,6 +28,7 @@ #include <linux/mm.h> #include <linux/slab.h> #include <linux/uaccess.h> +#include <linux/module.h> #include <plat/dma.h> diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 6892cfd2e3b7..3532782551cb 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -25,6 +25,7 @@ #include <linux/kernel.h> #include <linux/dma-mapping.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/jiffies.h> diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 483888a85cfd..976ac23dcd0c 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/platform_device.h> diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 43c04a9889c4..5abf8e7e7456 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -27,6 +27,7 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/mutex.h> +#include <linux/module.h> #include <linux/semaphore.h> #include <linux/seq_file.h> #include <linux/platform_device.h> diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 3e09726d32c7..17033457ee89 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/io.h> +#include <linux/export.h> #include <linux/err.h> #include <linux/delay.h> #include <linux/seq_file.h> diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 1bd3703e42ff..1130c608a561 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/dma-mapping.h> +#include <linux/export.h> #include <linux/vmalloc.h> #include <linux/clk.h> #include <linux/io.h> diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 695dc04cabba..40305ad7841e 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/regulator/consumer.h> +#include <linux/export.h> #include <video/omapdss.h> #include "dss.h" diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 6b1ac23dbbd3..df7bcce5b107 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -27,6 +27,7 @@ #include <linux/mm.h> #include <linux/omapfb.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <video/omapdss.h> #include <plat/vrfb.h> diff --git a/drivers/video/savage/savagefb_accel.c b/drivers/video/savage/savagefb_accel.c index bbcc055d3bb7..bfefa6234cf0 100644 --- a/drivers/video/savage/savagefb_accel.c +++ b/drivers/video/savage/savagefb_accel.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/fb.h> +#include <linux/module.h> #include "savagefb.h" diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 24640c8458ab..72ee96bc6b3e 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/types.h> +#include <linux/module.h> #include <video/mipi_display.h> #include <video/sh_mipi_dsi.h> diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 3a41c013d031..facffc254976 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -23,6 +23,7 @@ #include <linux/console.h> #include <linux/backlight.h> #include <linux/gpio.h> +#include <linux/module.h> #include <video/sh_mobile_lcdc.h> #include <video/sh_mobile_meram.h> #include <linux/atomic.h> diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c index ab5341814c74..d69cfef7c338 100644 --- a/drivers/video/via/via-gpio.c +++ b/drivers/video/via/via-gpio.c @@ -10,6 +10,7 @@ #include <linux/platform_device.h> #include <linux/via-core.h> #include <linux/via-gpio.h> +#include <linux/export.h> /* * The ports we know about. Note that the port-25 gpios are not diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index c8be8af0cc6d..2375e5bbf572 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/vmalloc.h> +#include <linux/module.h> #include <asm/io.h> #include <asm/uaccess.h> #include <video/w100fb.h> diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c index 3d9162151fd2..4939e0ccc4e5 100644 --- a/drivers/virt/fsl_hypervisor.c +++ b/drivers/virt/fsl_hypervisor.c @@ -706,6 +706,7 @@ static const struct file_operations fsl_hv_fops = { .poll = fsl_hv_poll, .read = fsl_hv_read, .unlocked_ioctl = fsl_hv_ioctl, + .compat_ioctl = fsl_hv_ioctl, }; static struct miscdevice fsl_hv_misc_dev = { diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index efb35aa8309a..984c501c258f 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -1,6 +1,7 @@ #include <linux/virtio.h> #include <linux/spinlock.h> #include <linux/virtio_config.h> +#include <linux/module.h> /* Unique numbering for virtio devices. */ static unsigned int dev_index; diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index e058ace2a4ad..94fd738a7741 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -25,6 +25,7 @@ #include <linux/freezer.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/module.h> struct virtio_balloon { diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 4acf88884f9b..c7a2c208f6ea 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -21,6 +21,7 @@ #include <linux/virtio_config.h> #include <linux/device.h> #include <linux/slab.h> +#include <linux/module.h> /* virtio guest is communicating with a virtual "device" that actually runs on * a host processor. Memory barriers are used to control SMP effects. */ diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index 63359797c8b1..e9309778ee72 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c @@ -23,6 +23,7 @@ #include <linux/list.h> #include <linux/sched.h> /* schedule_timeout() */ #include <linux/delay.h> +#include <linux/export.h> #include "w1_family.h" #include "w1.h" diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index f79e62e54e8d..68288355727a 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c @@ -24,6 +24,8 @@ #include <linux/delay.h> #include <linux/kthread.h> #include <linux/slab.h> +#include <linux/export.h> +#include <linux/moduleparam.h> #include "w1.h" #include "w1_log.h" diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 64c6752ea2c6..6285867a9356 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -66,6 +66,7 @@ config SOFT_WATCHDOG config WM831X_WATCHDOG tristate "WM831x watchdog" depends on MFD_WM831X + select WATCHDOG_CORE help Support for the watchdog in the WM831x AudioPlus PMICs. When the watchdog triggers the system will be reset. @@ -170,6 +171,7 @@ config HAVE_S3C2410_WATCHDOG config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" depends on ARCH_S3C2410 || HAVE_S3C2410_WATCHDOG + select WATCHDOG_CORE help Watchdog timer block in the Samsung SoCs. This will reboot the system when the timer expires with the watchdog enabled. diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index 9291506b8b23..03f449a430d2 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c @@ -429,7 +429,7 @@ static int __init coh901327_probe(struct platform_device *pdev) writew(U300_WDOG_SR_RESET_STATUS_RESET, virtbase + U300_WDOG_SR); irq = platform_get_irq(pdev, 0); - if (request_irq(irq, coh901327_interrupt, IRQF_DISABLED, + if (request_irq(irq, coh901327_interrupt, 0, DRV_NAME " Bark", pdev)) { ret = -EIO; goto out_no_irq; diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c index f1d1da662fbe..41018d429abb 100644 --- a/drivers/watchdog/eurotechwdt.c +++ b/drivers/watchdog/eurotechwdt.c @@ -427,7 +427,7 @@ static int __init eurwdt_init(void) { int ret; - ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL); + ret = request_irq(irq, eurwdt_interrupt, 0, "eurwdt", NULL); if (ret) { printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); goto out; diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 751a591684da..ba6ad662635a 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -1,7 +1,7 @@ /* * intel TCO Watchdog Driver * - * (c) Copyright 2006-2010 Wim Van Sebroeck <wim@iguana.be>. + * (c) Copyright 2006-2011 Wim Van Sebroeck <wim@iguana.be>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -44,7 +44,7 @@ /* Module and version information */ #define DRV_NAME "iTCO_wdt" -#define DRV_VERSION "1.06" +#define DRV_VERSION "1.07" #define PFX DRV_NAME ": " /* Includes */ @@ -384,6 +384,11 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +static int turn_SMI_watchdog_clear_off = 0; +module_param(turn_SMI_watchdog_clear_off, int, 0); +MODULE_PARM_DESC(turn_SMI_watchdog_clear_off, + "Turn off SMI clearing watchdog (default=0)"); + /* * Some TCO specific functions */ @@ -808,10 +813,12 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, ret = -EIO; goto out_unmap; } - /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ - val32 = inl(SMI_EN); - val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ - outl(val32, SMI_EN); + if (turn_SMI_watchdog_clear_off) { + /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ + val32 = inl(SMI_EN); + val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ + outl(val32, SMI_EN); + } /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */ diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c index 4dc31024d26c..82ccd36e2c90 100644 --- a/drivers/watchdog/mpcore_wdt.c +++ b/drivers/watchdog/mpcore_wdt.c @@ -367,8 +367,7 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev) goto err_misc; } - ret = request_irq(wdt->irq, mpcore_wdt_fire, IRQF_DISABLED, - "mpcore_wdt", wdt); + ret = request_irq(wdt->irq, mpcore_wdt_fire, 0, "mpcore_wdt", wdt); if (ret) { dev_printk(KERN_ERR, wdt->dev, "cannot register IRQ%d for watchdog\n", wdt->irq); diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c index 945ee8300306..7c0d8630e641 100644 --- a/drivers/watchdog/octeon-wdt-main.c +++ b/drivers/watchdog/octeon-wdt-main.c @@ -402,7 +402,7 @@ static void octeon_wdt_setup_interrupt(int cpu) irq = OCTEON_IRQ_WDOG0 + core; if (request_irq(irq, octeon_wdt_poke_irq, - IRQF_DISABLED, "octeon_wdt", octeon_wdt_poke_irq)) + IRQF_NO_THREAD, "octeon_wdt", octeon_wdt_poke_irq)) panic("octeon_wdt: Couldn't obtain irq %d", irq); cpumask_set_cpu(cpu, &irq_enabled_cpus); diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 30da88f47cd3..5de7e4fa5b8a 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -27,9 +27,8 @@ #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/timer.h> -#include <linux/miscdevice.h> +#include <linux/miscdevice.h> /* for MODULE_ALIAS_MISCDEV */ #include <linux/watchdog.h> -#include <linux/fs.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/interrupt.h> @@ -38,6 +37,7 @@ #include <linux/io.h> #include <linux/cpufreq.h> #include <linux/slab.h> +#include <linux/err.h> #include <mach/map.h> @@ -74,14 +74,12 @@ MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " "0 to reboot (default 0)"); MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); -static unsigned long open_lock; static struct device *wdt_dev; /* platform device attached to */ static struct resource *wdt_mem; static struct resource *wdt_irq; static struct clk *wdt_clock; static void __iomem *wdt_base; static unsigned int wdt_count; -static char expect_close; static DEFINE_SPINLOCK(wdt_lock); /* watchdog control routines */ @@ -93,11 +91,13 @@ static DEFINE_SPINLOCK(wdt_lock); /* functions */ -static void s3c2410wdt_keepalive(void) +static int s3c2410wdt_keepalive(struct watchdog_device *wdd) { spin_lock(&wdt_lock); writel(wdt_count, wdt_base + S3C2410_WTCNT); spin_unlock(&wdt_lock); + + return 0; } static void __s3c2410wdt_stop(void) @@ -109,14 +109,16 @@ static void __s3c2410wdt_stop(void) writel(wtcon, wdt_base + S3C2410_WTCON); } -static void s3c2410wdt_stop(void) +static int s3c2410wdt_stop(struct watchdog_device *wdd) { spin_lock(&wdt_lock); __s3c2410wdt_stop(); spin_unlock(&wdt_lock); + + return 0; } -static void s3c2410wdt_start(void) +static int s3c2410wdt_start(struct watchdog_device *wdd) { unsigned long wtcon; @@ -142,6 +144,8 @@ static void s3c2410wdt_start(void) writel(wdt_count, wdt_base + S3C2410_WTCNT); writel(wtcon, wdt_base + S3C2410_WTCON); spin_unlock(&wdt_lock); + + return 0; } static inline int s3c2410wdt_is_running(void) @@ -149,7 +153,7 @@ static inline int s3c2410wdt_is_running(void) return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE; } -static int s3c2410wdt_set_heartbeat(int timeout) +static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeout) { unsigned long freq = clk_get_rate(wdt_clock); unsigned int count; @@ -182,8 +186,6 @@ static int s3c2410wdt_set_heartbeat(int timeout) } } - tmr_margin = timeout; - DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", __func__, timeout, divisor, count, count/divisor); @@ -201,70 +203,6 @@ static int s3c2410wdt_set_heartbeat(int timeout) return 0; } -/* - * /dev/watchdog handling - */ - -static int s3c2410wdt_open(struct inode *inode, struct file *file) -{ - if (test_and_set_bit(0, &open_lock)) - return -EBUSY; - - if (nowayout) - __module_get(THIS_MODULE); - - expect_close = 0; - - /* start the timer */ - s3c2410wdt_start(); - return nonseekable_open(inode, file); -} - -static int s3c2410wdt_release(struct inode *inode, struct file *file) -{ - /* - * Shut off the timer. - * Lock it in if it's a module and we set nowayout - */ - - if (expect_close == 42) - s3c2410wdt_stop(); - else { - dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n"); - s3c2410wdt_keepalive(); - } - expect_close = 0; - clear_bit(0, &open_lock); - return 0; -} - -static ssize_t s3c2410wdt_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) -{ - /* - * Refresh the timer. - */ - if (len) { - if (!nowayout) { - size_t i; - - /* In case it was set long ago */ - expect_close = 0; - - for (i = 0; i != len; i++) { - char c; - - if (get_user(c, data + i)) - return -EFAULT; - if (c == 'V') - expect_close = 42; - } - } - s3c2410wdt_keepalive(); - } - return len; -} - #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE) static const struct watchdog_info s3c2410_wdt_ident = { @@ -273,53 +211,17 @@ static const struct watchdog_info s3c2410_wdt_ident = { .identity = "S3C2410 Watchdog", }; - -static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - void __user *argp = (void __user *)arg; - int __user *p = argp; - int new_margin; - - switch (cmd) { - case WDIOC_GETSUPPORT: - return copy_to_user(argp, &s3c2410_wdt_ident, - sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - case WDIOC_KEEPALIVE: - s3c2410wdt_keepalive(); - return 0; - case WDIOC_SETTIMEOUT: - if (get_user(new_margin, p)) - return -EFAULT; - if (s3c2410wdt_set_heartbeat(new_margin)) - return -EINVAL; - s3c2410wdt_keepalive(); - return put_user(tmr_margin, p); - case WDIOC_GETTIMEOUT: - return put_user(tmr_margin, p); - default: - return -ENOTTY; - } -} - -/* kernel interface */ - -static const struct file_operations s3c2410wdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = s3c2410wdt_write, - .unlocked_ioctl = s3c2410wdt_ioctl, - .open = s3c2410wdt_open, - .release = s3c2410wdt_release, +static struct watchdog_ops s3c2410wdt_ops = { + .owner = THIS_MODULE, + .start = s3c2410wdt_start, + .stop = s3c2410wdt_stop, + .ping = s3c2410wdt_keepalive, + .set_timeout = s3c2410wdt_set_heartbeat, }; -static struct miscdevice s3c2410wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &s3c2410wdt_fops, +static struct watchdog_device s3c2410_wdd = { + .info = &s3c2410_wdt_ident, + .ops = &s3c2410wdt_ops, }; /* interrupt handler code */ @@ -328,7 +230,7 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param) { dev_info(wdt_dev, "watchdog timer expired (irq)\n"); - s3c2410wdt_keepalive(); + s3c2410wdt_keepalive(&s3c2410_wdd); return IRQ_HANDLED; } @@ -349,14 +251,14 @@ static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb, * the watchdog is running. */ - s3c2410wdt_keepalive(); + s3c2410wdt_keepalive(&s3c2410_wdd); } else if (val == CPUFREQ_POSTCHANGE) { - s3c2410wdt_stop(); + s3c2410wdt_stop(&s3c2410_wdd); - ret = s3c2410wdt_set_heartbeat(tmr_margin); + ret = s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.timeout); if (ret >= 0) - s3c2410wdt_start(); + s3c2410wdt_start(&s3c2410_wdd); else goto err; } @@ -365,7 +267,8 @@ done: return 0; err: - dev_err(wdt_dev, "cannot set new value for timeout %d\n", tmr_margin); + dev_err(wdt_dev, "cannot set new value for timeout %d\n", + s3c2410_wdd.timeout); return ret; } @@ -396,10 +299,6 @@ static inline void s3c2410wdt_cpufreq_deregister(void) } #endif - - -/* device interface */ - static int __devinit s3c2410wdt_probe(struct platform_device *pdev) { struct device *dev; @@ -466,8 +365,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) /* see if we can actually set the requested timer margin, and if * not, try the default value */ - if (s3c2410wdt_set_heartbeat(tmr_margin)) { - started = s3c2410wdt_set_heartbeat( + if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, tmr_margin)) { + started = s3c2410wdt_set_heartbeat(&s3c2410_wdd, CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); if (started == 0) @@ -479,22 +378,21 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) "cannot start\n"); } - ret = misc_register(&s3c2410wdt_miscdev); + ret = watchdog_register_device(&s3c2410_wdd); if (ret) { - dev_err(dev, "cannot register miscdev on minor=%d (%d)\n", - WATCHDOG_MINOR, ret); + dev_err(dev, "cannot register watchdog (%d)\n", ret); goto err_cpufreq; } if (tmr_atboot && started == 0) { dev_info(dev, "starting watchdog timer\n"); - s3c2410wdt_start(); + s3c2410wdt_start(&s3c2410_wdd); } else if (!tmr_atboot) { /* if we're not enabling the watchdog, then ensure it is * disabled if it has been left running from the bootloader * or other source */ - s3c2410wdt_stop(); + s3c2410wdt_stop(&s3c2410_wdd); } /* print out a statement of readiness */ @@ -530,7 +428,7 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) static int __devexit s3c2410wdt_remove(struct platform_device *dev) { - misc_deregister(&s3c2410wdt_miscdev); + watchdog_unregister_device(&s3c2410_wdd); s3c2410wdt_cpufreq_deregister(); @@ -550,7 +448,7 @@ static int __devexit s3c2410wdt_remove(struct platform_device *dev) static void s3c2410wdt_shutdown(struct platform_device *dev) { - s3c2410wdt_stop(); + s3c2410wdt_stop(&s3c2410_wdd); } #ifdef CONFIG_PM @@ -565,7 +463,7 @@ static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state) wtdat_save = readl(wdt_base + S3C2410_WTDAT); /* Note that WTCNT doesn't need to be saved. */ - s3c2410wdt_stop(); + s3c2410wdt_stop(&s3c2410_wdd); return 0; } diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c index f31493e65b38..b01a30e5a663 100644 --- a/drivers/watchdog/sb_wdog.c +++ b/drivers/watchdog/sb_wdog.c @@ -300,7 +300,7 @@ static int __init sbwdog_init(void) * get the resources */ - ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, + ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED, ident.identity, (void *)user_dog); if (ret) { printk(KERN_ERR "%s: failed to request irq 1 - %d\n", @@ -350,7 +350,7 @@ void platform_wd_setup(void) { int ret; - ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, + ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED, "Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0)); if (ret) { printk(KERN_CRIT diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c index 52b63f2f0dac..b2840409ebc7 100644 --- a/drivers/watchdog/sc520_wdt.c +++ b/drivers/watchdog/sc520_wdt.c @@ -398,7 +398,7 @@ static int __init sc520_wdt_init(void) WATCHDOG_TIMEOUT); } - wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2); + wdtmrctl = ioremap(MMCR_BASE + OFFS_WDTMRCTL, 2); if (!wdtmrctl) { printk(KERN_ERR PFX "Unable to remap memory\n"); rc = -ENOMEM; diff --git a/drivers/watchdog/stmp3xxx_wdt.c b/drivers/watchdog/stmp3xxx_wdt.c index b3421fd2cda8..ac2346a452e5 100644 --- a/drivers/watchdog/stmp3xxx_wdt.c +++ b/drivers/watchdog/stmp3xxx_wdt.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/uaccess.h> +#include <linux/module.h> #include <mach/platform.h> #include <mach/regs-rtc.h> diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index e5c91d4404ed..dd5d67548758 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -142,7 +142,7 @@ static void w83627hf_init(void) w83627hf_unselect_wd_register(); } -static void wdt_ctrl(int timeout) +static void wdt_set_time(int timeout) { spin_lock(&io_lock); @@ -158,13 +158,13 @@ static void wdt_ctrl(int timeout) static int wdt_ping(void) { - wdt_ctrl(timeout); + wdt_set_time(timeout); return 0; } static int wdt_disable(void) { - wdt_ctrl(0); + wdt_set_time(0); return 0; } @@ -176,6 +176,24 @@ static int wdt_set_heartbeat(int t) return 0; } +static int wdt_get_time(void) +{ + int timeleft; + + spin_lock(&io_lock); + + w83627hf_select_wd_register(); + + outb_p(0xF6, WDT_EFER); /* Select CRF6 */ + timeleft = inb_p(WDT_EFDR); /* Read Timeout counter to CRF6 */ + + w83627hf_unselect_wd_register(); + + spin_unlock(&io_lock); + + return timeleft; +} + static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -202,7 +220,7 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; int __user *p = argp; - int new_timeout; + int timeval; static const struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, @@ -238,14 +256,17 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) wdt_ping(); break; case WDIOC_SETTIMEOUT: - if (get_user(new_timeout, p)) + if (get_user(timeval, p)) return -EFAULT; - if (wdt_set_heartbeat(new_timeout)) + if (wdt_set_heartbeat(timeval)) return -EINVAL; wdt_ping(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(timeout, p); + case WDIOC_GETTIMELEFT: + timeval = wdt_get_time(); + return put_user(timeval, p); default: return -ENOTTY; } diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c index bb03e151a1d0..d2ef002be96b 100644 --- a/drivers/watchdog/wdt.c +++ b/drivers/watchdog/wdt.c @@ -612,7 +612,7 @@ static int __init wdt_init(void) goto out; } - ret = request_irq(irq, wdt_interrupt, IRQF_DISABLED, "wdt501p", NULL); + ret = request_irq(irq, wdt_interrupt, 0, "wdt501p", NULL); if (ret) { printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); goto outreg; diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c index 172dad6c7693..e0fc3baa9197 100644 --- a/drivers/watchdog/wdt_pci.c +++ b/drivers/watchdog/wdt_pci.c @@ -643,7 +643,7 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev, irq = dev->irq; io = pci_resource_start(dev, 2); - if (request_irq(irq, wdtpci_interrupt, IRQF_DISABLED | IRQF_SHARED, + if (request_irq(irq, wdtpci_interrupt, IRQF_SHARED, "wdt_pci", &wdtpci_miscdev)) { printk(KERN_ERR PFX "IRQ %d is not free\n", irq); goto out_reg; diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 871caea4e1c6..7be38556aed0 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c @@ -12,8 +12,7 @@ #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> +#include <linux/slab.h> #include <linux/platform_device.h> #include <linux/watchdog.h> #include <linux/uaccess.h> @@ -29,19 +28,19 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -static unsigned long wm831x_wdt_users; -static struct miscdevice wm831x_wdt_miscdev; -static int wm831x_wdt_expect_close; -static DEFINE_MUTEX(wdt_mutex); -static struct wm831x *wm831x; -static unsigned int update_gpio; -static unsigned int update_state; +struct wm831x_wdt_drvdata { + struct watchdog_device wdt; + struct wm831x *wm831x; + struct mutex lock; + int update_gpio; + int update_state; +}; /* We can't use the sub-second values here but they're included * for completeness. */ static struct { - int time; /* Seconds */ - u16 val; /* WDOG_TO value */ + unsigned int time; /* Seconds */ + u16 val; /* WDOG_TO value */ } wm831x_wdt_cfgs[] = { { 1, 2 }, { 2, 3 }, @@ -52,32 +51,13 @@ static struct { { 33, 7 }, /* Actually 32.768s so include both, others round down */ }; -static int wm831x_wdt_set_timeout(struct wm831x *wm831x, u16 value) -{ - int ret; - - mutex_lock(&wdt_mutex); - - ret = wm831x_reg_unlock(wm831x); - if (ret == 0) { - ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, - WM831X_WDOG_TO_MASK, value); - wm831x_reg_lock(wm831x); - } else { - dev_err(wm831x->dev, "Failed to unlock security key: %d\n", - ret); - } - - mutex_unlock(&wdt_mutex); - - return ret; -} - -static int wm831x_wdt_start(struct wm831x *wm831x) +static int wm831x_wdt_start(struct watchdog_device *wdt_dev) { + struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); + struct wm831x *wm831x = driver_data->wm831x; int ret; - mutex_lock(&wdt_mutex); + mutex_lock(&driver_data->lock); ret = wm831x_reg_unlock(wm831x); if (ret == 0) { @@ -89,16 +69,18 @@ static int wm831x_wdt_start(struct wm831x *wm831x) ret); } - mutex_unlock(&wdt_mutex); + mutex_unlock(&driver_data->lock); return ret; } -static int wm831x_wdt_stop(struct wm831x *wm831x) +static int wm831x_wdt_stop(struct watchdog_device *wdt_dev) { + struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); + struct wm831x *wm831x = driver_data->wm831x; int ret; - mutex_lock(&wdt_mutex); + mutex_lock(&driver_data->lock); ret = wm831x_reg_unlock(wm831x); if (ret == 0) { @@ -110,26 +92,28 @@ static int wm831x_wdt_stop(struct wm831x *wm831x) ret); } - mutex_unlock(&wdt_mutex); + mutex_unlock(&driver_data->lock); return ret; } -static int wm831x_wdt_kick(struct wm831x *wm831x) +static int wm831x_wdt_ping(struct watchdog_device *wdt_dev) { + struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); + struct wm831x *wm831x = driver_data->wm831x; int ret; u16 reg; - mutex_lock(&wdt_mutex); + mutex_lock(&driver_data->lock); - if (update_gpio) { - gpio_set_value_cansleep(update_gpio, update_state); - update_state = !update_state; + if (driver_data->update_gpio) { + gpio_set_value_cansleep(driver_data->update_gpio, + driver_data->update_state); + driver_data->update_state = !driver_data->update_state; ret = 0; goto out; } - reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); if (!(reg & WM831X_WDOG_RST_SRC)) { @@ -150,182 +134,59 @@ static int wm831x_wdt_kick(struct wm831x *wm831x) } out: - mutex_unlock(&wdt_mutex); + mutex_unlock(&driver_data->lock); return ret; } -static int wm831x_wdt_open(struct inode *inode, struct file *file) +static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev, + unsigned int timeout) { - int ret; - - if (!wm831x) - return -ENODEV; - - if (test_and_set_bit(0, &wm831x_wdt_users)) - return -EBUSY; + struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); + struct wm831x *wm831x = driver_data->wm831x; + int ret, i; - ret = wm831x_wdt_start(wm831x); - if (ret != 0) - return ret; - - return nonseekable_open(inode, file); -} + for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) + if (wm831x_wdt_cfgs[i].time == timeout) + break; + if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) + ret = -EINVAL; -static int wm831x_wdt_release(struct inode *inode, struct file *file) -{ - if (wm831x_wdt_expect_close) - wm831x_wdt_stop(wm831x); - else { - dev_warn(wm831x->dev, "Watchdog device closed uncleanly\n"); - wm831x_wdt_kick(wm831x); + ret = wm831x_reg_unlock(wm831x); + if (ret == 0) { + ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, + WM831X_WDOG_TO_MASK, + wm831x_wdt_cfgs[i].val); + wm831x_reg_lock(wm831x); + } else { + dev_err(wm831x->dev, "Failed to unlock security key: %d\n", + ret); } - clear_bit(0, &wm831x_wdt_users); - - return 0; -} - -static ssize_t wm831x_wdt_write(struct file *file, - const char __user *data, size_t count, - loff_t *ppos) -{ - size_t i; - - if (count) { - wm831x_wdt_kick(wm831x); - - if (!nowayout) { - /* In case it was set long ago */ - wm831x_wdt_expect_close = 0; - - /* scan to see whether or not we got the magic - character */ - for (i = 0; i != count; i++) { - char c; - if (get_user(c, data + i)) - return -EFAULT; - if (c == 'V') - wm831x_wdt_expect_close = 42; - } - } - } - return count; + return ret; } -static const struct watchdog_info ident = { +static const struct watchdog_info wm831x_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .identity = "WM831x Watchdog", }; -static long wm831x_wdt_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret = -ENOTTY, time, i; - void __user *argp = (void __user *)arg; - int __user *p = argp; - u16 reg; - - switch (cmd) { - case WDIOC_GETSUPPORT: - ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; - break; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - ret = put_user(0, p); - break; - - case WDIOC_SETOPTIONS: - { - int options; - - if (get_user(options, p)) - return -EFAULT; - - ret = -EINVAL; - - /* Setting both simultaneously means at least one must fail */ - if (options == WDIOS_DISABLECARD) - ret = wm831x_wdt_start(wm831x); - - if (options == WDIOS_ENABLECARD) - ret = wm831x_wdt_stop(wm831x); - break; - } - - case WDIOC_KEEPALIVE: - ret = wm831x_wdt_kick(wm831x); - break; - - case WDIOC_SETTIMEOUT: - ret = get_user(time, p); - if (ret) - break; - - if (time == 0) { - if (nowayout) - ret = -EINVAL; - else - wm831x_wdt_stop(wm831x); - break; - } - - for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) - if (wm831x_wdt_cfgs[i].time == time) - break; - if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) - ret = -EINVAL; - else - ret = wm831x_wdt_set_timeout(wm831x, - wm831x_wdt_cfgs[i].val); - break; - - case WDIOC_GETTIMEOUT: - reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); - reg &= WM831X_WDOG_TO_MASK; - for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) - if (wm831x_wdt_cfgs[i].val == reg) - break; - if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) { - dev_warn(wm831x->dev, - "Unknown watchdog configuration: %x\n", reg); - ret = -EINVAL; - } else - ret = put_user(wm831x_wdt_cfgs[i].time, p); - - } - - return ret; -} - -static const struct file_operations wm831x_wdt_fops = { +static const struct watchdog_ops wm831x_wdt_ops = { .owner = THIS_MODULE, - .llseek = no_llseek, - .write = wm831x_wdt_write, - .unlocked_ioctl = wm831x_wdt_ioctl, - .open = wm831x_wdt_open, - .release = wm831x_wdt_release, -}; - -static struct miscdevice wm831x_wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &wm831x_wdt_fops, + .start = wm831x_wdt_start, + .stop = wm831x_wdt_stop, + .ping = wm831x_wdt_ping, + .set_timeout = wm831x_wdt_set_timeout, }; static int __devinit wm831x_wdt_probe(struct platform_device *pdev) { + struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *chip_pdata; struct wm831x_watchdog_pdata *pdata; - int reg, ret; - - if (wm831x) { - dev_err(&pdev->dev, "wm831x watchdog already registered\n"); - return -EBUSY; - } - - wm831x = dev_get_drvdata(pdev->dev.parent); + struct wm831x_wdt_drvdata *driver_data; + struct watchdog_device *wm831x_wdt; + int reg, ret, i; ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG); if (ret < 0) { @@ -338,6 +199,36 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) if (reg & WM831X_WDOG_DEBUG) dev_warn(wm831x->dev, "Watchdog is paused\n"); + driver_data = kzalloc(sizeof(*driver_data), GFP_KERNEL); + if (!driver_data) { + dev_err(wm831x->dev, "Unable to alloacate watchdog device\n"); + ret = -ENOMEM; + goto err; + } + + mutex_init(&driver_data->lock); + driver_data->wm831x = wm831x; + + wm831x_wdt = &driver_data->wdt; + + wm831x_wdt->info = &wm831x_wdt_info; + wm831x_wdt->ops = &wm831x_wdt_ops; + watchdog_set_drvdata(wm831x_wdt, driver_data); + + if (nowayout) + wm831x_wdt->status |= WDOG_NO_WAY_OUT; + + reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); + reg &= WM831X_WDOG_TO_MASK; + for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) + if (wm831x_wdt_cfgs[i].val == reg) + break; + if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) + dev_warn(wm831x->dev, + "Unknown watchdog timeout: %x\n", reg); + else + wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time; + /* Apply any configuration */ if (pdev->dev.parent->platform_data) { chip_pdata = pdev->dev.parent->platform_data; @@ -361,7 +252,7 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) dev_err(wm831x->dev, "Failed to request update GPIO: %d\n", ret); - goto err; + goto err_alloc; } ret = gpio_direction_output(pdata->update_gpio, 0); @@ -372,7 +263,7 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) goto err_gpio; } - update_gpio = pdata->update_gpio; + driver_data->update_gpio = pdata->update_gpio; /* Make sure the watchdog takes hardware updates */ reg |= WM831X_WDOG_RST_SRC; @@ -389,33 +280,34 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) } } - wm831x_wdt_miscdev.parent = &pdev->dev; - - ret = misc_register(&wm831x_wdt_miscdev); + ret = watchdog_register_device(&driver_data->wdt); if (ret != 0) { - dev_err(wm831x->dev, "Failed to register miscdev: %d\n", ret); + dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n", + ret); goto err_gpio; } + dev_set_drvdata(&pdev->dev, driver_data); + return 0; err_gpio: - if (update_gpio) { - gpio_free(update_gpio); - update_gpio = 0; - } + if (driver_data->update_gpio) + gpio_free(driver_data->update_gpio); +err_alloc: + kfree(driver_data); err: return ret; } static int __devexit wm831x_wdt_remove(struct platform_device *pdev) { - if (update_gpio) { - gpio_free(update_gpio); - update_gpio = 0; - } + struct wm831x_wdt_drvdata *driver_data = dev_get_drvdata(&pdev->dev); + + watchdog_unregister_device(&driver_data->wdt); - misc_deregister(&wm831x_wdt_miscdev); + if (driver_data->update_gpio) + gpio_free(driver_data->update_gpio); return 0; } diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 5876e1ae6c2d..a767884a6c7a 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -39,6 +39,7 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/errno.h> +#include <linux/module.h> #include <linux/mm.h> #include <linux/bootmem.h> #include <linux/pagemap.h> @@ -93,8 +94,8 @@ static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)]; #define inc_totalhigh_pages() (totalhigh_pages++) #define dec_totalhigh_pages() (totalhigh_pages--) #else -#define inc_totalhigh_pages() do {} while(0) -#define dec_totalhigh_pages() do {} while(0) +#define inc_totalhigh_pages() do {} while (0) +#define dec_totalhigh_pages() do {} while (0) #endif /* List of ballooned pages, threaded through the mem_map array. */ @@ -154,8 +155,7 @@ static struct page *balloon_retrieve(bool prefer_highmem) if (PageHighMem(page)) { balloon_stats.balloon_high--; inc_totalhigh_pages(); - } - else + } else balloon_stats.balloon_low--; totalram_pages++; @@ -422,7 +422,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) (unsigned long)__va(pfn << PAGE_SHIFT), __pte_ma(0), 0); BUG_ON(ret); - } + } } @@ -507,7 +507,7 @@ EXPORT_SYMBOL_GPL(balloon_set_new_target); int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem) { int pgno = 0; - struct page* page; + struct page *page; mutex_lock(&balloon_mutex); while (pgno < nr_pages) { page = balloon_retrieve(highmem); @@ -540,7 +540,7 @@ EXPORT_SYMBOL(alloc_xenballooned_pages); * @nr_pages: Number of pages * @pages: pages to return */ -void free_xenballooned_pages(int nr_pages, struct page** pages) +void free_xenballooned_pages(int nr_pages, struct page **pages) { int i; diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0eb8a57cc808..6e075cdd0c6b 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -85,8 +85,7 @@ enum xen_irq_type { * IPI - IPI vector * EVTCHN - */ -struct irq_info -{ +struct irq_info { struct list_head list; enum xen_irq_type type; /* type */ unsigned irq; @@ -282,9 +281,9 @@ static inline unsigned long active_evtchns(unsigned int cpu, struct shared_info *sh, unsigned int idx) { - return (sh->evtchn_pending[idx] & + return sh->evtchn_pending[idx] & per_cpu(cpu_evtchn_mask, cpu)[idx] & - ~sh->evtchn_mask[idx]); + ~sh->evtchn_mask[idx]; } static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) @@ -1180,7 +1179,7 @@ static void __xen_evtchn_do_upcall(void) int cpu = get_cpu(); struct shared_info *s = HYPERVISOR_shared_info; struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); - unsigned count; + unsigned count; do { unsigned long pending_words; diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 880798aae2f2..39871326afa2 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -193,9 +193,8 @@ static void gntdev_put_map(struct grant_map *map) atomic_sub(map->count, &pages_mapped); - if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) { + if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) notify_remote_via_evtchn(map->notify.event); - } if (map->pages) { if (!use_ptemod) diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 8c71ab801756..bf1c094f4ebf 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -193,7 +193,7 @@ int gnttab_query_foreign_access(grant_ref_t ref) nflags = shared[ref].flags; - return (nflags & (GTF_reading|GTF_writing)); + return nflags & (GTF_reading|GTF_writing); } EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 0b5366b5be20..ce4fa0831860 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -9,6 +9,7 @@ #include <linux/stop_machine.h> #include <linux/freezer.h> #include <linux/syscore_ops.h> +#include <linux/export.h> #include <xen/xen.h> #include <xen/xenbus.h> diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c index 66057075d6e2..b84bf0b6cc34 100644 --- a/drivers/xen/pci.c +++ b/drivers/xen/pci.c @@ -116,7 +116,7 @@ static int xen_add_device(struct device *dev) &manage_pci_ext); } else { struct physdev_manage_pci manage_pci = { - .bus = pci_dev->bus->number, + .bus = pci_dev->bus->number, .devfn = pci_dev->devfn, }; diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index c984768d98ca..8e964b91c447 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -35,6 +35,7 @@ #include <linux/bootmem.h> #include <linux/dma-mapping.h> +#include <linux/export.h> #include <xen/swiotlb-xen.h> #include <xen/page.h> #include <xen/xen-ops.h> diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c index 5c9dc43c1e94..9cc2259c9992 100644 --- a/drivers/xen/xen-balloon.c +++ b/drivers/xen/xen-balloon.c @@ -50,11 +50,6 @@ static struct sys_device balloon_sysdev; static int register_balloon(struct sys_device *sysdev); -static struct xenbus_watch target_watch = -{ - .node = "memory/target" -}; - /* React to a change in the target key */ static void watch_target(struct xenbus_watch *watch, const char **vec, unsigned int len) @@ -73,6 +68,11 @@ static void watch_target(struct xenbus_watch *watch, */ balloon_set_new_target(new_target >> (PAGE_SHIFT - 10)); } +static struct xenbus_watch target_watch = { + .node = "memory/target", + .callback = watch_target, +}; + static int balloon_init_watcher(struct notifier_block *notifier, unsigned long event, @@ -87,7 +87,9 @@ static int balloon_init_watcher(struct notifier_block *notifier, return NOTIFY_DONE; } -static struct notifier_block xenstore_notifier; +static struct notifier_block xenstore_notifier = { + .notifier_call = balloon_init_watcher, +}; static int __init balloon_init(void) { @@ -100,9 +102,6 @@ static int __init balloon_init(void) register_xen_selfballooning(&balloon_sysdev); - target_watch.callback = watch_target; - xenstore_notifier.notifier_call = balloon_init_watcher; - register_xenstore_notifier(&xenstore_notifier); return 0; diff --git a/drivers/xen/xen-pciback/conf_space.c b/drivers/xen/xen-pciback/conf_space.c index 444345afbd5c..52fed16d8701 100644 --- a/drivers/xen/xen-pciback/conf_space.c +++ b/drivers/xen/xen-pciback/conf_space.c @@ -10,6 +10,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/pci.h> #include "pciback.h" #include "conf_space.h" diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index cdacf923e073..81c3ce6b8bbe 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <asm/xen/hypervisor.h> #include <xen/interface/xen.h> #include <xen/interface/event_channel.h> @@ -443,7 +444,7 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) *vaddr = NULL; - area = xen_alloc_vm_area(PAGE_SIZE); + area = alloc_vm_area(PAGE_SIZE); if (!area) return -ENOMEM; @@ -453,7 +454,7 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) BUG(); if (op.status != GNTST_okay) { - xen_free_vm_area(area); + free_vm_area(area); xenbus_dev_fatal(dev, op.status, "mapping in shared page %d from domain %d", gnt_ref, dev->otherend_id); @@ -552,7 +553,7 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) BUG(); if (op.status == GNTST_okay) - xen_free_vm_area(area); + free_vm_area(area); else xenbus_dev_error(dev, op.status, "unmapping page at handle %d error %d", diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index cef9b0bf63d5..1b178c6e8937 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -46,6 +46,7 @@ #include <linux/mutex.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/module.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -309,8 +310,7 @@ void xenbus_unregister_driver(struct xenbus_driver *drv) } EXPORT_SYMBOL_GPL(xenbus_unregister_driver); -struct xb_find_info -{ +struct xb_find_info { struct xenbus_device *dev; const char *nodename; }; @@ -639,7 +639,7 @@ int xenbus_dev_cancel(struct device *dev) EXPORT_SYMBOL_GPL(xenbus_dev_cancel); /* A flag to determine if xenstored is 'ready' (i.e. has started) */ -int xenstored_ready = 0; +int xenstored_ready; int register_xenstore_notifier(struct notifier_block *nb) @@ -770,7 +770,7 @@ static int __init xenbus_init(void) proc_mkdir("xen", NULL); #endif - out_error: +out_error: return err; } diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h index b814935378c7..9b1de4e34c64 100644 --- a/drivers/xen/xenbus/xenbus_probe.h +++ b/drivers/xen/xenbus/xenbus_probe.h @@ -36,8 +36,7 @@ #define XEN_BUS_ID_SIZE 20 -struct xen_bus_type -{ +struct xen_bus_type { char *root; unsigned int levels; int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename); diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c index 32417b5064fd..c3c7cd195c11 100644 --- a/drivers/xen/xenbus/xenbus_probe_backend.c +++ b/drivers/xen/xenbus/xenbus_probe_backend.c @@ -42,6 +42,7 @@ #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/notifier.h> +#include <linux/export.h> #include <asm/page.h> #include <asm/pgtable.h> diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 540587e18a94..2f73195512b4 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -13,6 +13,7 @@ #include <linux/kthread.h> #include <linux/mutex.h> #include <linux/io.h> +#include <linux/module.h> #include <asm/page.h> #include <asm/pgtable.h> diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c index e0c84725d3e9..988880dcee75 100644 --- a/drivers/zorro/proc.c +++ b/drivers/zorro/proc.c @@ -13,6 +13,7 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/init.h> +#include <linux/export.h> #include <asm/uaccess.h> #include <asm/amigahw.h> #include <asm/setup.h> |