diff options
author | Jody McIntyre <scjody@modernduck.com> | 2005-12-05 15:52:41 -0500 |
---|---|---|
committer | Jody McIntyre <scjody@modernduck.com> | 2005-12-05 15:52:41 -0500 |
commit | c4fc108a8275f5eb77c9859725643a6870d20ef6 (patch) | |
tree | de7ce4af8e49ad2504fc270594124ec8ec874857 /drivers | |
parent | 741854e4f9a23421e194df8d846899172ff393d6 (diff) | |
parent | e4f5c82a92c2a546a16af1614114eec19120e40a (diff) |
Merge with http://kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Diffstat (limited to 'drivers')
102 files changed, 1259 insertions, 1686 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index fac1e160309..ea410b6b764 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -5,7 +5,7 @@ # Rewritten to use lists instead of if-statements. # -obj-$(CONFIG_PCI) += pci/ usb/ +obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PARISC) += parisc/ obj-$(CONFIG_RAPIDIO) += rapidio/ obj-y += video/ @@ -49,6 +49,7 @@ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/ obj-$(CONFIG_PARIDE) += block/paride/ obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_USB) += usb/ +obj-$(CONFIG_PCI) += usb/ obj-$(CONFIG_USB_GADGET) += usb/gadget/ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_INPUT) += input/ diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index fe1e8126fba..fce21c25752 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -197,7 +197,6 @@ config ACPI_ASUS config ACPI_IBM tristate "IBM ThinkPad Laptop Extras" depends on X86 - default y ---help--- This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds support for Fn-Fx key combinations, Bluetooth control, video diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index a18243488c6..5984b4f6715 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -16,7 +16,7 @@ EXTRA_CFLAGS += $(ACPI_CFLAGS) # ACPI Boot-Time Table Parsing # obj-y += tables.o -obj-y += blacklist.o +obj-$(CONFIG_X86) += blacklist.o # # ACPI Core Subsystem (Interpreter) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 42179256264..0c561c571f2 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -543,6 +543,8 @@ static int acpi_processor_get_info(struct acpi_processor *pr) return_VALUE(0); } +static void *processor_device_array[NR_CPUS]; + static int acpi_processor_start(struct acpi_device *device) { int result = 0; @@ -561,6 +563,19 @@ static int acpi_processor_start(struct acpi_device *device) BUG_ON((pr->id >= NR_CPUS) || (pr->id < 0)); + /* + * Buggy BIOS check + * ACPI id of processors can be reported wrongly by the BIOS. + * Don't trust it blindly + */ + if (processor_device_array[pr->id] != NULL && + processor_device_array[pr->id] != (void *)device) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "BIOS reporting wrong ACPI id" + "for the processor\n")); + return_VALUE(-ENODEV); + } + processor_device_array[pr->id] = (void *)device; + processors[pr->id] = pr; result = acpi_processor_add_fs(device); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 70d8a6ec092..5f51057518b 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -169,15 +169,11 @@ acpi_processor_power_activate(struct acpi_processor *pr, static void acpi_safe_halt(void) { - int polling = test_thread_flag(TIF_POLLING_NRFLAG); - if (polling) { - clear_thread_flag(TIF_POLLING_NRFLAG); - smp_mb__after_clear_bit(); - } + clear_thread_flag(TIF_POLLING_NRFLAG); + smp_mb__after_clear_bit(); if (!need_resched()) safe_halt(); - if (polling) - set_thread_flag(TIF_POLLING_NRFLAG); + set_thread_flag(TIF_POLLING_NRFLAG); } static atomic_t c3_cpu_count; @@ -280,11 +276,31 @@ static void acpi_processor_idle(void) cx->usage++; +#ifdef CONFIG_HOTPLUG_CPU + /* + * Check for P_LVL2_UP flag before entering C2 and above on + * an SMP system. We do it here instead of doing it at _CST/P_LVL + * detection phase, to work cleanly with logical CPU hotplug. + */ + if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && + !pr->flags.has_cst && acpi_fadt.plvl2_up) + cx->type = ACPI_STATE_C1; +#endif /* * Sleep: * ------ * Invoke the current Cx state to put the processor to sleep. */ + if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { + clear_thread_flag(TIF_POLLING_NRFLAG); + smp_mb__after_clear_bit(); + if (need_resched()) { + set_thread_flag(TIF_POLLING_NRFLAG); + local_irq_enable(); + return; + } + } + switch (cx->type) { case ACPI_STATE_C1: @@ -317,6 +333,7 @@ static void acpi_processor_idle(void) t2 = inl(acpi_fadt.xpm_tmr_blk.address); /* Re-enable interrupts */ local_irq_enable(); + set_thread_flag(TIF_POLLING_NRFLAG); /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; @@ -356,6 +373,7 @@ static void acpi_processor_idle(void) /* Re-enable interrupts */ local_irq_enable(); + set_thread_flag(TIF_POLLING_NRFLAG); /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; @@ -534,6 +552,15 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) pr->power.states[ACPI_STATE_C0].valid = 1; pr->power.states[ACPI_STATE_C1].valid = 1; +#ifndef CONFIG_HOTPLUG_CPU + /* + * Check for P_LVL2_UP flag before entering C2 and above on + * an SMP system. + */ + if ((num_online_cpus() > 1) && acpi_fadt.plvl2_up) + return_VALUE(-ENODEV); +#endif + /* determine C2 and C3 address from pblk */ pr->power.states[ACPI_STATE_C2].address = pr->pblk + 4; pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5; @@ -690,7 +717,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) /* Validate number of power states discovered */ if (pr->power.count < 2) - status = -ENODEV; + status = -EFAULT; end: acpi_os_free(buffer.pointer); @@ -841,11 +868,11 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) * this function */ result = acpi_processor_get_power_info_cst(pr); - if ((result) || (acpi_processor_power_verify(pr) < 2)) { + if (result == -ENODEV) result = acpi_processor_get_power_info_fadt(pr); - if ((result) || (acpi_processor_power_verify(pr) < 2)) - result = acpi_processor_get_power_info_default_c1(pr); - } + + if ((result) || (acpi_processor_power_verify(pr) < 2)) + result = acpi_processor_get_power_info_default_c1(pr); /* * Set Default Policy diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 37528c3b64b..f3758401532 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -101,9 +101,7 @@ static unsigned int acpi_thermal_cpufreq_is_init = 0; static int cpu_has_cpufreq(unsigned int cpu) { struct cpufreq_policy policy; - if (!acpi_thermal_cpufreq_is_init) - return -ENODEV; - if (!cpufreq_get_policy(&policy, cpu)) + if (!acpi_thermal_cpufreq_is_init || cpufreq_get_policy(&policy, cpu)) return -ENODEV; return 0; } @@ -127,13 +125,13 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu) if (!cpu_has_cpufreq(cpu)) return -ENODEV; - if (cpufreq_thermal_reduction_pctg[cpu] >= 20) { + if (cpufreq_thermal_reduction_pctg[cpu] > 20) cpufreq_thermal_reduction_pctg[cpu] -= 20; - cpufreq_update_policy(cpu); - return 0; - } - - return -ERANGE; + else + cpufreq_thermal_reduction_pctg[cpu] = 0; + cpufreq_update_policy(cpu); + /* We reached max freq again and can leave passive mode */ + return !cpufreq_thermal_reduction_pctg[cpu]; } static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, @@ -200,7 +198,7 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type) int result = 0; struct acpi_processor *pr = NULL; struct acpi_device *device = NULL; - int tx = 0; + int tx = 0, max_tx_px = 0; ACPI_FUNCTION_TRACE("acpi_processor_set_thermal_limit"); @@ -259,19 +257,27 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type) /* if going down: T-states first, P-states later */ if (pr->flags.throttling) { - if (tx == 0) + if (tx == 0) { + max_tx_px = 1; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "At minimum throttling state\n")); - else { + } else { tx--; goto end; } } result = acpi_thermal_cpufreq_decrease(pr->id); - if (result == -ERANGE) + if (result) { + /* + * We only could get -ERANGE, 1 or 0. + * In the first two cases we reached max freq again. + */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "At minimum performance state\n")); + max_tx_px = 1; + } else + max_tx_px = 0; break; } @@ -290,8 +296,10 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type) pr->limit.thermal.px, pr->limit.thermal.tx)); } else result = 0; - - return_VALUE(result); + if (max_tx_px) + return_VALUE(1); + else + return_VALUE(result); } int acpi_processor_get_limit_info(struct acpi_processor *pr) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 23e2c6968a1..31218e1d2a1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1110,7 +1110,7 @@ acpi_add_single_object(struct acpi_device **child, * * TBD: Assumes LDM provides driver hot-plug capability. */ - result = acpi_bus_find_driver(device); + acpi_bus_find_driver(device); end: if (!result) diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index a24847c08f7..19f3ea48475 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -72,7 +72,7 @@ #define _COMPONENT ACPI_THERMAL_COMPONENT ACPI_MODULE_NAME("acpi_thermal") - MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME); MODULE_LICENSE("GPL"); @@ -517,9 +517,9 @@ static int acpi_thermal_hot(struct acpi_thermal *tz) return_VALUE(0); } -static int acpi_thermal_passive(struct acpi_thermal *tz) +static void acpi_thermal_passive(struct acpi_thermal *tz) { - int result = 0; + int result = 1; struct acpi_thermal_passive *passive = NULL; int trend = 0; int i = 0; @@ -527,7 +527,7 @@ static int acpi_thermal_passive(struct acpi_thermal *tz) ACPI_FUNCTION_TRACE("acpi_thermal_passive"); if (!tz || !tz->trips.passive.flags.valid) - return_VALUE(-EINVAL); + return; passive = &(tz->trips.passive); @@ -547,7 +547,7 @@ static int acpi_thermal_passive(struct acpi_thermal *tz) trend, passive->tc1, tz->temperature, tz->last_temperature, passive->tc2, tz->temperature, passive->temperature)); - tz->trips.passive.flags.enabled = 1; + passive->flags.enabled = 1; /* Heating up? */ if (trend > 0) for (i = 0; i < passive->devices.count; i++) @@ -556,12 +556,32 @@ static int acpi_thermal_passive(struct acpi_thermal *tz) handles[i], ACPI_PROCESSOR_LIMIT_INCREMENT); /* Cooling off? */ - else if (trend < 0) + else if (trend < 0) { for (i = 0; i < passive->devices.count; i++) - acpi_processor_set_thermal_limit(passive-> - devices. - handles[i], - ACPI_PROCESSOR_LIMIT_DECREMENT); + /* + * assume that we are on highest + * freq/lowest thrott and can leave + * passive mode, even in error case + */ + if (!acpi_processor_set_thermal_limit + (passive->devices.handles[i], + ACPI_PROCESSOR_LIMIT_DECREMENT)) + result = 0; + /* + * Leave cooling mode, even if the temp might + * higher than trip point This is because some + * machines might have long thermal polling + * frequencies (tsp) defined. We will fall back + * into passive mode in next cycle (probably quicker) + */ + if (result) { + passive->flags.enabled = 0; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Disabling passive cooling, still above threshold," + " but we are cooling down\n")); + } + } + return; } /* @@ -571,23 +591,21 @@ static int acpi_thermal_passive(struct acpi_thermal *tz) * and avoid thrashing around the passive trip point. Note that we * assume symmetry. */ - else if (tz->trips.passive.flags.enabled) { - for (i = 0; i < passive->devices.count; i++) - result = - acpi_processor_set_thermal_limit(passive->devices. - handles[i], - ACPI_PROCESSOR_LIMIT_DECREMENT); - if (result == 1) { - tz->trips.passive.flags.enabled = 0; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Disabling passive cooling (zone is cool)\n")); - } + if (!passive->flags.enabled) + return; + for (i = 0; i < passive->devices.count; i++) + if (!acpi_processor_set_thermal_limit + (passive->devices.handles[i], + ACPI_PROCESSOR_LIMIT_DECREMENT)) + result = 0; + if (result) { + passive->flags.enabled = 0; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Disabling passive cooling (zone is cool)\n")); } - - return_VALUE(0); } -static int acpi_thermal_active(struct acpi_thermal *tz) +static void acpi_thermal_active(struct acpi_thermal *tz) { int result = 0; struct acpi_thermal_active *active = NULL; @@ -598,74 +616,66 @@ static int acpi_thermal_active(struct acpi_thermal *tz) ACPI_FUNCTION_TRACE("acpi_thermal_active"); if (!tz) - return_VALUE(-EINVAL); + return; for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - active = &(tz->trips.active[i]); if (!active || !active->flags.valid) break; - - /* - * Above Threshold? - * ---------------- - * If not already enabled, turn ON all cooling devices - * associated with this active threshold. - */ if (tz->temperature >= active->temperature) { + /* + * Above Threshold? + * ---------------- + * If not already enabled, turn ON all cooling devices + * associated with this active threshold. + */ if (active->temperature > maxtemp) - tz->state.active_index = i, maxtemp = - active->temperature; - if (!active->flags.enabled) { - for (j = 0; j < active->devices.count; j++) { - result = - acpi_bus_set_power(active->devices. - handles[j], - ACPI_STATE_D0); - if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Unable to turn cooling device [%p] 'on'\n", - active-> - devices. - handles[j])); - continue; - } - active->flags.enabled = 1; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Cooling device [%p] now 'on'\n", - active->devices. - handles[j])); - } - } - } - /* - * Below Threshold? - * ---------------- - * Turn OFF all cooling devices associated with this - * threshold. - */ - else if (active->flags.enabled) { + tz->state.active_index = i; + maxtemp = active->temperature; + if (active->flags.enabled) + continue; for (j = 0; j < active->devices.count; j++) { result = acpi_bus_set_power(active->devices. handles[j], - ACPI_STATE_D3); + ACPI_STATE_D0); if (result) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Unable to turn cooling device [%p] 'off'\n", + "Unable to turn cooling device [%p] 'on'\n", active->devices. handles[j])); continue; } - active->flags.enabled = 0; + active->flags.enabled = 1; ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Cooling device [%p] now 'off'\n", + "Cooling device [%p] now 'on'\n", active->devices.handles[j])); } + continue; + } + if (!active->flags.enabled) + continue; + /* + * Below Threshold? + * ---------------- + * Turn OFF all cooling devices associated with this + * threshold. + */ + for (j = 0; j < active->devices.count; j++) { + result = acpi_bus_set_power(active->devices.handles[j], + ACPI_STATE_D3); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Unable to turn cooling device [%p] 'off'\n", + active->devices.handles[j])); + continue; + } + active->flags.enabled = 0; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Cooling device [%p] now 'off'\n", + active->devices.handles[j])); } } - - return_VALUE(0); } static void acpi_thermal_check(void *context); @@ -744,15 +754,12 @@ static void acpi_thermal_check(void *data) * Again, separated from the above two to allow independent policy * decisions. */ - if (tz->trips.critical.flags.enabled) - tz->state.critical = 1; - if (tz->trips.hot.flags.enabled) - tz->state.hot = 1; - if (tz->trips.passive.flags.enabled) - tz->state.passive = 1; + tz->state.critical = tz->trips.critical.flags.enabled; + tz->state.hot = tz->trips.hot.flags.enabled; + tz->state.passive = tz->trips.passive.flags.enabled; + tz->state.active = 0; for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) - if (tz->trips.active[i].flags.enabled) - tz->state.active = 1; + tz->state.active |= tz->trips.active[i].flags.enabled; /* * Calculate Sleep Time diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index f051b151580..d10668f1469 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -812,7 +812,7 @@ acpi_video_device_write_brightness(struct file *file, ACPI_FUNCTION_TRACE("acpi_video_device_write_brightness"); - if (!dev || count + 1 > sizeof str) + if (!dev || !dev->brightness || count + 1 > sizeof str) return_VALUE(-EINVAL); if (copy_from_user(str, buffer, count)) diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c index bdd168d88f4..bd958d69a2a 100644 --- a/drivers/char/drm/drm_context.c +++ b/drivers/char/drm/drm_context.c @@ -432,7 +432,10 @@ int drm_addctx(struct inode *inode, struct file *filp, if (ctx.handle != DRM_KERNEL_CONTEXT) { if (dev->driver->context_ctor) - dev->driver->context_ctor(dev, ctx.handle); + if (!dev->driver->context_ctor(dev, ctx.handle)) { + DRM_DEBUG( "Running out of ctxs or memory.\n"); + return -ENOMEM; + } } ctx_entry = drm_alloc(sizeof(*ctx_entry), DRM_MEM_CTXLIST); diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 4be59dbb78c..1ba07263036 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -193,6 +193,7 @@ static const u8 W83792D_REG_LEVELS[3][4] = { 0xE2 } /* (bit3-0) SmartFanII: Fan3 Level 3 */ }; +#define W83792D_REG_GPIO_EN 0x1A #define W83792D_REG_CONFIG 0x40 #define W83792D_REG_VID_FANDIV 0x47 #define W83792D_REG_CHIPID 0x49 @@ -257,7 +258,7 @@ DIV_TO_REG(long val) { int i; val = SENSORS_LIMIT(val, 1, 128) >> 1; - for (i = 0; i < 6; i++) { + for (i = 0; i < 7; i++) { if (val == 0) break; val >>= 1; @@ -1282,8 +1283,8 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) w83792d_init_client(new_client); /* A few vars need to be filled upon startup */ - for (i = 1; i <= 7; i++) { - data->fan_min[i - 1] = w83792d_read_value(new_client, + for (i = 0; i < 7; i++) { + data->fan_min[i] = w83792d_read_value(new_client, W83792D_REG_FAN_MIN[i]); } @@ -1306,10 +1307,20 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file_fan(new_client, 1); device_create_file_fan(new_client, 2); device_create_file_fan(new_client, 3); - device_create_file_fan(new_client, 4); - device_create_file_fan(new_client, 5); - device_create_file_fan(new_client, 6); - device_create_file_fan(new_client, 7); + + /* Read GPIO enable register to check if pins for fan 4,5 are used as + GPIO */ + val1 = w83792d_read_value(new_client, W83792D_REG_GPIO_EN); + if (!(val1 & 0x40)) + device_create_file_fan(new_client, 4); + if (!(val1 & 0x20)) + device_create_file_fan(new_client, 5); + + val1 = w83792d_read_value(new_client, W83792D_REG_PIN); + if (val1 & 0x40) + device_create_file_fan(new_client, 6); + if (val1 & 0x04) + device_create_file_fan(new_client, 7); device_create_file_temp1(new_client); /* Temp1 */ device_create_file_temp_add(new_client, 2); /* Temp2 */ diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index e73f81c2238..eb7f52537cc 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -310,7 +310,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, u8 method; __be64 *tid; int ret, length, hdr_len, copy_offset; - int rmpp_active = 0; + int rmpp_active, has_rmpp_header; if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR) return -EINVAL; @@ -360,28 +360,31 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, } rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data; - if (ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE) { - /* RMPP active */ - if (!agent->rmpp_version) { - ret = -EINVAL; - goto err_ah; - } - - /* Validate that the management class can support RMPP */ - if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) { - hdr_len = IB_MGMT_SA_HDR; - } else if ((rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && - (rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) { - hdr_len = IB_MGMT_VENDOR_HDR; - } else { - ret = -EINVAL; - goto err_ah; - } - rmpp_active = 1; + if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) { + hdr_len = IB_MGMT_SA_HDR; copy_offset = IB_MGMT_RMPP_HDR; + has_rmpp_header = 1; + } else if (rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START && + rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END) { + hdr_len = IB_MGMT_VENDOR_HDR; + copy_offset = IB_MGMT_RMPP_HDR; + has_rmpp_header = 1; } else { hdr_len = IB_MGMT_MAD_HDR; copy_offset = IB_MGMT_MAD_HDR; + has_rmpp_header = 0; + } + + if (has_rmpp_header) + rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & + IB_MGMT_RMPP_FLAG_ACTIVE; + else + rmpp_active = 0; + + /* Validate that the management class can support RMPP */ + if (rmpp_active && !agent->rmpp_version) { + ret = -EINVAL; + goto err_ah; } packet->msg = ib_create_send_mad(agent, diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index ecb83012786..7114e3fbab0 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -105,12 +105,23 @@ struct ib_uverbs_event { u32 *counter; }; +struct ib_uverbs_mcast_entry { + struct list_head list; + union ib_gid gid; + u16 lid; +}; + struct ib_uevent_object { struct ib_uobject uobject; struct list_head event_list; u32 events_reported; }; +struct ib_uqp_object { + struct ib_uevent_object uevent; + struct list_head mcast_list; +}; + struct ib_ucq_object { struct ib_uobject uobject; struct ib_uverbs_file *uverbs_file; diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index ed45da892b1..a57d021d435 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -815,7 +815,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, struct ib_uverbs_create_qp cmd; struct ib_uverbs_create_qp_resp resp; struct ib_udata udata; - struct ib_uevent_object *uobj; + struct ib_uqp_object *uobj; struct ib_pd *pd; struct ib_cq *scq, *rcq; struct ib_srq *srq; @@ -866,10 +866,11 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, attr.cap.max_recv_sge = cmd.max_recv_sge; attr.cap.max_inline_data = cmd.max_inline_data; - uobj->uobject.user_handle = cmd.user_handle; - uobj->uobject.context = file->ucontext; - uobj->events_reported = 0; - INIT_LIST_HEAD(&uobj->event_list); + uobj->uevent.uobject.user_handle = cmd.user_handle; + uobj->uevent.uobject.context = file->ucontext; + uobj->uevent.events_reported = 0; + INIT_LIST_HEAD(&uobj->uevent.event_list); + INIT_LIST_HEAD(&uobj->mcast_list); qp = pd->device->create_qp(pd, &attr, &udata); if (IS_ERR(qp)) { @@ -882,7 +883,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, qp->send_cq = attr.send_cq; qp->recv_cq = attr.recv_cq; qp->srq = attr.srq; - qp->uobject = &uobj->uobject; + qp->uobject = &uobj->uevent.uobject; qp->event_handler = attr.event_handler; qp->qp_context = attr.qp_context; qp->qp_type = attr.qp_type; @@ -901,14 +902,14 @@ retry: goto err_destroy; } - ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uobject.id); + ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uevent.uobject.id); if (ret == -EAGAIN) goto retry; if (ret) goto err_destroy; - resp.qp_handle = uobj->uobject.id; + resp.qp_handle = uobj->uevent.uobject.id; resp.max_recv_sge = attr.cap.max_recv_sge; resp.max_send_sge = attr.cap.max_send_sge; resp.max_recv_wr = attr.cap.max_recv_wr; @@ -922,7 +923,7 @@ retry: } down(&file->mutex); - list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); + list_add_tail(&uobj->uevent.uobject.list, &file->ucontext->qp_list); up(&file->mutex); up(&ib_uverbs_idr_mutex); @@ -930,7 +931,7 @@ retry: return in_len; err_idr: - idr_remove(&ib_uverbs_qp_idr, uobj->uobject.id); + idr_remove(&ib_uverbs_qp_idr, uobj->uevent.uobject.id); err_destroy: ib_destroy_qp(qp); @@ -1032,7 +1033,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, struct ib_uverbs_destroy_qp cmd; struct ib_uverbs_destroy_qp_resp resp; struct ib_qp *qp; - struct ib_uevent_object *uobj; + struct ib_uqp_object *uobj; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) @@ -1046,7 +1047,12 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, if (!qp || qp->uobject->context != file->ucontext) goto out; - uobj = container_of(qp->uobject, struct ib_uevent_object, uobject); + uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); + + if (!list_empty(&uobj->mcast_list)) { + ret = -EBUSY; + goto out; + } ret = ib_destroy_qp(qp); if (ret) @@ -1055,12 +1061,12 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); down(&file->mutex); - list_del(&uobj->uobject.list); + list_del(&uobj->uevent.uobject.list); up(&file->mutex); - ib_uverbs_release_uevent(file, uobj); + ib_uverbs_release_uevent(file, &uobj->uevent); - resp.events_reported = uobj->events_reported; + resp.events_reported = uobj->uevent.events_reported; kfree(uobj); @@ -1542,6 +1548,8 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, { struct ib_uverbs_attach_mcast cmd; struct ib_qp *qp; + struct ib_uqp_object *uobj; + struct ib_uverbs_mcast_entry *mcast; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) @@ -1550,9 +1558,36 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, down(&ib_uverbs_idr_mutex); qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); - if (qp && qp->uobject->context == file->ucontext) - ret = ib_attach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); + if (!qp || qp->uobject->context != file->ucontext) + goto out; + + uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); + + list_for_each_entry(mcast, &uobj->mcast_list, list) + if (cmd.mlid == mcast->lid && + !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { + ret = 0; + goto out; + } + mcast = kmalloc(sizeof *mcast, GFP_KERNEL); + if (!mcast) { + ret = -ENOMEM; + goto out; + } + + mcast->lid = cmd.mlid; + memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw); + + ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid); + if (!ret) { + uobj = container_of(qp->uobject, struct ib_uqp_object, + uevent.uobject); + list_add_tail(&mcast->list, &uobj->mcast_list); + } else + kfree(mcast); + +out: up(&ib_uverbs_idr_mutex); return ret ? ret : in_len; @@ -1563,7 +1598,9 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, int out_len) { struct ib_uverbs_detach_mcast cmd; + struct ib_uqp_object *uobj; struct ib_qp *qp; + struct ib_uverbs_mcast_entry *mcast; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) @@ -1572,9 +1609,24 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, down(&ib_uverbs_idr_mutex); qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); - if (qp && qp->uobject->context == file->ucontext) - ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); + if (!qp || qp->uobject->context != file->ucontext) + goto out; + + ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); + if (ret) + goto out; + uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); + + list_for_each_entry(mcast, &uobj->mcast_list, list) + if (cmd.mlid == mcast->lid && + !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { + list_del(&mcast->list); + kfree(mcast); + break; + } + +out: up(&ib_uverbs_idr_mutex); return ret ? ret : in_len; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index de6581d7cb8..81737bd6fae 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -160,6 +160,18 @@ void ib_uverbs_release_uevent(struct ib_uverbs_file *file, spin_unlock_irq(&file->async_file->lock); } +static void ib_uverbs_detach_umcast(struct ib_qp *qp, + struct ib_uqp_object *uobj) +{ + struct ib_uverbs_mcast_entry *mcast, *tmp; + + list_for_each_entry_safe(mcast, tmp, &uobj->mcast_list, list) { + ib_detach_mcast(qp, &mcast->gid, mcast->lid); + list_del(&mcast->list); + kfree(mcast); + } +} + static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, struct ib_ucontext *context) { @@ -180,13 +192,14 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); - struct ib_uevent_object *uevent = - container_of(uobj, struct ib_uevent_object, uobject); + struct ib_uqp_object *uqp = + container_of(uobj, struct ib_uqp_object, uevent.uobject); idr_remove(&ib_uverbs_qp_idr, uobj->id); + ib_uverbs_detach_umcast(qp, uqp); ib_destroy_qp(qp); list_del(&uobj->list); - ib_uverbs_release_uevent(file, uevent); - kfree(uevent); + ib_uverbs_release_uevent(file, &uqp->uevent); + kfree(uqp); } list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index dd4e13303e9..7450550db73 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -871,7 +871,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); mthca_wq_init(&qp->sq); + qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); + mthca_wq_init(&qp->rq); + qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1); if (mthca_is_memfree(dev)) { *qp->sq.db = 0; @@ -1819,6 +1822,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, { struct mthca_dev *dev = to_mdev(ibqp->device); struct mthca_qp *qp = to_mqp(ibqp); + __be32 doorbell[2]; void *wqe; void *prev_wqe; unsigned long flags; @@ -1838,6 +1842,34 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, ind = qp->sq.head & (qp->sq.max - 1); for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (unlikely(nreq == MTHCA_ARBEL_MAX_WQES_PER_SEND_DB)) { + nreq = 0; + + doorbell[0] = cpu_to_be32((MTHCA_ARBEL_MAX_WQES_PER_SEND_DB << 24) | + ((qp->sq.head & 0xffff) << 8) | + f0 | op0); + doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0); + + qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB; + size0 = 0; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->sq.db = cpu_to_be32(qp->sq.head & 0xffff); + + /* + * Make sure doorbell record is written before we + * write MMIO send doorbell. + */ + wmb(); + mthca_write64(doorbell, + dev->kar + MTHCA_SEND_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } + if (mthca_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) { mthca_err(dev, "SQ %06x full (%u head, %u tail," " %d max, %d nreq)\n", qp->qpn, @@ -2014,8 +2046,6 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, out: if (likely(nreq)) { - __be32 doorbell[2]; - doorbell[0] = cpu_to_be32((nreq << 24) | ((qp->sq.head & 0xffff) << 8) | f0 | op0); diff --git a/drivers/infiniband/hw/mthca/mthca_wqe.h b/drivers/infiniband/hw/mthca/mthca_wqe.h index 73f1c0b9021..e7d2c1e8619 100644 --- a/drivers/infiniband/hw/mthca/mthca_wqe.h +++ b/drivers/infiniband/hw/mthca/mthca_wqe.h @@ -50,7 +50,8 @@ enum { enum { MTHCA_INVAL_LKEY = 0x100, - MTHCA_TAVOR_MAX_WQES_PER_RECV_DB = 256 + MTHCA_TAVOR_MAX_WQES_PER_RECV_DB = 256, + MTHCA_ARBEL_MAX_WQES_PER_SEND_DB = 255 }; struct mthca_next_seg { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 54ef2fea530..23885801b6d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -608,9 +608,13 @@ void ipoib_ib_dev_flush(void *_dev) if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) ipoib_ib_dev_up(dev); + down(&priv->vlan_mutex); + /* Flush any child interfaces too */ list_for_each_entry(cpriv, &priv->child_intfs, list) ipoib_ib_dev_flush(&cpriv->dev); + + up(&priv->vlan_mutex); } void ipoib_ib_dev_cleanup(struct net_device *dev) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 2fa30751f36..475d98fa9e2 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -94,8 +94,10 @@ int ipoib_open(struct net_device *dev) if (ipoib_ib_dev_open(dev)) return -EINVAL; - if (ipoib_ib_dev_up(dev)) + if (ipoib_ib_dev_up(dev)) { + ipoib_ib_dev_stop(dev); return -EINVAL; + } if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { struct ipoib_dev_priv *cpriv; @@ -398,9 +400,9 @@ static void path_rec_completion(int status, while ((skb = __skb_dequeue(&neigh->queue))) __skb_queue_tail(&skqueue, skb); } - } else - path->query = NULL; + } + path->query = NULL; complete(&path->done); spin_unlock_irqrestore(&priv->lock, flags); @@ -428,7 +430,6 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, skb_queue_head_init(&path->queue); INIT_LIST_HEAD(&path->neigh_list); - init_completion(&path->done); memcpy(path->pathrec.dgid.raw, gid->raw, sizeof (union ib_gid)); path->pathrec.sgid = priv->local_gid; @@ -446,6 +447,8 @@ static int path_rec_start(struct net_device *dev, ipoib_dbg(priv, "Start path record lookup for " IPOIB_GID_FMT "\n", IPOIB_GID_ARG(path->pathrec.dgid)); + init_completion(&path->done); + path->query_id = ib_sa_path_rec_get(priv->ca, priv->port, &path->pathrec, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index c33ed87f9df..ef3ee035bbc 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -135,20 +135,14 @@ static struct ipoib_mcast *ipoib_mcast_alloc(struct net_device *dev, if (!mcast) return NULL; - init_completion(&mcast->done); - mcast->dev = dev; mcast->created = jiffies; mcast->backoff = 1; - mcast->logcount = 0; INIT_LIST_HEAD(&mcast->list); INIT_LIST_HEAD(&mcast->neigh_list); skb_queue_head_init(&mcast->pkt_queue); - mcast->ah = NULL; - mcast->query = NULL; - return mcast; } @@ -350,6 +344,8 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) rec.port_gid = priv->local_gid; rec.pkey = cpu_to_be16(priv->pkey); + init_completion(&mcast->done); + ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec, IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | @@ -469,6 +465,8 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, rec.traffic_class = priv->broadcast->mcmember.traffic_class; } + init_completion(&mcast->done); + ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec, comp_mask, mcast->backoff * 1000, GFP_ATOMIC, ipoib_mcast_join_complete, diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c index 75cf237196e..b386cc66c6b 100644 --- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c @@ -19,7 +19,7 @@ void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff); } -void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) +static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) { flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff); } diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 2aa767f9bd7..cb2e7d6ba28 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -35,7 +35,7 @@ #include <linux/moduleparam.h> #include <linux/vmalloc.h> #include <linux/delay.h> -#include <linux/rwsem.h> +#include <linux/spinlock.h> #include <linux/sched.h> #include "dvb_ca_en50221.h" @@ -111,9 +111,6 @@ struct dvb_ca_slot { /* size of the buffer to use when talking to the CAM */ int link_buf_size; - /* semaphore for syncing access to slot structure */ - struct rw_semaphore sem; - /* buffer for incoming packets */ struct dvb_ringbuffer rx_buffer; @@ -602,14 +599,11 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * eb if (ebuf == NULL) { int buf_free; - down_read(&ca->slot_info[slot].sem); if (ca->slot_info[slot].rx_buffer.data == NULL) { - up_read(&ca->slot_info[slot].sem); status = -EIO; goto exit; } buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); - up_read(&ca->slot_info[slot].sem); if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) { status = -EAGAIN; @@ -680,14 +674,11 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * eb /* OK, add it to the receive buffer, or copy into external buffer if supplied */ if (ebuf == NULL) { - down_read(&ca->slot_info[slot].sem); if (ca->slot_info[slot].rx_buffer.data == NULL) { - up_read(&ca->slot_info[slot].sem); status = -EIO; goto exit; } dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); - up_read(&ca->slot_info[slot].sem); } else { memcpy(ebuf, buf, bytes_read); } @@ -802,12 +793,8 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) { dprintk("%s\n", __FUNCTION__); - down_write(&ca->slot_info[slot].sem); ca->pub->slot_shutdown(ca->pub, slot); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; - vfree(ca->slot_info[slot].rx_buffer.data); - ca->slot_info[slot].rx_buffer.data = NULL; - up_write(&ca->slot_info[slot].sem); /* need to wake up all processes to check if they're now trying to write to a defunct CAM */ @@ -893,7 +880,7 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) case DVB_CA_SLOTSTATE_RUNNING: if (ca->open) - dvb_ca_en50221_read_data(ca, slot, NULL, 0); + dvb_ca_en50221_thread_wakeup(ca); break; } } @@ -1127,16 +1114,16 @@ static int dvb_ca_en50221_thread(void *data) break; } - rxbuf = vmalloc(RX_BUFFER_SIZE); - if (rxbuf == NULL) { - printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; + if (ca->slot_info[slot].rx_buffer.data == NULL) { + rxbuf = vmalloc(RX_BUFFER_SIZE); + if (rxbuf == NULL) { + printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); } - down_write(&ca->slot_info[slot].sem); - dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); - up_write(&ca->slot_info[slot].sem); ca->pub->slot_ts_enable(ca->pub, slot); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; @@ -1148,11 +1135,7 @@ static int dvb_ca_en50221_thread(void *data) if (!ca->open) continue; - // no need to poll if the CAM supports IRQs - if (ca->slot_info[slot].da_irq_supported) - break; - - // poll mode + // poll slots for data pktcount = 0; while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) { if (!ca->open) @@ -1367,12 +1350,13 @@ exit: /** * Condition for waking up in dvb_ca_en50221_io_read_condition */ -static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *result, int *_slot) +static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, + int *result, int *_slot) { int slot; int slot_count = 0; int idx; - int fraglen; + size_t fraglen; int connection_id = -1; int found = 0; u8 hdr[2]; @@ -1382,10 +1366,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *resu if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) goto nextslot; - down_read(&ca->slot_info[slot].sem); - if (ca->slot_info[slot].rx_buffer.data == NULL) { - up_read(&ca->slot_info[slot].sem); return 0; } @@ -1403,10 +1384,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *resu idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); } - if (!found) - up_read(&ca->slot_info[slot].sem); - - nextslot: +nextslot: slot = (slot + 1) % ca->slot_count; slot_count++; } @@ -1511,8 +1489,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, goto exit; status = pktlen; - exit: - up_read(&ca->slot_info[slot].sem); +exit: return status; } @@ -1544,11 +1521,11 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) for (i = 0; i < ca->slot_count; i++) { if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { - down_write(&ca->slot_info[i].sem); if (ca->slot_info[i].rx_buffer.data != NULL) { + /* it is safe to call this here without locks because + * ca->open == 0. Data is not read in this case */ dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); } - up_write(&ca->slot_info[i].sem); } } @@ -1607,7 +1584,6 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) dprintk("%s\n", __FUNCTION__); if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { - up_read(&ca->slot_info[slot].sem); mask |= POLLIN; } @@ -1619,7 +1595,6 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) poll_wait(file, &ca->wait_queue, wait); if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { - up_read(&ca->slot_info[slot].sem); mask |= POLLIN; } @@ -1709,7 +1684,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; atomic_set(&ca->slot_info[i].camchange_count, 0); ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; - init_rwsem(&ca->slot_info[i].sem); } if (signal_pending(current)) { @@ -1729,7 +1703,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ca->thread_pid = ret; return 0; - error: +error: if (ca != NULL) { if (ca->dvbdev != NULL) dvb_unregister_device(ca->dvbdev); @@ -1771,6 +1745,9 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) for (i = 0; i < ca->slot_count; i++) { dvb_ca_en50221_slot_shutdown(ca, i); + if (ca->slot_info[i].rx_buffer.data != NULL) { + vfree(ca->slot_info[i].rx_buffer.data); + } } kfree(ca->slot_info); dvb_unregister_device(ca->dvbdev); diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 87935490bfb..df536bd2e10 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -151,6 +151,8 @@ struct dvb_net_priv { unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */ int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */ unsigned long ts_count; /* Current ts cell counter. */ + + struct semaphore mutex; }; @@ -881,12 +883,13 @@ static int dvb_net_filter_sec_set(struct net_device *dev, static int dvb_net_feed_start(struct net_device *dev) { - int ret, i; + int ret = 0, i; struct dvb_net_priv *priv = dev->priv; struct dmx_demux *demux = priv->demux; unsigned char *mac = (unsigned char *) dev->dev_addr; dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode); + down(&priv->mutex); if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) printk("%s: BUG %d\n", __FUNCTION__, __LINE__); @@ -900,7 +903,7 @@ static int dvb_net_feed_start(struct net_device *dev) dvb_net_sec_callback); if (ret<0) { printk("%s: could not allocate section feed\n", dev->name); - return ret; + goto error; } ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); @@ -909,7 +912,7 @@ static int dvb_net_feed_start(struct net_device *dev) printk("%s: could not set section feed\n", dev->name); priv->demux->release_section_feed(priv->demux, priv->secfeed); priv->secfeed=NULL; - return ret; + goto error; } if (priv->rx_mode != RX_MODE_PROMISC) { @@ -948,7 +951,7 @@ static int dvb_net_feed_start(struct net_device *dev) ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback); if (ret < 0) { printk("%s: could not allocate ts feed\n", dev->name); - return ret; + goto error; } /* Set netdevice pointer for ts decaps callback. */ @@ -962,23 +965,26 @@ static int dvb_net_feed_start(struct net_device *dev) printk("%s: could not set ts feed\n", dev->name); priv->demux->release_ts_feed(priv->demux, priv->tsfeed); priv->tsfeed = NULL; - return ret; + goto error; } dprintk("%s: start filtering\n", __FUNCTION__); priv->tsfeed->start_filtering(priv->tsfeed); } else - return -EINVAL; + ret = -EINVAL; - return 0; +error: + up(&priv->mutex); + return ret; } static int dvb_net_feed_stop(struct net_device *dev) { struct dvb_net_priv *priv = dev->priv; - int i; + int i, ret = 0; dprintk("%s\n", __FUNCTION__); + down(&priv->mutex); if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { if (priv->secfeed) { if (priv->secfeed->is_filtering) { @@ -1019,8 +1025,9 @@ static int dvb_net_feed_stop(struct net_device *dev) else printk("%s: no ts feed to stop\n", dev->name); } else - return -EINVAL; - return 0; + ret = -EINVAL; + up(&priv->mutex); + return ret; } @@ -1044,8 +1051,8 @@ static void wq_set_multicast_list (void *data) struct dvb_net_priv *priv = dev->priv; dvb_net_feed_stop(dev); - priv->rx_mode = RX_MODE_UNI; + spin_lock_bh(&dev->xmit_lock); if (dev->flags & IFF_PROMISC) { dprintk("%s: promiscuous mode\n", dev->name); @@ -1070,6 +1077,7 @@ static void wq_set_multicast_list (void *data) } } + spin_unlock_bh(&dev->xmit_lock); dvb_net_feed_start(dev); } @@ -1200,6 +1208,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net); INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net); + init_MUTEX(&priv->mutex); net->base_addr = pid; diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index 49f541d9a04..8c7beffb045 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -65,7 +65,7 @@ static struct dvb_usb_rc_key a800_rc_keys[] = { }; -int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[5]; if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0), diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 00b946419b4..269d899da48 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -21,9 +21,9 @@ MODULE_LICENSE("GPL"); int dibusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) { if (d->priv != NULL) { - struct dib_fe_xfer_ops *ops = d->priv; - if (ops->fifo_ctrl != NULL) - if (ops->fifo_ctrl(d->fe,onoff)) { + struct dibusb_state *st = d->priv; + if (st->ops.fifo_ctrl != NULL) + if (st->ops.fifo_ctrl(d->fe,onoff)) { err("error while controlling the fifo of the demod."); return -ENODEV; } @@ -35,9 +35,9 @@ EXPORT_SYMBOL(dibusb_streaming_ctrl); int dibusb_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff) { if (d->priv != NULL) { - struct dib_fe_xfer_ops *ops = d->priv; - if (d->pid_filtering && ops->pid_ctrl != NULL) - ops->pid_ctrl(d->fe,index,pid,onoff); + struct dibusb_state *st = d->priv; + if (st->ops.pid_ctrl != NULL) + st->ops.pid_ctrl(d->fe,index,pid,onoff); } return 0; } @@ -46,9 +46,9 @@ EXPORT_SYMBOL(dibusb_pid_filter); int dibusb_pid_filter_ctrl(struct dvb_usb_device *d, int onoff) { if (d->priv != NULL) { - struct dib_fe_xfer_ops *ops = d->priv; - if (ops->pid_parse != NULL) - if (ops->pid_parse(d->fe,onoff) < 0) + struct dibusb_state *st = d->priv; + if (st->ops.pid_parse != NULL) + if (st->ops.pid_parse(d->fe,onoff) < 0) err("could not handle pid_parser"); } return 0; diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 74545f82eff..f98e306a575 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -148,7 +148,7 @@ static struct dvb_usb_rc_key digitv_rc_keys[] = { }; /* TODO is it really the NEC protocol ? */ -int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[5]; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index a902059812a..dd8e0b94edb 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -23,7 +23,7 @@ module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); /* general initialization functions */ -int dvb_usb_exit(struct dvb_usb_device *d) +static int dvb_usb_exit(struct dvb_usb_device *d) { deb_info("state before exiting everything: %x\n",d->state); dvb_usb_remote_exit(d); diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 9f639297a9f..d9a8ede14b4 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -7,7 +7,7 @@ Copyright (C) 2001-2002 Convergence Integrated Media GmbH Holger Waechtler <holger@convergence.de> - Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk> + Copyright (C) 2004 Steven Toth <stoth@hauppauge.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h index 11f86806756..1f250885d2c 100644 --- a/drivers/media/dvb/frontends/cx22702.h +++ b/drivers/media/dvb/frontends/cx22702.h @@ -7,7 +7,7 @@ Copyright (C) 2001-2002 Convergence Integrated Media GmbH Holger Waechtler <holger@convergence.de> - Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk> + Copyright (C) 2004 Steven Toth <stoth@hauppauge.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index bad0933eb71..84b62881cea 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -44,6 +44,8 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/slab.h> +#include <linux/string.h> #include "dvb_frontend.h" #include "dvb-pll.h" diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index c6d276618e8..ad8647a3c85 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -140,25 +140,25 @@ static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate) /* yeuch! */ fpxin = state->config->xin * 10; fptmp = fpxin; do_div(fptmp, 123); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 1; fptmp = fpxin; do_div(fptmp, 160); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 0; fptmp = fpxin; do_div(fptmp, 246); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 1; fptmp = fpxin; do_div(fptmp, 320); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 0; fptmp = fpxin; do_div(fptmp, 492); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 1; fptmp = fpxin; do_div(fptmp, 640); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 0; fptmp = fpxin; do_div(fptmp, 984); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 1; fin = state->config->xin >> 4; diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index d8bf6587789..fa5034a9ecf 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -81,6 +81,7 @@ config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" depends on DVB_CORE && PCI select VIDEO_SAA7146 + select DVB_STV0297 select DVB_STV0299 select DVB_TDA1004X help diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c index c3801e328fe..6079e8865d5 100644 --- a/drivers/media/dvb/ttpci/av7110_ca.c +++ b/drivers/media/dvb/ttpci/av7110_ca.c @@ -40,6 +40,7 @@ #include "av7110.h" #include "av7110_hw.h" +#include "av7110_ca.h" void CI_handle(struct av7110 *av7110, u8 *data, u16 len) diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index aa75dc03a0b..9f51bae7194 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1020,6 +1020,8 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); static struct saa7146_extension budget_extension = { .name = "budget_av", + .flags = SAA7146_I2C_SHORT_DELAY, + .pci_tbl = pci_tbl, .module = THIS_MODULE, diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 75fb92d6099..b9b3cd9c036 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -1166,7 +1166,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); static struct saa7146_extension budget_extension = { .name = "budget_ci dvb\0", - .flags = 0, + .flags = SAA7146_I2C_SHORT_DELAY, .module = THIS_MODULE, .pci_tbl = &pci_tbl[0], diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 4fd8bbc4703..bc4ce7559cb 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -738,7 +738,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); static struct saa7146_extension budget_extension = { .name = "budget dvb\0", - .flags = 0, + .flags = SAA7146_I2C_SHORT_DELAY, .module = THIS_MODULE, .pci_tbl = pci_tbl, diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c index e9a8457b072..ac79ef178c0 100644 --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c @@ -37,6 +37,7 @@ #include <linux/string.h> #include <linux/i2c.h> +#include "ttpci-eeprom.h" #if 1 #define dprintk(x...) do { printk(x); } while (0) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index ecb9a31dd00..cc4a723e24d 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -32,9 +32,6 @@ config VIDEO_BT848_DVB ---help--- This adds support for DVB/ATSC cards based on the BT878 chip. - To compile this driver as a module, choose M here: the - module will be called dvb-bt8xx. - config VIDEO_SAA6588 tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards" depends on VIDEO_DEV && I2C && VIDEO_BT848 diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index e31ebb11c46..012be639aa1 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -2904,7 +2904,7 @@ void __devinit bttv_idcard(struct bttv *btv) */ /* Some Modular Technology cards have an eeprom, but no subsystem ID */ -void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) +static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) { int type = -1; @@ -3879,7 +3879,7 @@ static void __devinit init_PXC200(struct bttv *btv) * error. ERROR_CPLD_Check_Failed. */ /* ----------------------------------------------------------------------- */ -void +static void init_RTV24 (struct bttv *btv) { uint32_t dataRead = 0; @@ -4103,7 +4103,7 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq) /* ----------------------------------------------------------------------- */ /* winview */ -void winview_audio(struct bttv *btv, struct video_audio *v, int set) +static void winview_audio(struct bttv *btv, struct video_audio *v, int set) { /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ int bits_out, loops, vol, data; diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 709099f03bd..3c58a2a6890 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -1720,7 +1720,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) memset(i,0,sizeof(*i)); i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; - i->audioset = 1; + i->audioset = 0; if (i->index == bttv_tvcards[btv->c.type].tuner) { sprintf(i->name, "Television"); i->type = V4L2_INPUT_TYPE_TUNER; @@ -1771,12 +1771,20 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) memset(t,0,sizeof(*t)); strcpy(t->name, "Television"); t->type = V4L2_TUNER_ANALOG_TV; - t->rangehigh = 0xffffffffUL; t->capability = V4L2_TUNER_CAP_NORM; t->rxsubchans = V4L2_TUNER_SUB_MONO; if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) t->signal = 0xffff; { + struct video_tuner tuner; + + memset(&tuner, 0, sizeof (tuner)); + tuner.rangehigh = 0xffffffffUL; + bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner); + t->rangelow = tuner.rangelow; + t->rangehigh = tuner.rangehigh; + } + { /* Hmmm ... */ struct video_audio va; memset(&va, 0, sizeof(struct video_audio)); @@ -1853,7 +1861,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) } case VIDIOC_LOG_STATUS: { - bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, 0); + bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL); return 0; } @@ -2029,19 +2037,33 @@ static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type) return 0; } +static void +pix_format_set_size (struct v4l2_pix_format * f, + const struct bttv_format * fmt, + unsigned int width, + unsigned int height) +{ + f->width = width; + f->height = height; + + if (fmt->flags & FORMAT_FLAGS_PLANAR) { + f->bytesperline = width; /* Y plane */ + f->sizeimage = (width * height * fmt->depth) >> 3; + } else { + f->bytesperline = (width * fmt->depth) >> 3; + f->sizeimage = height * f->bytesperline; + } +} + static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f) { switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format)); - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; + pix_format_set_size (&f->fmt.pix, fh->fmt, + fh->width, fh->height); f->fmt.pix.field = fh->cap.field; f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; return 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: memset(&f->fmt.win,0,sizeof(struct v4l2_window)); @@ -2106,11 +2128,9 @@ static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv, f->fmt.pix.width = maxw; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; + pix_format_set_size (&f->fmt.pix, fmt, + f->fmt.pix.width & ~3, + f->fmt.pix.height); return 0; } @@ -2278,6 +2298,15 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, retval = -EINVAL; goto fh_unlock_and_return; } + if (fmt->flags & FORMAT_FLAGS_RAW) { + /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL * + RAW_LINES * 2. F1 is stored at offset 0, F2 + at buffer size / 2. */ + fh->width = RAW_BPL; + fh->height = gbufsize / RAW_BPL; + btv->init.width = RAW_BPL; + btv->init.height = gbufsize / RAW_BPL; + } fh->ovfmt = fmt; fh->fmt = fmt; btv->init.ovfmt = fmt; @@ -2589,9 +2618,11 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, if (0 == v4l2) return -EINVAL; - strcpy(cap->driver,"bttv"); - strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci)); + memset(cap, 0, sizeof (*cap)); + strlcpy(cap->driver, "bttv", sizeof (cap->driver)); + strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card)); + snprintf(cap->bus_info, sizeof (cap->bus_info), + "PCI:%s", pci_name(btv->c.pci)); cap->version = BTTV_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | @@ -2952,6 +2983,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR; field = videobuf_next_field(&fh->cap); if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) { + kfree (fh->cap.read_buf); + fh->cap.read_buf = NULL; up(&fh->cap.lock); return POLLERR; } diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index f6afeec499c..aea3f038cff 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -208,8 +208,11 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw) static void input_change(struct i2c_client *client) { + struct cx25840_state *state = i2c_get_clientdata(client); v4l2_std_id std = cx25840_get_v4lstd(client); + /* Note: perhaps V4L2_STD_PAL_M should be handled as V4L2_STD_NTSC + instead of V4L2_STD_PAL. Someone needs to test this. */ if (std & V4L2_STD_PAL) { /* Follow tuner change procedure for PAL */ cx25840_write(client, 0x808, 0xff); @@ -220,7 +223,32 @@ static void input_change(struct i2c_client *client) cx25840_write(client, 0x80b, 0x10); } else if (std & V4L2_STD_NTSC) { /* NTSC */ - cx25840_write(client, 0x808, 0xf6); + if (state->cardtype == CARDTYPE_PVR150_WORKAROUND) { + /* Certain Hauppauge PVR150 models have a hardware bug + that causes audio to drop out. For these models the + audio standard must be set explicitly. + To be precise: it affects cards with tuner models + 85, 99 and 112 (model numbers from tveeprom). */ + if (std == V4L2_STD_NTSC_M_JP) { + /* Japan uses EIAJ audio standard */ + cx25840_write(client, 0x808, 0x2f); + } else { + /* Others use the BTSC audio standard */ + cx25840_write(client, 0x808, 0x1f); + } + /* South Korea uses the A2-M (aka Zweiton M) audio + standard, and should set 0x808 to 0x3f, but I don't + know how to detect this. */ + } else if (std == V4L2_STD_NTSC_M_JP) { + /* Japan uses EIAJ audio standard */ + cx25840_write(client, 0x808, 0xf7); + } else { + /* Others use the BTSC audio standard */ + cx25840_write(client, 0x808, 0xf6); + } + /* South Korea uses the A2-M (aka Zweiton M) audio standard, + and should set 0x808 to 0xf8, but I don't know how to + detect this. */ cx25840_write(client, 0x80b, 0x00); } @@ -241,7 +269,8 @@ static int set_input(struct i2c_client *client, enum cx25840_input input) case CX25840_TUNER: cx25840_dbg("now setting Tuner input\n"); - if (state->cardtype == CARDTYPE_PVR150) { + if (state->cardtype == CARDTYPE_PVR150 || + state->cardtype == CARDTYPE_PVR150_WORKAROUND) { /* CH_SEL_ADC2=1 */ cx25840_and_or(client, 0x102, ~0x2, 0x02); } @@ -363,6 +392,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) case CX25840_CID_CARDTYPE: switch (ctrl->value) { case CARDTYPE_PVR150: + case CARDTYPE_PVR150_WORKAROUND: case CARDTYPE_PG600: state->cardtype = ctrl->value; break; @@ -714,7 +744,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_cx25840; +static struct i2c_driver i2c_driver_cx25840; static int cx25840_detect_client(struct i2c_adapter *adapter, int address, int kind) @@ -807,7 +837,7 @@ static int cx25840_detach_client(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_cx25840 = { +static struct i2c_driver i2c_driver_cx25840 = { .name = "cx25840", .id = I2C_DRIVERID_CX25840, diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h index 5c3f0639fb7..4932ed1c9b1 100644 --- a/drivers/media/video/cx25840/cx25840.h +++ b/drivers/media/video/cx25840/cx25840.h @@ -40,9 +40,16 @@ extern int cx25840_debug; #define CX25840_CID_CARDTYPE (V4L2_CID_PRIVATE_BASE+0) +/* The CARDTYPE_PVR150_WORKAROUND cardtype activates a workaround for a + hardware bug that is present in PVR150 (and possible PVR500) cards that + have certain NTSC tuners (tveeprom model numbers 85, 99 and 112). The + audio autodetect fails on some channels for these models and the workaround + is to select the audio standard explicitly. Many thanks to Hauppauge for + providing this information. */ enum cx25840_cardtype { CARDTYPE_PVR150, - CARDTYPE_PG600 + CARDTYPE_PG600, + CARDTYPE_PVR150_WORKAROUND, }; enum cx25840_input { diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index f2268631b7c..951709aa88b 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -567,6 +567,7 @@ struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -711,6 +712,7 @@ struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -1083,41 +1085,28 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); core->tuner_type = tv.tuner_type; core->has_radio = tv.has_radio; -} - -static int hauppauge_eeprom_dvb(struct cx88_core *core, u8 *ee) -{ - int model; - int tuner; /* Make sure we support the board model */ - model = ee[0x1f] << 24 | ee[0x1e] << 16 | ee[0x1d] << 8 | ee[0x1c]; - switch(model) { - case 90002: - case 90500: - case 90501: + switch (tv.model) + { + case 90002: /* Nova-T-PCI (9002) */ + case 92001: /* Nova-S-Plus (Video and IR) */ + case 92002: /* Nova-S-Plus (Video and IR) */ + case 90003: /* Nova-T-PCI (9002 No RF out) */ + case 90500: /* Nova-T-PCI (oem) */ + case 90501: /* Nova-T-PCI (oem/IR) */ + case 92000: /* Nova-SE2 (OEM, No Video or IR) */ + /* known */ break; default: printk("%s: warning: unknown hauppauge model #%d\n", - core->name, model); + core->name, tv.model); break; } - /* Make sure we support the tuner */ - tuner = ee[0x2d]; - switch(tuner) { - case 0x4B: /* dtt 7595 */ - case 0x4C: /* dtt 7592 */ - break; - default: - printk("%s: error: unknown hauppauge tuner 0x%02x\n", - core->name, tuner); - return -ENODEV; - } - printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%d\n", - core->name, model, tuner); - return 0; + printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + core->name, tv.model); } /* ----------------------------------------------------------------------- */ @@ -1201,7 +1190,7 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) void cx88_card_setup(struct cx88_core *core) { - static u8 eeprom[128]; + static u8 eeprom[256]; if (0 == core->i2c_rc) { core->i2c_client.addr = 0xa0 >> 1; @@ -1224,7 +1213,7 @@ void cx88_card_setup(struct cx88_core *core) break; case CX88_BOARD_HAUPPAUGE_DVB_T1: if (0 == core->i2c_rc) - hauppauge_eeprom_dvb(core,eeprom); + hauppauge_eeprom(core,eeprom); break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index eb806af1718..bb6eb54e19c 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -837,6 +837,29 @@ static int set_pll(struct cx88_core *core, int prescale, u32 ofreq) return -1; } +int cx88_start_audio_dma(struct cx88_core *core) +{ + /* setup fifo + format */ + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0); + + cx_write(MO_AUDD_LNGTH, 128); /* fifo bpl size */ + cx_write(MO_AUDR_LNGTH, 128); /* fifo bpl size */ + + /* start dma */ + cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */ + + return 0; +} + +int cx88_stop_audio_dma(struct cx88_core *core) +{ + /* stop dma */ + cx_write(MO_AUD_DMACNTRL, 0x0000); + + return 0; +} + static int set_tvaudio(struct cx88_core *core) { struct cx88_tvnorm *norm = core->tvnorm; @@ -877,12 +900,16 @@ static int set_tvaudio(struct cx88_core *core) cx88_set_tvaudio(core); /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */ - cx_write(MO_AUDD_LNGTH, 128); /* fifo size */ - cx_write(MO_AUDR_LNGTH, 128); /* fifo size */ - cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */ +/* + This should be needed only on cx88-alsa. It seems that some cx88 chips have + bugs and does require DMA enabled for it to work. + */ + cx88_start_audio_dma(core); return 0; } + + int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm) { u32 fsc8; @@ -1204,6 +1231,8 @@ EXPORT_SYMBOL(cx88_set_scale); EXPORT_SYMBOL(cx88_vdev_init); EXPORT_SYMBOL(cx88_core_get); EXPORT_SYMBOL(cx88_core_put); +EXPORT_SYMBOL(cx88_start_audio_dma); +EXPORT_SYMBOL(cx88_stop_audio_dma); /* * Local variables: diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 6d9bec1c583..a1b120c8a9b 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -119,13 +119,10 @@ static void set_audio_registers(struct cx88_core *core, const struct rlist *l) static void set_audio_start(struct cx88_core *core, u32 mode) { - // mute + /* mute */ cx_write(AUD_VOL_CTL, (1 << 6)); - // start programming - cx_write(MO_AUD_DMACNTRL, 0x0000); - msleep(100); - //cx_write(AUD_CTL, 0x0000); + /* start programming */ cx_write(AUD_INIT, mode); cx_write(AUD_INIT_LD, 0x0001); cx_write(AUD_SOFT_RESET, 0x0001); @@ -135,17 +132,21 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) { u32 volume; + /* restart dma; This avoids buzz in NICAM and is good in others */ + cx88_stop_audio_dma(core); + cx_write(AUD_RATE_THRES_DMD, 0x000000C0); + cx88_start_audio_dma(core); + if (cx88_boards[core->board].blackbird) { - // sets sound input from external adc + /* sets sound input from external adc */ cx_set(AUD_CTL, EN_I2SIN_ENABLE); - //cx_write(AUD_I2SINPUTCNTL, 0); cx_write(AUD_I2SINPUTCNTL, 4); cx_write(AUD_BAUDRATE, 1); - // 'pass-thru mode': this enables the i2s output to the mpeg encoder + /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ cx_set(AUD_CTL, EN_I2SOUT_ENABLE); cx_write(AUD_I2SOUTPUTCNTL, 1); cx_write(AUD_I2SCNTL, 0); - //cx_write(AUD_APB_IN_RATE_ADJ, 0); + /* cx_write(AUD_APB_IN_RATE_ADJ, 0); */ } else { ctl |= EN_DAC_ENABLE; cx_write(AUD_CTL, ctl); @@ -153,7 +154,6 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) /* finish programming */ cx_write(AUD_SOFT_RESET, 0x0000); - cx_write(MO_AUD_DMACNTRL, 0x0003); /* unmute */ volume = cx_sread(SHADOW_AUD_VOL_CTL); @@ -313,7 +313,6 @@ static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode) {AUD_RATE_ADJ3, 0x00000100}, {AUD_RATE_ADJ4, 0x00000400}, {AUD_RATE_ADJ5, 0x00001000}, - //{ AUD_DMD_RA_DDS, 0x00c0d5ce }, {AUD_ERRLOGPERIOD_R, 0x00000fff}, {AUD_ERRINTRPTTHSHLD1_R, 0x000003ff}, {AUD_ERRINTRPTTHSHLD2_R, 0x000000ff}, @@ -351,12 +350,12 @@ static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode) set_audio_registers(core, nicam_l); break; case WW_I: - dprintk("%s PAL-I NICAM (status: devel)\n", __FUNCTION__); + dprintk("%s PAL-I NICAM (status: known-good)\n", __FUNCTION__); set_audio_registers(core, nicam_bgdki_common); set_audio_registers(core, nicam_i); break; default: - dprintk("%s PAL-BGDK NICAM (status: unknown)\n", __FUNCTION__); + dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __FUNCTION__); set_audio_registers(core, nicam_bgdki_common); set_audio_registers(core, nicam_default); break; @@ -715,8 +714,7 @@ int cx88_detect_nicam(struct cx88_core *core) /* if bit1=1 then nicam is detected */ j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1); - /* 3x detected: absolutly sure now */ - if (j == 3) { + if (j == 1) { dprintk("nicam is detected.\n"); return 1; } diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index b19d3a9e229..27fb080fd7a 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -491,6 +491,10 @@ extern struct cx88_core* cx88_core_get(struct pci_dev *pci); extern void cx88_core_put(struct cx88_core *core, struct pci_dev *pci); +extern int cx88_start_audio_dma(struct cx88_core *core); +extern int cx88_stop_audio_dma(struct cx88_core *core); + + /* ----------------------------------------------------------- */ /* cx88-vbi.c */ diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index d54bc012748..9f6e5e5355a 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -32,7 +32,7 @@ /* #define ENABLE_DEBUG_ISOC_FRAMES */ -unsigned int core_debug; +static unsigned int core_debug; module_param(core_debug,int,0644); MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); @@ -41,7 +41,7 @@ MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); printk(KERN_INFO "%s %s :"fmt, \ dev->name, __FUNCTION__ , ##arg); } while (0) -unsigned int reg_debug; +static unsigned int reg_debug; module_param(reg_debug,int,0644); MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]"); @@ -50,7 +50,7 @@ MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]"); printk(KERN_INFO "%s %s :"fmt, \ dev->name, __FUNCTION__ , ##arg); } while (0) -unsigned int isoc_debug; +static unsigned int isoc_debug; module_param(isoc_debug,int,0644); MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]"); diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 57c1826b928..abec32c175a 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -226,7 +226,7 @@ static int em28xx_config(struct em28xx *dev) * em28xx_config_i2c() * configure i2c attached devices */ -void em28xx_config_i2c(struct em28xx *dev) +static void em28xx_config_i2c(struct em28xx *dev) { struct v4l2_frequency f; struct video_decoder_init em28xx_vdi = {.data = NULL }; diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 801c736e932..124c502ea1f 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -278,7 +278,7 @@ static int ir_probe(struct i2c_adapter *adap); static struct i2c_driver driver = { .name = "ir remote kbd driver", - .id = I2C_DRIVERID_EXP3, /* FIXME */ + .id = I2C_DRIVERID_I2C_IR, .flags = I2C_DF_NOTIFY, .attach_adapter = ir_probe, .detach_client = ir_detach, diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 0235cef07b3..e717e30d818 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -771,17 +771,19 @@ static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client) static void saa7115_log_status(struct i2c_client *client) { - static const char * const audclk_freq_strs[] = { - "44.1 kHz", - "48 kHz", - "32 kHz" - }; struct saa7115_state *state = i2c_get_clientdata(client); + char *audfreq = "undefined"; int reg1e, reg1f; int signalOk; int vcr; - saa7115_info("Audio frequency: %s\n", audclk_freq_strs[state->audclk_freq]); + switch (state->audclk_freq) { + case V4L2_AUDCLK_32_KHZ: audfreq = "32 kHz"; break; + case V4L2_AUDCLK_441_KHZ: audfreq = "44.1 kHz"; break; + case V4L2_AUDCLK_48_KHZ: audfreq = "48 kHz"; break; + } + + saa7115_info("Audio frequency: %s\n", audfreq); if (client->name[6] == '4') { /* status for the saa7114 */ reg1f = saa7115_read(client, 0x1f); diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c index 25b30f352d8..59e13fdea78 100644 --- a/drivers/media/video/saa711x.c +++ b/drivers/media/video/saa711x.c @@ -323,7 +323,7 @@ saa711x_command (struct i2c_client *client, case VIDEO_MODE_SECAM: saa711x_write(client, 0x08, - (decoder->reg[0x0e] & 0x3f) | 0x00); + (decoder->reg[0x08] & 0x3f) | 0x00); saa711x_write(client, 0x0e, (decoder->reg[0x0e] & 0x8f) | 0x50); break; diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 843431f10e3..3428e1ed003 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -223,7 +223,7 @@ static const struct i2c_reg_value saa7127_init_config_60hz[] = { }; #define SAA7127_50HZ_DAC_CONTROL 0x02 -struct i2c_reg_value saa7127_init_config_50hz[] = { +static struct i2c_reg_value saa7127_init_config_50hz[] = { { SAA7127_REG_BURST_START, 0x21 }, /* BURST_END is also used as a chip ID in saa7127_detect_client */ { SAA7127_REG_BURST_END, 0x1d }, @@ -696,7 +696,7 @@ static int saa7127_command(struct i2c_client *client, /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_saa7127; +static struct i2c_driver i2c_driver_saa7127; /* ----------------------------------------------------------------------- */ @@ -818,7 +818,7 @@ static int saa7127_detach(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_saa7127 = { +static struct i2c_driver i2c_driver_saa7127 = { .name = "saa7127", .id = I2C_DRIVERID_SAA7127, .flags = I2C_DF_NOTIFY, diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 5707c666660..263c6e2e3e8 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -58,8 +58,6 @@ static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s)."); -int position; - #define dprintk(fmt, arg...) if (debug) \ printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ## arg) @@ -140,7 +138,8 @@ static void saa7134_dma_start(struct saa7134_dev *dev) * */ -void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status) +static void saa7134_irq_alsa_done(struct saa7134_dev *dev, + unsigned long status) { int next_blk, reg = 0; @@ -881,7 +880,7 @@ static void snd_saa7134_free(snd_card_t * card) * */ -int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) +static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) { snd_card_t *card; @@ -945,6 +944,8 @@ int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name, chip->iobase, chip->irq); + printk(KERN_INFO "%s/alsa: %s registered as card %d\n",dev->name,card->longname,index[devnum]); + if ((err = snd_card_register(card)) == 0) { snd_saa7134_cards[devnum] = card; return 0; @@ -955,6 +956,22 @@ __nodev: return err; } + +static int alsa_device_init(struct saa7134_dev *dev) +{ + dev->dmasound.priv_data = dev; + alsa_card_saa7134_create(dev,dev->nr); + return 1; +} + +static int alsa_device_exit(struct saa7134_dev *dev) +{ + + snd_card_free(snd_saa7134_cards[dev->nr]); + snd_saa7134_cards[dev->nr] = NULL; + return 1; +} + /* * Module initializer * @@ -968,22 +985,21 @@ static int saa7134_alsa_init(void) struct saa7134_dev *dev = NULL; struct list_head *list; - position = 0; - printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); list_for_each(list,&saa7134_devlist) { dev = list_entry(list, struct saa7134_dev, devlist); if (dev->dmasound.priv_data == NULL) { - dev->dmasound.priv_data = dev; - alsa_card_saa7134_create(dev,position); - position++; + alsa_device_init(dev); } else { printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name); return -EBUSY; } } + dmasound_init = alsa_device_init; + dmasound_exit = alsa_device_exit; + if (dev == NULL) printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n"); @@ -994,7 +1010,7 @@ static int saa7134_alsa_init(void) * Module destructor */ -void saa7134_alsa_exit(void) +static void saa7134_alsa_exit(void) { int idx; diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 4275d2ddb86..1a093bf176f 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -88,6 +88,9 @@ LIST_HEAD(saa7134_devlist); static LIST_HEAD(mops_list); static unsigned int saa7134_devcount; +int (*dmasound_init)(struct saa7134_dev *dev); +int (*dmasound_exit)(struct saa7134_dev *dev); + #define dprintk(fmt, arg...) if (core_debug) \ printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg) @@ -184,8 +187,7 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) /* ----------------------------------------------------------- */ /* delayed request_module */ -#ifdef CONFIG_MODULES - +#if defined(CONFIG_MODULES) && defined(MODULE) static int need_empress; static int need_dvb; static int need_alsa; @@ -234,9 +236,7 @@ static void request_module_depend(char *name, int *flag) } #else - #define request_module_depend(name,flag) - #endif /* CONFIG_MODULES */ /* ------------------------------------------------------------------ */ @@ -1017,6 +1017,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, /* check for signal */ saa7134_irq_video_intl(dev); + if (dmasound_init && !dev->dmasound.priv_data) { + dmasound_init(dev); + } + return 0; fail4: @@ -1040,6 +1044,11 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) struct list_head *item; struct saa7134_mpeg_ops *mops; + /* Release DMA sound modules if present */ + if (dmasound_exit && dev->dmasound.priv_data) { + dmasound_exit(dev); + } + /* debugging ... */ if (irq_debug) { u32 report = saa_readl(SAA7134_IRQ_REPORT); @@ -1071,6 +1080,7 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) saa7134_i2c_unregister(dev); saa7134_unregister_video(dev); + /* the DMA sound modules should be unloaded before reaching this, but just in case they are still present... */ if (dev->dmasound.priv_data != NULL) { @@ -1078,6 +1088,7 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) dev->dmasound.priv_data = NULL; } + /* release resources */ free_irq(pci_dev->irq, dev); iounmap(dev->lmmio); @@ -1149,10 +1160,10 @@ static int saa7134_init(void) static void saa7134_fini(void) { -#ifdef CONFIG_MODULES +#if defined(CONFIG_MODULES) && defined(MODULE) if (pending_registered) unregister_module_notifier(&pending_notifier); -#endif +#endif /* CONFIG_MODULES */ pci_unregister_driver(&saa7134_pci_driver); } @@ -1168,6 +1179,8 @@ EXPORT_SYMBOL(saa7134_boards); /* ----------------- for the DMA sound modules --------------- */ +EXPORT_SYMBOL(dmasound_init); +EXPORT_SYMBOL(dmasound_exit); EXPORT_SYMBOL(saa7134_pgtable_free); EXPORT_SYMBOL(saa7134_pgtable_build); EXPORT_SYMBOL(saa7134_pgtable_alloc); diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index fd9ed11ab1e..5a579194e45 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -899,26 +899,26 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) spin_unlock(&dev->slock); } -int saa7134_dsp_create(struct saa7134_dev *dev) +static int saa7134_dsp_create(struct saa7134_dev *dev) { int err; - err = dev->dmasound.minor_dsp = - register_sound_dsp(&saa7134_dsp_fops, - dsp_nr[dev->nr]); - if (err < 0) { - goto fail; - } - printk(KERN_INFO "%s: registered device dsp%d\n", - dev->name,dev->dmasound.minor_dsp >> 4); - - err = dev->dmasound.minor_mixer = - register_sound_mixer(&saa7134_mixer_fops, - mixer_nr[dev->nr]); - if (err < 0) - goto fail; - printk(KERN_INFO "%s: registered device mixer%d\n", - dev->name,dev->dmasound.minor_mixer >> 4); + err = dev->dmasound.minor_dsp = + register_sound_dsp(&saa7134_dsp_fops, + dsp_nr[dev->nr]); + if (err < 0) { + goto fail; + } + printk(KERN_INFO "%s: registered device dsp%d\n", + dev->name,dev->dmasound.minor_dsp >> 4); + + err = dev->dmasound.minor_mixer = + register_sound_mixer(&saa7134_mixer_fops, + mixer_nr[dev->nr]); + if (err < 0) + goto fail; + printk(KERN_INFO "%s: registered device mixer%d\n", + dev->name,dev->dmasound.minor_mixer >> 4); return 0; @@ -929,6 +929,31 @@ fail: } +static int oss_device_init(struct saa7134_dev *dev) +{ + dev->dmasound.priv_data = dev; + saa7134_oss_init1(dev); + saa7134_dsp_create(dev); + return 1; +} + +static int oss_device_exit(struct saa7134_dev *dev) +{ + + unregister_sound_mixer(dev->dmasound.minor_mixer); + unregister_sound_dsp(dev->dmasound.minor_dsp); + + saa7134_oss_fini(dev); + + if (dev->pci->irq > 0) { + synchronize_irq(dev->pci->irq); + free_irq(dev->pci->irq,&dev->dmasound); + } + + dev->dmasound.priv_data = NULL; + return 1; +} + static int saa7134_oss_init(void) { struct saa7134_dev *dev = NULL; @@ -939,9 +964,7 @@ static int saa7134_oss_init(void) list_for_each(list,&saa7134_devlist) { dev = list_entry(list, struct saa7134_dev, devlist); if (dev->dmasound.priv_data == NULL) { - dev->dmasound.priv_data = dev; - saa7134_oss_init1(dev); - saa7134_dsp_create(dev); + oss_device_init(dev); } else { printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name); return -EBUSY; @@ -951,11 +974,14 @@ static int saa7134_oss_init(void) if (dev == NULL) printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n"); + dmasound_init = oss_device_init; + dmasound_exit = oss_device_exit; + return 0; } -void saa7134_oss_exit(void) +static void saa7134_oss_exit(void) { struct saa7134_dev *dev = NULL; struct list_head *list; @@ -967,18 +993,7 @@ void saa7134_oss_exit(void) if (!dev->dmasound.minor_dsp) continue; - unregister_sound_mixer(dev->dmasound.minor_mixer); - unregister_sound_dsp(dev->dmasound.minor_dsp); - - saa7134_oss_fini(dev); - - if (dev->pci->irq > 0) { - synchronize_irq(dev->pci->irq); - free_irq(dev->pci->irq,&dev->dmasound); - } - - dev->dmasound.priv_data = NULL; - + oss_device_exit(dev); } printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n"); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 244e1973081..add49db1ad4 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -571,6 +571,10 @@ void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf); int saa7134_set_dmabits(struct saa7134_dev *dev); +extern int (*dmasound_init)(struct saa7134_dev *dev); +extern int (*dmasound_exit)(struct saa7134_dev *dev); + + /* ----------------------------------------------------------- */ /* saa7134-cards.c */ diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 72e8741e8b5..d95aecebbda 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -81,7 +81,7 @@ hauppauge_tuner_fmt[] = { 0x00000010, " PAL(I)" }, { 0x00400000, " SECAM(L/L')" }, { 0x00000e00, " PAL(D/K)" }, - { 0x03000000, " ATSC Digital" }, + { 0x03000000, " ATSC/DVB Digital" }, }; /* This is the full list of possible tuners. Many thanks to Hauppauge for @@ -209,13 +209,27 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Philips FMD1216ME"}, { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, { TUNER_ABSENT, "Panasonic ENV57H12D5"}, - { TUNER_ABSENT, "TCL MFNM05-4"}, + { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, { TUNER_ABSENT, "TCL MNM05-4"}, { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, { TUNER_ABSENT, "TCL MQNM05-4"}, { TUNER_ABSENT, "LG TAPC-W701D"}, { TUNER_ABSENT, "TCL 9886P-WM"}, { TUNER_ABSENT, "TCL 1676NM-WM"}, + /* 110-119 */ + { TUNER_ABSENT, "Thompson DTT75105"}, + { TUNER_ABSENT, "Conexant_CX24109"}, + { TUNER_ABSENT, "TCL M2523_5N_E"}, + { TUNER_ABSENT, "TCL M2523_3DB_E"}, + { TUNER_ABSENT, "Philips 8275A"}, + { TUNER_ABSENT, "Microtune MT2060"}, + { TUNER_ABSENT, "Philips FM1236 MK5"}, + { TUNER_ABSENT, "Philips FM1216ME MK5"}, + { TUNER_ABSENT, "TCL M2523_3DI_E"}, + { TUNER_ABSENT, "Samsung THPD5222FG30A"}, + /* 120-129 */ + { TUNER_ABSENT, "Xceive XC3028"}, + { TUNER_ABSENT, "Philips FQ1216LME MK5"}, }; static struct HAUPPAUGE_AUDIOIC @@ -325,6 +339,7 @@ static int hasRadioTuner(int tunerType) case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM: case 89: //PNPEnv_TUNER_TCL_MFPE05_2: case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4: + case 105: return 1; } return 0; @@ -368,10 +383,15 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, memset(tvee, 0, sizeof(*tvee)); done = len = beenhere = 0; - /* Hack for processing eeprom for em28xx */ - if ((eeprom_data[0]==0x1a)&&(eeprom_data[1]==0xeb)&& - (eeprom_data[2]==0x67)&&(eeprom_data[3]==0x95)) - start=0xa0; + /* Hack for processing eeprom for em28xx and cx 2388x*/ + if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) && + (eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95)) + start=0xa0; /* Generic em28xx offset */ + else if (((eeprom_data[0] & 0xf0) == 0x10) && + (eeprom_data[1] == 0x00) && + (eeprom_data[2] == 0x00) && + (eeprom_data[8] == 0x84)) + start=8; /* Generic cx2388x offset */ else start=0; @@ -448,6 +468,17 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, eeprom_data[i+5] + (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); + + if ( (eeprom_data[i + 8] && 0xf0) && + (tvee->serial_number < 0xffffff) ) { + tvee->MAC_address[0] = 0x00; + tvee->MAC_address[1] = 0x0D; + tvee->MAC_address[2] = 0xFE; + tvee->MAC_address[3] = eeprom_data[i + 7]; + tvee->MAC_address[4] = eeprom_data[i + 6]; + tvee->MAC_address[5] = eeprom_data[i + 5]; + tvee->has_MAC_address = 1; + } break; case 0x05: @@ -466,11 +497,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, case 0x06: /* tag 'ModelRev' */ tvee->model = - eeprom_data[i+1] + - (eeprom_data[i+2] << 8); - tvee->revision = eeprom_data[i+5] + - (eeprom_data[i+6] << 8) + - (eeprom_data[i+7] << 16); + eeprom_data[i + 1] + + (eeprom_data[i + 2] << 8) + + (eeprom_data[i + 3] << 16) + + (eeprom_data[i + 4] << 24); + tvee->revision = + eeprom_data[i +5 ] + + (eeprom_data[i + 6] << 8) + + (eeprom_data[i + 7] << 16); break; case 0x07: @@ -563,6 +597,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, t_name2 = "unknown"; } + tvee->tuner_hauppauge_model = tuner1; + tvee->tuner2_hauppauge_model = tuner2; tvee->tuner_formats = 0; tvee->tuner2_formats = 0; for (i = j = 0; i < 8; i++) { @@ -578,6 +614,12 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n", tvee->model, tvee->rev_str, tvee->serial_number); + if (tvee->has_MAC_address == 1) { + tveeprom_info("MAC address is %02X-%02X-%02X-%02X-%02X-%02X\n", + tvee->MAC_address[0], tvee->MAC_address[1], + tvee->MAC_address[2], tvee->MAC_address[3], + tvee->MAC_address[4], tvee->MAC_address[5]); + } tveeprom_info("tuner model is %s (idx %d, type %d)\n", t_name1, tuner1, tvee->tuner_type); tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index acfd3a103f3..9a6bf287e26 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -753,10 +753,9 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data, int retval; /* setup stuff */ - retval = -ENOMEM; q->read_buf = videobuf_alloc(q->msize); if (NULL == q->read_buf) - goto done; + return -ENOMEM; q->read_buf->memory = V4L2_MEMORY_USERPTR; q->read_buf->baddr = (unsigned long)data; @@ -817,10 +816,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, if (NULL == q->read_buf) goto done; q->read_buf->memory = V4L2_MEMORY_USERPTR; + q->read_buf->bsize = count; /* preferred size */ field = videobuf_next_field(q); retval = q->ops->buf_prepare(q,q->read_buf,field); - if (0 != retval) + if (0 != retval) { + kfree (q->read_buf); + q->read_buf = NULL; goto done; + } spin_lock_irqsave(q->irqlock,flags); q->ops->buf_queue(q,q->read_buf); spin_unlock_irqrestore(q->irqlock,flags); diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 83c49f9610d..6de5b0094b8 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -76,14 +76,14 @@ static void video_release(struct class_device *cd) } static struct class video_class = { - .name = VIDEO_NAME, + .name = VIDEO_NAME, .release = video_release, }; /* - * Active devices + * Active devices */ - + static struct video_device *video_device[VIDEO_NUM_DEVICES]; static DECLARE_MUTEX(videodev_lock); @@ -101,7 +101,7 @@ static int video_open(struct inode *inode, struct file *file) int err = 0; struct video_device *vfl; struct file_operations *old_fops; - + if(minor>=VIDEO_NUM_DEVICES) return -ENODEV; down(&videodev_lock); @@ -189,7 +189,7 @@ video_usercopy(struct inode *inode, struct file *file, return -ENOMEM; parg = mbuf; } - + err = -EFAULT; if (_IOC_DIR(cmd) & _IOC_WRITE) if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) @@ -240,7 +240,7 @@ int video_exclusive_open(struct inode *inode, struct file *file) int video_exclusive_release(struct inode *inode, struct file *file) { struct video_device *vfl = video_devdata(file); - + vfl->users--; return 0; } @@ -253,7 +253,7 @@ static struct file_operations video_fops; * @type: type of device to register * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... * -1 == first free) - * + * * The registration code assigns minor numbers based on the type * requested. -ENFILE is returned in all the device slots for this * category are full. If not then the minor field is set and the @@ -269,7 +269,7 @@ static struct file_operations video_fops; * * %VFL_TYPE_VBI - Vertical blank data (undecoded) * - * %VFL_TYPE_RADIO - A radio card + * %VFL_TYPE_RADIO - A radio card */ int video_register_device(struct video_device *vfd, int type, int nr) @@ -278,7 +278,7 @@ int video_register_device(struct video_device *vfd, int type, int nr) int base; int end; char *name_base; - + switch(type) { case VFL_TYPE_GRABBER: @@ -293,7 +293,7 @@ int video_register_device(struct video_device *vfd, int type, int nr) break; case VFL_TYPE_VBI: base=224; - end=240; + end=256; name_base = "vbi"; break; case VFL_TYPE_RADIO: @@ -334,7 +334,7 @@ int video_register_device(struct video_device *vfd, int type, int nr) init_MUTEX(&vfd->lock); /* sysfs class */ - memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); + memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); if (vfd->dev) vfd->class_dev.dev = vfd->dev; vfd->class_dev.class = &video_class; @@ -360,7 +360,7 @@ int video_register_device(struct video_device *vfd, int type, int nr) * This unregisters the passed device and deassigns the minor * number. Future open calls will be met with errors. */ - + void video_unregister_device(struct video_device *vfd) { down(&videodev_lock); @@ -384,7 +384,7 @@ static struct file_operations video_fops= /* * Initialise video for linux */ - + static int __init videodev_init(void) { int ret; diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 65c2ec5c421..4262a22adc2 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1118,6 +1118,65 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) return -1; } +int +mpt_alt_ioc_wait(MPT_ADAPTER *ioc) +{ + int loop_count = 30 * 4; /* Wait 30 seconds */ + int status = -1; /* -1 means failed to get board READY */ + + do { + spin_lock(&ioc->initializing_hba_lock); + if (ioc->initializing_hba_lock_flag == 0) { + ioc->initializing_hba_lock_flag=1; + spin_unlock(&ioc->initializing_hba_lock); + status = 0; + break; + } + spin_unlock(&ioc->initializing_hba_lock); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/4); + } while (--loop_count); + + return status; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_bringup_adapter - This is a wrapper function for mpt_do_ioc_recovery + * @ioc: Pointer to MPT adapter structure + * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. + * + * This routine performs all the steps necessary to bring the IOC + * to a OPERATIONAL state. + * + * Special Note: This function was added with spin lock's so as to allow + * the dv(domain validation) work thread to succeed on the other channel + * that maybe occuring at the same time when this function is called. + * Without this lock, the dv would fail when message frames were + * requested during hba bringup on the alternate ioc. + */ +static int +mpt_bringup_adapter(MPT_ADAPTER *ioc, int sleepFlag) +{ + int r; + + if(ioc->alt_ioc) { + if((r=mpt_alt_ioc_wait(ioc->alt_ioc)!=0)) + return r; + } + + r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, + CAN_SLEEP); + + if(ioc->alt_ioc) { + spin_lock(&ioc->alt_ioc->initializing_hba_lock); + ioc->alt_ioc->initializing_hba_lock_flag=0; + spin_unlock(&ioc->alt_ioc->initializing_hba_lock); + } + +return r; +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mpt_attach - Install a PCI intelligent MPT adapter. @@ -1186,6 +1245,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->pcidev = pdev; ioc->diagPending = 0; spin_lock_init(&ioc->diagLock); + spin_lock_init(&ioc->initializing_hba_lock); /* Initialize the event logging. */ @@ -1408,8 +1468,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) */ mpt_detect_bound_ports(ioc, pdev); - if ((r = mpt_do_ioc_recovery(ioc, - MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) { + if ((r = mpt_bringup_adapter(ioc, CAN_SLEEP)) != 0){ printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n", ioc->name, r); @@ -6298,6 +6357,7 @@ EXPORT_SYMBOL(mpt_read_ioc_pg_3); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); EXPORT_SYMBOL(mptbase_sas_persist_operation); +EXPORT_SYMBOL(mpt_alt_ioc_wait); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 5f5b3fb5b4d..bac8eb4186d 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -611,6 +611,8 @@ typedef struct _MPT_ADAPTER int DoneCtx; int TaskCtx; int InternalCtx; + spinlock_t initializing_hba_lock; + int initializing_hba_lock_flag; struct list_head list; struct net_device *netdev; struct list_head sas_topology; @@ -1001,6 +1003,7 @@ extern void mpt_free_fw_memory(MPT_ADAPTER *ioc); extern int mpt_findImVolumes(MPT_ADAPTER *ioc); extern int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); +extern int mpt_alt_ioc_wait(MPT_ADAPTER *ioc); /* * Public data decl's... diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 4330ed0ceda..b7b9846ff3f 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -4162,6 +4162,12 @@ mptscsih_domainValidation(void *arg) } } + if(mpt_alt_ioc_wait(hd->ioc)!=0) { + ddvprintk((MYIOC_s_WARN_FMT "alt_ioc busy!\n", + hd->ioc->name)); + continue; + } + if (mptscsih_doDv(hd, 0, id) == 1) { /* Untagged device was busy, try again */ @@ -4173,6 +4179,10 @@ mptscsih_domainValidation(void *arg) hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING); } + spin_lock(&hd->ioc->initializing_hba_lock); + hd->ioc->initializing_hba_lock_flag=0; + spin_unlock(&hd->ioc->initializing_hba_lock); + if (isPhysDisk) { for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { if (hd->ioc->raid_data.isRaid & (1 << ii)) { diff --git a/drivers/net/b44.c b/drivers/net/b44.c index c53848f787e..7aa49b974dc 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -28,8 +28,8 @@ #define DRV_MODULE_NAME "b44" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.96" -#define DRV_MODULE_RELDATE "Nov 8, 2005" +#define DRV_MODULE_VERSION "0.97" +#define DRV_MODULE_RELDATE "Nov 30, 2005" #define B44_DEF_MSG_ENABLE \ (NETIF_MSG_DRV | \ @@ -1417,6 +1417,7 @@ static int b44_open(struct net_device *dev) add_timer(&bp->timer); b44_enable_ints(bp); + netif_start_queue(dev); out: return err; } @@ -1837,12 +1838,15 @@ static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = if_mii(ifr); struct b44 *bp = netdev_priv(dev); - int err; + int err = -EINVAL; + + if (!netif_running(dev)) + goto out; spin_lock_irq(&bp->lock); err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL); spin_unlock_irq(&bp->lock); - +out: return err; } @@ -2113,6 +2117,7 @@ static int b44_resume(struct pci_dev *pdev) add_timer(&bp->timer); b44_enable_ints(bp); + netif_wake_queue(dev); return 0; } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 8b207f0e139..e0ae248b431 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2621,19 +2621,7 @@ e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb) E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) ) return 0; } - if(htons(ETH_P_IP) == skb->protocol) { - const struct iphdr *ip = skb->nh.iph; - if(IPPROTO_UDP == ip->protocol) { - struct udphdr *udp = (struct udphdr *)(skb->h.uh); - if(ntohs(udp->dest) == 67) { - offset = (uint8_t *)udp + 8 - skb->data; - length = skb->len - offset; - - return e1000_mng_write_dhcp_info(hw, - (uint8_t *)udp + 8, length); - } - } - } else if((skb->len > MINIMUM_DHCP_PACKET_SIZE) && (!skb->protocol)) { + if ((skb->len > MINIMUM_DHCP_PACKET_SIZE) && (!skb->protocol)) { struct ethhdr *eth = (struct ethhdr *) skb->data; if((htons(ETH_P_IP) == eth->h_proto)) { const struct iphdr *ip = diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index eb7d6947871..1da8a66f91e 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -65,7 +65,7 @@ */ #define DRV_NAME "emac" -#define DRV_VERSION "3.53" +#define DRV_VERSION "3.54" #define DRV_DESC "PPC 4xx OCP EMAC driver" MODULE_DESCRIPTION(DRV_DESC); @@ -158,6 +158,14 @@ static inline void emac_report_timeout_error(struct ocp_enet_private *dev, #define PHY_POLL_LINK_ON HZ #define PHY_POLL_LINK_OFF (HZ / 5) +/* Graceful stop timeouts in us. + * We should allow up to 1 frame time (full-duplex, ignoring collisions) + */ +#define STOP_TIMEOUT_10 1230 +#define STOP_TIMEOUT_100 124 +#define STOP_TIMEOUT_1000 13 +#define STOP_TIMEOUT_1000_JUMBO 73 + /* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", @@ -222,10 +230,12 @@ static void emac_tx_disable(struct ocp_enet_private *dev) r = in_be32(&p->mr0); if (r & EMAC_MR0_TXE) { - int n = 300; + int n = dev->stop_timeout; out_be32(&p->mr0, r & ~EMAC_MR0_TXE); - while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) + while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) { + udelay(1); --n; + } if (unlikely(!n)) emac_report_timeout_error(dev, "TX disable timeout"); } @@ -248,9 +258,11 @@ static void emac_rx_enable(struct ocp_enet_private *dev) if (!(r & EMAC_MR0_RXE)) { if (unlikely(!(r & EMAC_MR0_RXI))) { /* Wait if previous async disable is still in progress */ - int n = 100; - while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) + int n = dev->stop_timeout; + while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) { + udelay(1); --n; + } if (unlikely(!n)) emac_report_timeout_error(dev, "RX disable timeout"); @@ -273,10 +285,12 @@ static void emac_rx_disable(struct ocp_enet_private *dev) r = in_be32(&p->mr0); if (r & EMAC_MR0_RXE) { - int n = 300; + int n = dev->stop_timeout; out_be32(&p->mr0, r & ~EMAC_MR0_RXE); - while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) + while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) { + udelay(1); --n; + } if (unlikely(!n)) emac_report_timeout_error(dev, "RX disable timeout"); } @@ -395,6 +409,7 @@ static int emac_configure(struct ocp_enet_private *dev) r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST; if (dev->phy.duplex == DUPLEX_FULL) r |= EMAC_MR1_FDE; + dev->stop_timeout = STOP_TIMEOUT_10; switch (dev->phy.speed) { case SPEED_1000: if (emac_phy_gpcs(dev->phy.mode)) { @@ -409,12 +424,16 @@ static int emac_configure(struct ocp_enet_private *dev) r |= EMAC_MR1_MF_1000; r |= EMAC_MR1_RFS_16K; gige = 1; - - if (dev->ndev->mtu > ETH_DATA_LEN) + + if (dev->ndev->mtu > ETH_DATA_LEN) { r |= EMAC_MR1_JPSM; + dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO; + } else + dev->stop_timeout = STOP_TIMEOUT_1000; break; case SPEED_100: r |= EMAC_MR1_MF_100; + dev->stop_timeout = STOP_TIMEOUT_100; /* Fall through */ default: r |= EMAC_MR1_RFS_4K; @@ -2048,6 +2067,7 @@ static int __init emac_probe(struct ocp_device *ocpdev) dev->phy.duplex = DUPLEX_FULL; dev->phy.autoneg = AUTONEG_DISABLE; dev->phy.pause = dev->phy.asym_pause = 0; + dev->stop_timeout = STOP_TIMEOUT_100; init_timer(&dev->link_timer); dev->link_timer.function = emac_link_timer; dev->link_timer.data = (unsigned long)dev; diff --git a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h index e9b44d030ac..911abbaf471 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.h +++ b/drivers/net/ibm_emac/ibm_emac_core.h @@ -189,6 +189,8 @@ struct ocp_enet_private { struct timer_list link_timer; int reset_failed; + int stop_timeout; /* in us */ + struct ibm_emac_error_stats estats; struct net_device_stats nstats; diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index b039bd89ceb..272d331d29c 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -296,7 +296,7 @@ static int __init jazz_sonic_init_module(void) } jazz_sonic_device = platform_device_alloc(jazz_sonic_string, 0); - if (!jazz_sonnic_device) + if (!jazz_sonic_device) goto out_unregister; if (platform_device_add(jazz_sonic_device)) { @@ -307,7 +307,7 @@ static int __init jazz_sonic_init_module(void) return 0; out_unregister: - driver_unregister(&jazz_sonic_driver); + platform_driver_unregister(&jazz_sonic_driver); return -ENOMEM; } diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h index 878535953cb..026c732024c 100644 --- a/drivers/net/mipsnet.h +++ b/drivers/net/mipsnet.h @@ -1,28 +1,8 @@ -// -// <COPYRIGHT CLASS="1B" YEAR="2005"> -// Unpublished work (c) MIPS Technologies, Inc. All rights reserved. -// Unpublished rights reserved under the copyright laws of the U.S.A. and -// other countries. -// -// PROPRIETARY / SECRET CONFIDENTIAL INFORMATION OF MIPS TECHNOLOGIES, INC. -// FOR INTERNAL USE ONLY. -// -// Under no circumstances (contract or otherwise) may this information be -// disclosed to, or copied, modified or used by anyone other than employees -// or contractors of MIPS Technologies having a need to know. -// </COPYRIGHT> -// -//++ -// File: MIPS_Net.h -// -// Description: -// The definition of the emulated MIPSNET device's interface. -// -// Notes: This include file needs to work from a Linux device drivers. -// -//-- -// - +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ #ifndef __MIPSNET_H #define __MIPSNET_H diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 384a736a0d2..356f5090922 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -131,10 +131,9 @@ typedef struct local_info_t { u_short tx_queue_len; cardtype_t cardtype; u_short sent; - u_char mc_filter[8]; } local_info_t; -#define MC_FILTERBREAK 8 +#define MC_FILTERBREAK 64 /*====================================================================*/ /* @@ -1005,15 +1004,8 @@ static void fjn_reset(struct net_device *dev) for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + NODE_ID + i); - /* Switch to bank 1 */ - if (lp->cardtype == MBH10302) - outb(BANK_1, ioaddr + CONFIG_1); - else - outb(BANK_1U, ioaddr + CONFIG_1); - - /* set the multicast table to accept none. */ - for (i = 0; i < 8; i++) - outb(0x00, ioaddr + MAR_ADR + i); + /* (re)initialize the multicast table */ + set_rx_mode(dev); /* Switch to bank 2 (runtime mode) */ if (lp->cardtype == MBH10302) @@ -1264,11 +1256,11 @@ static struct net_device_stats *fjn_get_stats(struct net_device *dev) static void set_rx_mode(struct net_device *dev) { kio_addr_t ioaddr = dev->base_addr; - struct local_info_t *lp = netdev_priv(dev); u_char mc_filter[8]; /* Multicast hash filter */ u_long flags; int i; + int saved_bank; int saved_config_0 = inb(ioaddr + CONFIG_0); local_irq_save(flags); @@ -1306,15 +1298,13 @@ static void set_rx_mode(struct net_device *dev) outb(2, ioaddr + RX_MODE); /* Use normal mode. */ } - if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) { - int saved_bank = inb(ioaddr + CONFIG_1); - /* Switch to bank 1 and set the multicast table. */ - outb(0xe4, ioaddr + CONFIG_1); - for (i = 0; i < 8; i++) - outb(mc_filter[i], ioaddr + MAR_ADR + i); - memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter)); - outb(saved_bank, ioaddr + CONFIG_1); - } + /* Switch to bank 1 and set the multicast table. */ + saved_bank = inb(ioaddr + CONFIG_1); + outb(0xe4, ioaddr + CONFIG_1); + + for (i = 0; i < 8; i++) + outb(mc_filter[i], ioaddr + MAR_ADR + i); + outb(saved_bank, ioaddr + CONFIG_1); outb(saved_config_0, ioaddr + CONFIG_0); diff --git a/drivers/net/sk98lin/Makefile b/drivers/net/sk98lin/Makefile index 6783039ffb7..7653d6e33aa 100644 --- a/drivers/net/sk98lin/Makefile +++ b/drivers/net/sk98lin/Makefile @@ -27,8 +27,7 @@ sk98lin-objs := \ sktimer.o \ skvpd.o \ skxmac2.o \ - skproc.o \ - skcsum.o + skproc.o # DBGDEF = \ # -DDEBUG @@ -77,7 +76,7 @@ endif # SK_DBGCAT_DRV_INT_SRC 0x04000000 interrupts sources # SK_DBGCAT_DRV_EVENT 0x08000000 driver events -EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DSK_USE_CSUM -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM) +EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM) clean: rm -f core *.o *.a *.s diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h index 542cec57f86..2dc5728e3ef 100644 --- a/drivers/net/sk98lin/h/skdrv2nd.h +++ b/drivers/net/sk98lin/h/skdrv2nd.h @@ -425,10 +425,6 @@ struct s_AC { TX_PORT TxPort[SK_MAX_MACS][2]; RX_PORT RxPort[SK_MAX_MACS]; - unsigned int CsOfs1; /* for checksum calculation */ - unsigned int CsOfs2; /* for checksum calculation */ - SK_U32 CsOfs; /* for checksum calculation */ - SK_BOOL CheckQueue; /* check event queue soon */ SK_TIMER DrvCleanupTimer;/* to check for pending descriptors */ DIM_INFO DynIrqModInfo; /* all data related to DIM */ diff --git a/drivers/net/sk98lin/skcsum.c b/drivers/net/sk98lin/skcsum.c deleted file mode 100644 index 38a6e7a631f..00000000000 --- a/drivers/net/sk98lin/skcsum.c +++ /dev/null @@ -1,871 +0,0 @@ -/****************************************************************************** - * - * Name: skcsum.c - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.12 $ - * Date: $Date: 2003/08/20 13:55:53 $ - * Purpose: Store/verify Internet checksum in send/receive packets. - * - ******************************************************************************/ - -/****************************************************************************** - * - * (C)Copyright 1998-2003 SysKonnect GmbH. - * - * 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. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifdef SK_USE_CSUM /* Check if CSUM is to be used. */ - -#ifndef lint -static const char SysKonnectFileId[] = - "@(#) $Id: skcsum.c,v 1.12 2003/08/20 13:55:53 mschmid Exp $ (C) SysKonnect."; -#endif /* !lint */ - -/****************************************************************************** - * - * Description: - * - * This is the "GEnesis" common module "CSUM". - * - * This module contains the code necessary to calculate, store, and verify the - * Internet Checksum of IP, TCP, and UDP frames. - * - * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon" - * and is the code name of this SysKonnect project. - * - * Compilation Options: - * - * SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an - * empty module. - * - * SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id - * definitions. In this case, all SKCS_PROTO_xxx definitions must be made - * external. - * - * SKCS_OVERWRITE_STATUS - Define to overwrite the default return status - * definitions. In this case, all SKCS_STATUS_xxx definitions must be made - * external. - * - * Include File Hierarchy: - * - * "h/skdrv1st.h" - * "h/skcsum.h" - * "h/sktypes.h" - * "h/skqueue.h" - * "h/skdrv2nd.h" - * - ******************************************************************************/ - -#include "h/skdrv1st.h" -#include "h/skcsum.h" -#include "h/skdrv2nd.h" - -/* defines ********************************************************************/ - -/* The size of an Ethernet MAC header. */ -#define SKCS_ETHERNET_MAC_HEADER_SIZE (6+6+2) - -/* The size of the used topology's MAC header. */ -#define SKCS_MAC_HEADER_SIZE SKCS_ETHERNET_MAC_HEADER_SIZE - -/* The size of the IP header without any option fields. */ -#define SKCS_IP_HEADER_SIZE 20 - -/* - * Field offsets within the IP header. - */ - -/* "Internet Header Version" and "Length". */ -#define SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH 0 - -/* "Total Length". */ -#define SKCS_OFS_IP_TOTAL_LENGTH 2 - -/* "Flags" "Fragment Offset". */ -#define SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET 6 - -/* "Next Level Protocol" identifier. */ -#define SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL 9 - -/* Source IP address. */ -#define SKCS_OFS_IP_SOURCE_ADDRESS 12 - -/* Destination IP address. */ -#define SKCS_OFS_IP_DESTINATION_ADDRESS 16 - - -/* - * Field offsets within the UDP header. - */ - -/* UDP checksum. */ -#define SKCS_OFS_UDP_CHECKSUM 6 - -/* IP "Next Level Protocol" identifiers (see RFC 790). */ -#define SKCS_PROTO_ID_TCP 6 /* Transport Control Protocol */ -#define SKCS_PROTO_ID_UDP 17 /* User Datagram Protocol */ - -/* IP "Don't Fragment" bit. */ -#define SKCS_IP_DONT_FRAGMENT SKCS_HTON16(0x4000) - -/* Add a byte offset to a pointer. */ -#define SKCS_IDX(pPtr, Ofs) ((void *) ((char *) (pPtr) + (Ofs))) - -/* - * Macros that convert host to network representation and vice versa, i.e. - * little/big endian conversion on little endian machines only. - */ -#ifdef SK_LITTLE_ENDIAN -#define SKCS_HTON16(Val16) (((unsigned) (Val16) >> 8) | (((Val16) & 0xff) << 8)) -#endif /* SK_LITTLE_ENDIAN */ -#ifdef SK_BIG_ENDIAN -#define SKCS_HTON16(Val16) (Val16) -#endif /* SK_BIG_ENDIAN */ -#define SKCS_NTOH16(Val16) SKCS_HTON16(Val16) - -/* typedefs *******************************************************************/ - -/* function prototypes ********************************************************/ - -/****************************************************************************** - * - * SkCsGetSendInfo - get checksum information for a send packet - * - * Description: - * Get all checksum information necessary to send a TCP or UDP packet. The - * function checks the IP header passed to it. If the high-level protocol - * is either TCP or UDP the pseudo header checksum is calculated and - * returned. - * - * The function returns the total length of the IP header (including any - * IP option fields), which is the same as the start offset of the IP data - * which in turn is the start offset of the TCP or UDP header. - * - * The function also returns the TCP or UDP pseudo header checksum, which - * should be used as the start value for the hardware checksum calculation. - * (Note that any actual pseudo header checksum can never calculate to - * zero.) - * - * Note: - * There is a bug in the GENESIS ASIC which may lead to wrong checksums. - * - * Arguments: - * pAc - A pointer to the adapter context struct. - * - * pIpHeader - Pointer to IP header. Must be at least the IP header *not* - * including any option fields, i.e. at least 20 bytes. - * - * Note: This pointer will be used to address 8-, 16-, and 32-bit - * variables with the respective alignment offsets relative to the pointer. - * Thus, the pointer should point to a 32-bit aligned address. If the - * target system cannot address 32-bit variables on non 32-bit aligned - * addresses, then the pointer *must* point to a 32-bit aligned address. - * - * pPacketInfo - A pointer to the packet information structure for this - * packet. Before calling this SkCsGetSendInfo(), the following field must - * be initialized: - * - * ProtocolFlags - Initialize with any combination of - * SKCS_PROTO_XXX bit flags. SkCsGetSendInfo() will only work on - * the protocols specified here. Any protocol(s) not specified - * here will be ignored. - * - * Note: Only one checksum can be calculated in hardware. Thus, if - * SKCS_PROTO_IP is specified in the 'ProtocolFlags', - * SkCsGetSendInfo() must calculate the IP header checksum in - * software. It might be a better idea to have the calling - * protocol stack calculate the IP header checksum. - * - * Returns: N/A - * On return, the following fields in 'pPacketInfo' may or may not have - * been filled with information, depending on the protocol(s) found in the - * packet: - * - * ProtocolFlags - Returns the SKCS_PROTO_XXX bit flags of the protocol(s) - * that were both requested by the caller and actually found in the packet. - * Protocol(s) not specified by the caller and/or not found in the packet - * will have their respective SKCS_PROTO_XXX bit flags reset. - * - * Note: For IP fragments, TCP and UDP packet information is ignored. - * - * IpHeaderLength - The total length in bytes of the complete IP header - * including any option fields is returned here. This is the start offset - * of the IP data, i.e. the TCP or UDP header if present. - * - * IpHeaderChecksum - If IP has been specified in the 'ProtocolFlags', the - * 16-bit Internet Checksum of the IP header is returned here. This value - * is to be stored into the packet's 'IP Header Checksum' field. - * - * PseudoHeaderChecksum - If this is a TCP or UDP packet and if TCP or UDP - * has been specified in the 'ProtocolFlags', the 16-bit Internet Checksum - * of the TCP or UDP pseudo header is returned here. - */ -void SkCsGetSendInfo( -SK_AC *pAc, /* Adapter context struct. */ -void *pIpHeader, /* IP header. */ -SKCS_PACKET_INFO *pPacketInfo, /* Packet information struct. */ -int NetNumber) /* Net number */ -{ - /* Internet Header Version found in IP header. */ - unsigned InternetHeaderVersion; - - /* Length of the IP header as found in IP header. */ - unsigned IpHeaderLength; - - /* Bit field specifiying the desired/found protocols. */ - unsigned ProtocolFlags; - - /* Next level protocol identifier found in IP header. */ - unsigned NextLevelProtocol; - - /* Length of IP data portion. */ - unsigned IpDataLength; - - /* TCP/UDP pseudo header checksum. */ - unsigned long PseudoHeaderChecksum; - - /* Pointer to next level protocol statistics structure. */ - SKCS_PROTO_STATS *NextLevelProtoStats; - - /* Temporary variable. */ - unsigned Tmp; - - Tmp = *(SK_U8 *) - SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH); - - /* Get the Internet Header Version (IHV). */ - /* Note: The IHV is stored in the upper four bits. */ - - InternetHeaderVersion = Tmp >> 4; - - /* Check the Internet Header Version. */ - /* Note: We currently only support IP version 4. */ - - if (InternetHeaderVersion != 4) { /* IPv4? */ - SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX, - ("Tx: Unknown Internet Header Version %u.\n", - InternetHeaderVersion)); - pPacketInfo->ProtocolFlags = 0; - pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++; - return; - } - - /* Get the IP header length (IHL). */ - /* - * Note: The IHL is stored in the lower four bits as the number of - * 4-byte words. - */ - - IpHeaderLength = (Tmp & 0xf) * 4; - pPacketInfo->IpHeaderLength = IpHeaderLength; - - /* Check the IP header length. */ - - /* 04-Aug-1998 sw - Really check the IHL? Necessary? */ - - if (IpHeaderLength < 5*4) { - SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX, - ("Tx: Invalid IP Header Length %u.\n", IpHeaderLength)); - pPacketInfo->ProtocolFlags = 0; - pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++; - return; - } - - /* This is an IPv4 frame with a header of valid length. */ - - pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxOkCts++; - - /* Check if we should calculate the IP header checksum. */ - - ProtocolFlags = pPacketInfo->ProtocolFlags; - - if (ProtocolFlags & SKCS_PROTO_IP) { - pPacketInfo->IpHeaderChecksum = - SkCsCalculateChecksum(pIpHeader, IpHeaderLength); - } - - /* Get the next level protocol identifier. */ - - NextLevelProtocol = - *(SK_U8 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL); - - /* - * Check if this is a TCP or UDP frame and if we should calculate the - * TCP/UDP pseudo header checksum. - * - * Also clear all protocol bit flags of protocols not present in the - * frame. - */ - - if ((ProtocolFlags & SKCS_PROTO_TCP) != 0 && - NextLevelProtocol == SKCS_PROTO_ID_TCP) { - /* TCP/IP frame. */ - ProtocolFlags &= SKCS_PROTO_TCP | SKCS_PROTO_IP; - NextLevelProtoStats = - &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP]; - } - else if ((ProtocolFlags & SKCS_PROTO_UDP) != 0 && - NextLevelProtocol == SKCS_PROTO_ID_UDP) { - /* UDP/IP frame. */ - ProtocolFlags &= SKCS_PROTO_UDP | SKCS_PROTO_IP; - NextLevelProtoStats = - &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP]; - } - else { - /* - * Either not a TCP or UDP frame and/or TCP/UDP processing not - * specified. - */ - pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP; - return; - } - - /* Check if this is an IP fragment. */ - - /* - * Note: An IP fragment has a non-zero "Fragment Offset" field and/or - * the "More Fragments" bit set. Thus, if both the "Fragment Offset" - * and the "More Fragments" are zero, it is *not* a fragment. We can - * easily check both at the same time since they are in the same 16-bit - * word. - */ - - if ((*(SK_U16 *) - SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) & - ~SKCS_IP_DONT_FRAGMENT) != 0) { - /* IP fragment; ignore all other protocols. */ - pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP; - NextLevelProtoStats->TxUnableCts++; - return; - } - - /* - * Calculate the TCP/UDP pseudo header checksum. - */ - - /* Get total length of IP header and data. */ - - IpDataLength = - *(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH); - - /* Get length of IP data portion. */ - - IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength; - - /* Calculate the sum of all pseudo header fields (16-bit). */ - - PseudoHeaderChecksum = - (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, - SKCS_OFS_IP_SOURCE_ADDRESS + 0) + - (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, - SKCS_OFS_IP_SOURCE_ADDRESS + 2) + - (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, - SKCS_OFS_IP_DESTINATION_ADDRESS + 0) + - (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, - SKCS_OFS_IP_DESTINATION_ADDRESS + 2) + - (unsigned long) SKCS_HTON16(NextLevelProtocol) + - (unsigned long) SKCS_HTON16(IpDataLength); - - /* Add-in any carries. */ - - SKCS_OC_ADD(PseudoHeaderChecksum, PseudoHeaderChecksum, 0); - - /* Add-in any new carry. */ - - SKCS_OC_ADD(pPacketInfo->PseudoHeaderChecksum, PseudoHeaderChecksum, 0); - - pPacketInfo->ProtocolFlags = ProtocolFlags; - NextLevelProtoStats->TxOkCts++; /* Success. */ -} /* SkCsGetSendInfo */ - - -/****************************************************************************** - * - * SkCsGetReceiveInfo - verify checksum information for a received packet - * - * Description: - * Verify a received frame's checksum. The function returns a status code - * reflecting the result of the verification. - * - * Note: - * Before calling this function you have to verify that the frame is - * not padded and Checksum1 and Checksum2 are bigger than 1. - * - * Arguments: - * pAc - Pointer to adapter context struct. - * - * pIpHeader - Pointer to IP header. Must be at least the length in bytes - * of the received IP header including any option fields. For UDP packets, - * 8 additional bytes are needed to access the UDP checksum. - * - * Note: The actual length of the IP header is stored in the lower four - * bits of the first octet of the IP header as the number of 4-byte words, - * so it must be multiplied by four to get the length in bytes. Thus, the - * maximum IP header length is 15 * 4 = 60 bytes. - * - * Checksum1 - The first 16-bit Internet Checksum calculated by the - * hardware starting at the offset returned by SkCsSetReceiveFlags(). - * - * Checksum2 - The second 16-bit Internet Checksum calculated by the - * hardware starting at the offset returned by SkCsSetReceiveFlags(). - * - * Returns: - * SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame. - * SKCS_STATUS_IP_CSUM_ERROR - IP checksum error. - * SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame. - * SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame - * SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok). - * SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame). - * SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok). - * SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok). - * SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok. - * SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok. - * SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum. - * - * Note: If SKCS_OVERWRITE_STATUS is defined, the SKCS_STATUS_XXX values - * returned here can be defined in some header file by the module using CSUM. - * In this way, the calling module can assign return values for its own needs, - * e.g. by assigning bit flags to the individual protocols. - */ -SKCS_STATUS SkCsGetReceiveInfo( -SK_AC *pAc, /* Adapter context struct. */ -void *pIpHeader, /* IP header. */ -unsigned Checksum1, /* Hardware checksum 1. */ -unsigned Checksum2, /* Hardware checksum 2. */ -int NetNumber) /* Net number */ -{ - /* Internet Header Version found in IP header. */ - unsigned InternetHeaderVersion; - - /* Length of the IP header as found in IP header. */ - unsigned IpHeaderLength; - - /* Length of IP data portion. */ - unsigned IpDataLength; - - /* IP header checksum. */ - unsigned IpHeaderChecksum; - - /* IP header options checksum, if any. */ - unsigned IpOptionsChecksum; - - /* IP data checksum, i.e. TCP/UDP checksum. */ - unsigned IpDataChecksum; - - /* Next level protocol identifier found in IP header. */ - unsigned NextLevelProtocol; - - /* The checksum of the "next level protocol", i.e. TCP or UDP. */ - unsigned long NextLevelProtocolChecksum; - - /* Pointer to next level protocol statistics structure. */ - SKCS_PROTO_STATS *NextLevelProtoStats; - - /* Temporary variable. */ - unsigned Tmp; - - Tmp = *(SK_U8 *) - SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH); - - /* Get the Internet Header Version (IHV). */ - /* Note: The IHV is stored in the upper four bits. */ - - InternetHeaderVersion = Tmp >> 4; - - /* Check the Internet Header Version. */ - /* Note: We currently only support IP version 4. */ - - if (InternetHeaderVersion != 4) { /* IPv4? */ - SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX, - ("Rx: Unknown Internet Header Version %u.\n", - InternetHeaderVersion)); - pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++; - return (SKCS_STATUS_UNKNOWN_IP_VERSION); - } - - /* Get the IP header length (IHL). */ - /* - * Note: The IHL is stored in the lower four bits as the number of - * 4-byte words. - */ - - IpHeaderLength = (Tmp & 0xf) * 4; - - /* Check the IP header length. */ - - /* 04-Aug-1998 sw - Really check the IHL? Necessary? */ - - if (IpHeaderLength < 5*4) { - SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX, - ("Rx: Invalid IP Header Length %u.\n", IpHeaderLength)); - pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++; - return (SKCS_STATUS_IP_CSUM_ERROR); - } - - /* This is an IPv4 frame with a header of valid length. */ - - /* Get the IP header and data checksum. */ - - IpDataChecksum = Checksum2; - - /* - * The IP header checksum is calculated as follows: - * - * IpHeaderChecksum = Checksum1 - Checksum2 - */ - - SKCS_OC_SUB(IpHeaderChecksum, Checksum1, Checksum2); - - /* Check if any IP header options. */ - - if (IpHeaderLength > SKCS_IP_HEADER_SIZE) { - - /* Get the IP options checksum. */ - - IpOptionsChecksum = SkCsCalculateChecksum( - SKCS_IDX(pIpHeader, SKCS_IP_HEADER_SIZE), - IpHeaderLength - SKCS_IP_HEADER_SIZE); - - /* Adjust the IP header and IP data checksums. */ - - SKCS_OC_ADD(IpHeaderChecksum, IpHeaderChecksum, IpOptionsChecksum); - - SKCS_OC_SUB(IpDataChecksum, IpDataChecksum, IpOptionsChecksum); - } - - /* - * Check if the IP header checksum is ok. - * - * NOTE: We must check the IP header checksum even if the caller just wants - * us to check upper-layer checksums, because we cannot do any further - * processing of the packet without a valid IP checksum. - */ - - /* Get the next level protocol identifier. */ - - NextLevelProtocol = *(SK_U8 *) - SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL); - - if (IpHeaderChecksum != 0xffff) { - pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++; - /* the NDIS tester wants to know the upper level protocol too */ - if (NextLevelProtocol == SKCS_PROTO_ID_TCP) { - return(SKCS_STATUS_IP_CSUM_ERROR_TCP); - } - else if (NextLevelProtocol == SKCS_PROTO_ID_UDP) { - return(SKCS_STATUS_IP_CSUM_ERROR_UDP); - } - return (SKCS_STATUS_IP_CSUM_ERROR); - } - - /* - * Check if this is a TCP or UDP frame and if we should calculate the - * TCP/UDP pseudo header checksum. - * - * Also clear all protocol bit flags of protocols not present in the - * frame. - */ - - if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_TCP) != 0 && - NextLevelProtocol == SKCS_PROTO_ID_TCP) { - /* TCP/IP frame. */ - NextLevelProtoStats = - &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP]; - } - else if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_UDP) != 0 && - NextLevelProtocol == SKCS_PROTO_ID_UDP) { - /* UDP/IP frame. */ - NextLevelProtoStats = - &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP]; - } - else { - /* - * Either not a TCP or UDP frame and/or TCP/UDP processing not - * specified. - */ - return (SKCS_STATUS_IP_CSUM_OK); - } - - /* Check if this is an IP fragment. */ - - /* - * Note: An IP fragment has a non-zero "Fragment Offset" field and/or - * the "More Fragments" bit set. Thus, if both the "Fragment Offset" - * and the "More Fragments" are zero, it is *not* a fragment. We can - * easily check both at the same time since they are in the same 16-bit - * word. - */ - - if ((*(SK_U16 *) - SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) & - ~SKCS_IP_DONT_FRAGMENT) != 0) { - /* IP fragment; ignore all other protocols. */ - NextLevelProtoStats->RxUnableCts++; - return (SKCS_STATUS_IP_FRAGMENT); - } - - /* - * 08-May-2000 ra - * - * From RFC 768 (UDP) - * If the computed checksum is zero, it is transmitted as all ones (the - * equivalent in one's complement arithmetic). An all zero transmitted - * checksum value means that the transmitter generated no checksum (for - * debugging or for higher level protocols that don't care). - */ - - if (NextLevelProtocol == SKCS_PROTO_ID_UDP && - *(SK_U16*)SKCS_IDX(pIpHeader, IpHeaderLength + 6) == 0x0000) { - - NextLevelProtoStats->RxOkCts++; - - return (SKCS_STATUS_IP_CSUM_OK_NO_UDP); - } - - /* - * Calculate the TCP/UDP checksum. - */ - - /* Get total length of IP header and data. */ - - IpDataLength = - *(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH); - - /* Get length of IP data portion. */ - - IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength; - - NextLevelProtocolChecksum = - - /* Calculate the pseudo header checksum. */ - - (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, - SKCS_OFS_IP_SOURCE_ADDRESS + 0) + - (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, - SKCS_OFS_IP_SOURCE_ADDRESS + 2) + - (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, - SKCS_OFS_IP_DESTINATION_ADDRESS + 0) + - (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, - SKCS_OFS_IP_DESTINATION_ADDRESS + 2) + - (unsigned long) SKCS_HTON16(NextLevelProtocol) + - (unsigned long) SKCS_HTON16(IpDataLength) + - - /* Add the TCP/UDP header checksum. */ - - (unsigned long) IpDataChecksum; - - /* Add-in any carries. */ - - SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0); - - /* Add-in any new carry. */ - - SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0); - - /* Check if the TCP/UDP checksum is ok. */ - - if ((unsigned) NextLevelProtocolChecksum == 0xffff) { - - /* TCP/UDP checksum ok. */ - - NextLevelProtoStats->RxOkCts++; - - return (NextLevelProtocol == SKCS_PROTO_ID_TCP ? - SKCS_STATUS_TCP_CSUM_OK : SKCS_STATUS_UDP_CSUM_OK); - } - - /* TCP/UDP checksum error. */ - - NextLevelProtoStats->RxErrCts++; - - return (NextLevelProtocol == SKCS_PROTO_ID_TCP ? - SKCS_STATUS_TCP_CSUM_ERROR : SKCS_STATUS_UDP_CSUM_ERROR); -} /* SkCsGetReceiveInfo */ - - -/****************************************************************************** - * - * SkCsSetReceiveFlags - set checksum receive flags - * - * Description: - * Use this function to set the various receive flags. According to the - * protocol flags set by the caller, the start offsets within received - * packets of the two hardware checksums are returned. These offsets must - * be stored in all receive descriptors. - * - * Arguments: - * pAc - Pointer to adapter context struct. - * - * ReceiveFlags - Any combination of SK_PROTO_XXX flags of the protocols - * for which the caller wants checksum information on received frames. - * - * pChecksum1Offset - The start offset of the first receive descriptor - * hardware checksum to be calculated for received frames is returned - * here. - * - * pChecksum2Offset - The start offset of the second receive descriptor - * hardware checksum to be calculated for received frames is returned - * here. - * - * Returns: N/A - * Returns the two hardware checksum start offsets. - */ -void SkCsSetReceiveFlags( -SK_AC *pAc, /* Adapter context struct. */ -unsigned ReceiveFlags, /* New receive flags. */ -unsigned *pChecksum1Offset, /* Offset for hardware checksum 1. */ -unsigned *pChecksum2Offset, /* Offset for hardware checksum 2. */ -int NetNumber) -{ - /* Save the receive flags. */ - - pAc->Csum.ReceiveFlags[NetNumber] = ReceiveFlags; - - /* First checksum start offset is the IP header. */ - *pChecksum1Offset = SKCS_MAC_HEADER_SIZE; - - /* - * Second checksum start offset is the IP data. Note that this may vary - * if there are any IP header options in the actual packet. - */ - *pChecksum2Offset = SKCS_MAC_HEADER_SIZE + SKCS_IP_HEADER_SIZE; -} /* SkCsSetReceiveFlags */ - -#ifndef SK_CS_CALCULATE_CHECKSUM - -/****************************************************************************** - * - * SkCsCalculateChecksum - calculate checksum for specified data - * - * Description: - * Calculate and return the 16-bit Internet Checksum for the specified - * data. - * - * Arguments: - * pData - Pointer to data for which the checksum shall be calculated. - * Note: The pointer should be aligned on a 16-bit boundary. - * - * Length - Length in bytes of data to checksum. - * - * Returns: - * The 16-bit Internet Checksum for the specified data. - * - * Note: The checksum is calculated in the machine's natural byte order, - * i.e. little vs. big endian. Thus, the resulting checksum is different - * for the same input data on little and big endian machines. - * - * However, when written back to the network packet, the byte order is - * always in correct network order. - */ -unsigned SkCsCalculateChecksum( -void *pData, /* Data to checksum. */ -unsigned Length) /* Length of data. */ -{ - SK_U16 *pU16; /* Pointer to the data as 16-bit words. */ - unsigned long Checksum; /* Checksum; must be at least 32 bits. */ - - /* Sum up all 16-bit words. */ - - pU16 = (SK_U16 *) pData; - for (Checksum = 0; Length > 1; Length -= 2) { - Checksum += *pU16++; - } - - /* If this is an odd number of bytes, add-in the last byte. */ - - if (Length > 0) { -#ifdef SK_BIG_ENDIAN - /* Add the last byte as the high byte. */ - Checksum += ((unsigned) *(SK_U8 *) pU16) << 8; -#else /* !SK_BIG_ENDIAN */ - /* Add the last byte as the low byte. */ - Checksum += *(SK_U8 *) pU16; -#endif /* !SK_BIG_ENDIAN */ - } - - /* Add-in any carries. */ - - SKCS_OC_ADD(Checksum, Checksum, 0); - - /* Add-in any new carry. */ - - SKCS_OC_ADD(Checksum, Checksum, 0); - - /* Note: All bits beyond the 16-bit limit are now zero. */ - - return ((unsigned) Checksum); -} /* SkCsCalculateChecksum */ - -#endif /* SK_CS_CALCULATE_CHECKSUM */ - -/****************************************************************************** - * - * SkCsEvent - the CSUM event dispatcher - * - * Description: - * This is the event handler for the CSUM module. - * - * Arguments: - * pAc - Pointer to adapter context. - * - * Ioc - I/O context. - * - * Event - Event id. - * - * Param - Event dependent parameter. - * - * Returns: - * The 16-bit Internet Checksum for the specified data. - * - * Note: The checksum is calculated in the machine's natural byte order, - * i.e. little vs. big endian. Thus, the resulting checksum is different - * for the same input data on little and big endian machines. - * - * However, when written back to the network packet, the byte order is - * always in correct network order. - */ -int SkCsEvent( -SK_AC *pAc, /* Pointer to adapter context. */ -SK_IOC Ioc, /* I/O context. */ -SK_U32 Event, /* Event id. */ -SK_EVPARA Param) /* Event dependent parameter. */ -{ - int ProtoIndex; - int NetNumber; - - switch (Event) { - /* - * Clear protocol statistics. - * - * Param - Protocol index, or -1 for all protocols. - * - Net number. - */ - case SK_CSUM_EVENT_CLEAR_PROTO_STATS: - - ProtoIndex = (int)Param.Para32[1]; - NetNumber = (int)Param.Para32[0]; - if (ProtoIndex < 0) { /* Clear for all protocols. */ - if (NetNumber >= 0) { - SK_MEMSET(&pAc->Csum.ProtoStats[NetNumber][0], 0, - sizeof(pAc->Csum.ProtoStats[NetNumber])); - } - } - else { /* Clear for individual protocol. */ - SK_MEMSET(&pAc->Csum.ProtoStats[NetNumber][ProtoIndex], 0, - sizeof(pAc->Csum.ProtoStats[NetNumber][ProtoIndex])); - } - break; - default: - break; - } - return (0); /* Success. */ -} /* SkCsEvent */ - -#endif /* SK_USE_CSUM */ diff --git a/drivers/net/sk98lin/skethtool.c b/drivers/net/sk98lin/skethtool.c index fb639959292..b71769ae460 100644 --- a/drivers/net/sk98lin/skethtool.c +++ b/drivers/net/sk98lin/skethtool.c @@ -549,4 +549,6 @@ struct ethtool_ops SkGeEthtoolOps = { .phys_id = locateDevice, .get_pauseparam = getPauseParams, .set_pauseparam = setPauseParams, + .get_link = ethtool_op_get_link, + .get_perm_addr = ethtool_op_get_perm_addr, }; diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index b18c92cb629..00c5d7f04c6 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -101,7 +101,6 @@ * "h/skgeinit.h" * "h/skaddr.h" * "h/skgesirq.h" - * "h/skcsum.h" * "h/skrlmt.h" * ******************************************************************************/ @@ -113,6 +112,7 @@ #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/dma-mapping.h> +#include <linux/ip.h> #include "h/skdrv1st.h" #include "h/skdrv2nd.h" @@ -601,11 +601,6 @@ SK_BOOL DualNet; return(-EAGAIN); } - SkCsSetReceiveFlags(pAC, - SKCS_PROTO_IP | SKCS_PROTO_TCP | SKCS_PROTO_UDP, - &pAC->CsOfs1, &pAC->CsOfs2, 0); - pAC->CsOfs = (pAC->CsOfs2 << 16) | pAC->CsOfs1; - BoardInitMem(pAC); /* tschilling: New common function with minimum size check. */ DualNet = SK_FALSE; @@ -823,7 +818,7 @@ uintptr_t VNextDescr; /* the virtual bus address of the next descriptor */ /* set the pointers right */ pDescr->VNextRxd = VNextDescr & 0xffffffffULL; pDescr->pNextRxd = pNextDescr; - pDescr->TcpSumStarts = pAC->CsOfs; + pDescr->TcpSumStarts = 0; /* advance one step */ pPrevDescr = pDescr; @@ -1505,8 +1500,6 @@ struct sk_buff *pMessage) /* pointer to send-message */ TXD *pOldTxd; unsigned long Flags; SK_U64 PhysAddr; - int Protocol; - int IpHeaderLength; int BytesSend = pMessage->len; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("X")); @@ -1579,8 +1572,10 @@ struct sk_buff *pMessage) /* pointer to send-message */ pTxd->pMBuf = pMessage; if (pMessage->ip_summed == CHECKSUM_HW) { - Protocol = ((SK_U8)pMessage->data[C_OFFSET_IPPROTO] & 0xff); - if ((Protocol == C_PROTO_ID_UDP) && + u16 hdrlen = pMessage->h.raw - pMessage->data; + u16 offset = hdrlen + pMessage->csum; + + if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) && (pAC->GIni.GIChipRev == 0) && (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { pTxd->TBControl = BMU_TCP_CHECK; @@ -1588,14 +1583,9 @@ struct sk_buff *pMessage) /* pointer to send-message */ pTxd->TBControl = BMU_UDP_CHECK; } - IpHeaderLength = (SK_U8)pMessage->data[C_OFFSET_IPHEADER]; - IpHeaderLength = (IpHeaderLength & 0xf) * 4; - pTxd->TcpSumOfs = 0; /* PH-Checksum already calculated */ - pTxd->TcpSumSt = C_LEN_ETHERMAC_HEADER + IpHeaderLength + - (Protocol == C_PROTO_ID_UDP ? - C_OFFSET_UDPHEADER_UDPCS : - C_OFFSET_TCPHEADER_TCPCS); - pTxd->TcpSumWr = C_LEN_ETHERMAC_HEADER + IpHeaderLength; + pTxd->TcpSumOfs = 0; + pTxd->TcpSumSt = hdrlen; + pTxd->TcpSumWr = offset; pTxd->TBControl |= BMU_OWN | BMU_STF | BMU_SW | BMU_EOF | @@ -1658,11 +1648,10 @@ struct sk_buff *pMessage) /* pointer to send-message */ TXD *pTxdLst; int CurrFrag; int BytesSend; - int IpHeaderLength; - int Protocol; skb_frag_t *sk_frag; SK_U64 PhysAddr; unsigned long Flags; + SK_U32 Control; spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); #ifndef USE_TX_COMPLETE @@ -1685,7 +1674,6 @@ struct sk_buff *pMessage) /* pointer to send-message */ pTxdFst = pTxd; pTxdLst = pTxd; BytesSend = 0; - Protocol = 0; /* ** Map the first fragment (header) into the DMA-space @@ -1703,32 +1691,31 @@ struct sk_buff *pMessage) /* pointer to send-message */ ** Does the HW need to evaluate checksum for TCP or UDP packets? */ if (pMessage->ip_summed == CHECKSUM_HW) { - pTxd->TBControl = BMU_STF | BMU_STFWD | skb_headlen(pMessage); + u16 hdrlen = pMessage->h.raw - pMessage->data; + u16 offset = hdrlen + pMessage->csum; + + Control = BMU_STFWD; + /* ** We have to use the opcode for tcp here, because the ** opcode for udp is not working in the hardware yet ** (Revision 2.0) */ - Protocol = ((SK_U8)pMessage->data[C_OFFSET_IPPROTO] & 0xff); - if ((Protocol == C_PROTO_ID_UDP) && + if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) && (pAC->GIni.GIChipRev == 0) && (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { - pTxd->TBControl |= BMU_TCP_CHECK; + Control |= BMU_TCP_CHECK; } else { - pTxd->TBControl |= BMU_UDP_CHECK; + Control |= BMU_UDP_CHECK; } - IpHeaderLength = ((SK_U8)pMessage->data[C_OFFSET_IPHEADER] & 0xf)*4; - pTxd->TcpSumOfs = 0; /* PH-Checksum already claculated */ - pTxd->TcpSumSt = C_LEN_ETHERMAC_HEADER + IpHeaderLength + - (Protocol == C_PROTO_ID_UDP ? - C_OFFSET_UDPHEADER_UDPCS : - C_OFFSET_TCPHEADER_TCPCS); - pTxd->TcpSumWr = C_LEN_ETHERMAC_HEADER + IpHeaderLength; - } else { - pTxd->TBControl = BMU_CHECK | BMU_SW | BMU_STF | - skb_headlen(pMessage); - } + pTxd->TcpSumOfs = 0; + pTxd->TcpSumSt = hdrlen; + pTxd->TcpSumWr = offset; + } else + Control = BMU_CHECK | BMU_SW; + + pTxd->TBControl = BMU_STF | Control | skb_headlen(pMessage); pTxd = pTxd->pNextTxd; pTxPort->TxdRingFree--; @@ -1752,40 +1739,18 @@ struct sk_buff *pMessage) /* pointer to send-message */ pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pTxd->pMBuf = pMessage; - /* - ** Does the HW need to evaluate checksum for TCP or UDP packets? - */ - if (pMessage->ip_summed == CHECKSUM_HW) { - pTxd->TBControl = BMU_OWN | BMU_SW | BMU_STFWD; - /* - ** We have to use the opcode for tcp here because the - ** opcode for udp is not working in the hardware yet - ** (revision 2.0) - */ - if ((Protocol == C_PROTO_ID_UDP) && - (pAC->GIni.GIChipRev == 0) && - (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { - pTxd->TBControl |= BMU_TCP_CHECK; - } else { - pTxd->TBControl |= BMU_UDP_CHECK; - } - } else { - pTxd->TBControl = BMU_CHECK | BMU_SW | BMU_OWN; - } + pTxd->TBControl = Control | BMU_OWN | sk_frag->size;; /* ** Do we have the last fragment? */ if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags ) { #ifdef USE_TX_COMPLETE - pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF | sk_frag->size; + pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF; #else - pTxd->TBControl |= BMU_EOF | sk_frag->size; + pTxd->TBControl |= BMU_EOF; #endif pTxdFst->TBControl |= BMU_OWN | BMU_SW; - - } else { - pTxd->TBControl |= sk_frag->size; } pTxdLst = pTxd; pTxd = pTxd->pNextTxd; @@ -2032,7 +1997,6 @@ SK_U32 Control; /* control field of descriptor */ struct sk_buff *pMsg; /* pointer to message holding frame */ struct sk_buff *pNewMsg; /* pointer to a new message for copying frame */ int FrameLength; /* total length of received frame */ -int IpFrameLength; SK_MBUF *pRlmtMbuf; /* ptr to a buffer for giving a frame to rlmt */ SK_EVPARA EvPara; /* an event parameter union */ unsigned long Flags; /* for spin lock */ @@ -2045,10 +2009,6 @@ SK_BOOL IsMc; SK_BOOL IsBadFrame; /* Bad frame */ SK_U32 FrameStat; -unsigned short Csum1; -unsigned short Csum2; -unsigned short Type; -int Result; SK_U64 PhysAddr; rx_start: @@ -2177,8 +2137,8 @@ rx_start: (dma_addr_t) PhysAddr, FrameLength, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(pNewMsg, pMsg->data, - FrameLength, 0); + memcpy(pNewMsg->data, pMsg, FrameLength); + pci_dma_sync_single_for_device(pAC->PciDev, (dma_addr_t) PhysAddr, FrameLength, @@ -2206,69 +2166,16 @@ rx_start: /* set length in message */ skb_put(pMsg, FrameLength); - /* hardware checksum */ - Type = ntohs(*((short*)&pMsg->data[12])); + } /* frame > SK_COPY_TRESHOLD */ #ifdef USE_SK_RX_CHECKSUM - if (Type == 0x800) { - Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff); - Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff); - IpFrameLength = (int) ntohs((unsigned short) - ((unsigned short *) pMsg->data)[8]); - - /* - * Test: If frame is padded, a check is not possible! - * Frame not padded? Length difference must be 14 (0xe)! - */ - if ((FrameLength - IpFrameLength) != 0xe) { - /* Frame padded => TCP offload not possible! */ - pMsg->ip_summed = CHECKSUM_NONE; - } else { - /* Frame not padded => TCP offload! */ - if ((((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) && - (pAC->GIni.GIChipId == CHIP_ID_GENESIS)) || - (pAC->ChipsetType)) { - Result = SkCsGetReceiveInfo(pAC, - &pMsg->data[14], - Csum1, Csum2, pRxPort->PortIndex); - if (Result == - SKCS_STATUS_IP_FRAGMENT || - Result == - SKCS_STATUS_IP_CSUM_OK || - Result == - SKCS_STATUS_TCP_CSUM_OK || - Result == - SKCS_STATUS_UDP_CSUM_OK) { - pMsg->ip_summed = - CHECKSUM_UNNECESSARY; - } - else if (Result == - SKCS_STATUS_TCP_CSUM_ERROR || - Result == - SKCS_STATUS_UDP_CSUM_ERROR || - Result == - SKCS_STATUS_IP_CSUM_ERROR_UDP || - Result == - SKCS_STATUS_IP_CSUM_ERROR_TCP || - Result == - SKCS_STATUS_IP_CSUM_ERROR ) { - /* HW Checksum error */ - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, - SK_DBGCAT_DRV_RX_PROGRESS, - ("skge: CRC error. Frame dropped!\n")); - goto rx_failed; - } else { - pMsg->ip_summed = - CHECKSUM_NONE; - } - }/* checksumControl calculation valid */ - } /* Frame length check */ - } /* IP frame */ + pMsg->csum = pRxd->TcpSums; + pMsg->ip_summed = CHECKSUM_HW; #else - pMsg->ip_summed = CHECKSUM_NONE; + pMsg->ip_summed = CHECKSUM_NONE; #endif - } /* frame > SK_COPY_TRESHOLD */ - + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V")); ForRlmt = SK_RLMT_RX_PROTOCOL; #if 0 @@ -4946,7 +4853,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, dev->irq = pdev->irq; error = SkGeInitPCI(pAC); if (error) { - printk("SKGE: PCI setup failed: %i\n", error); + printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error); goto out_free_netdev; } @@ -4982,7 +4889,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, /* Register net device */ if (register_netdev(dev)) { - printk(KERN_ERR "SKGE: Could not register device.\n"); + printk(KERN_ERR "sk98lin: Could not register device.\n"); goto out_free_resources; } @@ -5001,8 +4908,8 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, SkGeYellowLED(pAC, pAC->IoBase, 1); - memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); SkGeProcCreate(dev); @@ -5048,13 +4955,14 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, #endif if (register_netdev(dev)) { - printk(KERN_ERR "SKGE: Could not register device.\n"); + printk(KERN_ERR "sk98lin: Could not register device for seconf port.\n"); free_netdev(dev); pAC->dev[1] = pAC->dev[0]; } else { SkGeProcCreate(dev); memcpy(&dev->dev_addr, &pAC->Addr.Net[1].CurrentMacAddress, 6); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); printk("%s: %s\n", dev->name, pAC->DeviceStr); printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 596c93b12da..716467879b9 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2300,14 +2300,12 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) td->dma_hi = map >> 32; if (skb->ip_summed == CHECKSUM_HW) { - const struct iphdr *ip - = (const struct iphdr *) (skb->data + ETH_HLEN); int offset = skb->h.raw - skb->data; /* This seems backwards, but it is what the sk98lin * does. Looks like hardware is wrong? */ - if (ip->protocol == IPPROTO_UDP + if (skb->h.ipiph->protocol == IPPROTO_UDP && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON) control = BMU_TCP_CHECK; else diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 340ab4ee4b6..7a92b1cbd6a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2755,8 +2755,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, SET_NETDEV_DEV(dev, dmdev); - if (test_bit(FLAG_MPI,&ai->flags)) - reset_card (dev, 1); + reset_card (dev, 1); + msleep(400); rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev ); if (rc) { diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 488ab06fb79..6fd0bf73683 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -3512,9 +3512,8 @@ static int orinoco_ioctl_setpower(struct net_device *dev, break; default: err = -EINVAL; - } - if (err) goto out; + } if (prq->flags & IW_POWER_TIMEOUT) { priv->pm_on = 1; diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index c218b5c944a..5e84c5aa777 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -996,6 +996,20 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) spin_lock_init(&adapter->fsf_req_list_lock); INIT_LIST_HEAD(&adapter->fsf_req_list_head); + /* initialize debug locks */ + + spin_lock_init(&adapter->erp_dbf_lock); + spin_lock_init(&adapter->hba_dbf_lock); + spin_lock_init(&adapter->san_dbf_lock); + spin_lock_init(&adapter->scsi_dbf_lock); + + /* initialize error recovery stuff */ + + rwlock_init(&adapter->erp_lock); + sema_init(&adapter->erp_ready_sem, 0); + INIT_LIST_HEAD(&adapter->erp_ready_head); + INIT_LIST_HEAD(&adapter->erp_running_head); + /* initialize abort lock */ rwlock_init(&adapter->abort_lock); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 826fb3b0060..95599719f8a 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -926,7 +926,6 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) char dbf_name[DEBUG_MAX_NAME_LEN]; /* debug feature area which records recovery activity */ - spin_lock_init(&adapter->erp_dbf_lock); sprintf(dbf_name, "zfcp_%s_erp", zfcp_get_busid_by_adapter(adapter)); adapter->erp_dbf = debug_register(dbf_name, dbfsize, 2, sizeof(struct zfcp_erp_dbf_record)); @@ -936,7 +935,6 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) debug_set_level(adapter->erp_dbf, 3); /* debug feature area which records HBA (FSF and QDIO) conditions */ - spin_lock_init(&adapter->hba_dbf_lock); sprintf(dbf_name, "zfcp_%s_hba", zfcp_get_busid_by_adapter(adapter)); adapter->hba_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_hba_dbf_record)); @@ -947,7 +945,6 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) debug_set_level(adapter->hba_dbf, 3); /* debug feature area which records SAN command failures and recovery */ - spin_lock_init(&adapter->san_dbf_lock); sprintf(dbf_name, "zfcp_%s_san", zfcp_get_busid_by_adapter(adapter)); adapter->san_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_san_dbf_record)); @@ -958,7 +955,6 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) debug_set_level(adapter->san_dbf, 6); /* debug feature area which records SCSI command failures and recovery */ - spin_lock_init(&adapter->scsi_dbf_lock); sprintf(dbf_name, "zfcp_%s_scsi", zfcp_get_busid_by_adapter(adapter)); adapter->scsi_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_scsi_dbf_record)); diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 023f4e558ae..ee7314d8c2d 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1071,11 +1071,6 @@ zfcp_erp_thread_setup(struct zfcp_adapter *adapter) atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); - rwlock_init(&adapter->erp_lock); - INIT_LIST_HEAD(&adapter->erp_ready_head); - INIT_LIST_HEAD(&adapter->erp_running_head); - sema_init(&adapter->erp_ready_sem, 0); - retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); if (retval < 0) { ZFCP_LOG_NORMAL("error: creation of erp thread failed for " @@ -2248,29 +2243,26 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action) return retval; } -/* - * function: zfcp_fsf_init - * - * purpose: initializes FSF operation for the specified adapter - * - * returns: 0 - succesful initialization of FSF operation - * !0 - failed to initialize FSF operation - */ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action) { - int xconfig, xport; + int retval; - if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, - &erp_action->adapter->status)) { + if ((atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &erp_action->adapter->status)) && + (erp_action->adapter->adapter_features & + FSF_FEATURE_HBAAPI_MANAGEMENT)) { zfcp_erp_adapter_strategy_open_fsf_xport(erp_action); atomic_set(&erp_action->adapter->erp_counter, 0); return ZFCP_ERP_FAILED; } - xconfig = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action); - xport = zfcp_erp_adapter_strategy_open_fsf_xport(erp_action); - if ((xconfig == ZFCP_ERP_FAILED) || (xport == ZFCP_ERP_FAILED)) + retval = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action); + if (retval == ZFCP_ERP_FAILED) + return ZFCP_ERP_FAILED; + + retval = zfcp_erp_adapter_strategy_open_fsf_xport(erp_action); + if (retval == ZFCP_ERP_FAILED) return ZFCP_ERP_FAILED; return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); @@ -2359,41 +2351,29 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) { - int retval = ZFCP_ERP_SUCCEEDED; + int ret; int retries; int sleep; struct zfcp_adapter *adapter = erp_action->adapter; atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); - for (retries = 0; ; retries++) { - ZFCP_LOG_DEBUG("Doing exchange port data\n"); + retries = 0; + do { + write_lock(&adapter->erp_lock); zfcp_erp_action_to_running(erp_action); + write_unlock(&adapter->erp_lock); zfcp_erp_timeout_init(erp_action); - if (zfcp_fsf_exchange_port_data(erp_action, adapter, NULL)) { - retval = ZFCP_ERP_FAILED; - debug_text_event(adapter->erp_dbf, 5, "a_fstx_xf"); - ZFCP_LOG_INFO("error: initiation of exchange of " - "port data failed for adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - break; + ret = zfcp_fsf_exchange_port_data(erp_action, adapter, NULL); + if (ret == -EOPNOTSUPP) { + debug_text_event(adapter->erp_dbf, 3, "a_xport_notsupp"); + return ZFCP_ERP_SUCCEEDED; + } else if (ret) { + debug_text_event(adapter->erp_dbf, 3, "a_xport_failed"); + return ZFCP_ERP_FAILED; } - debug_text_event(adapter->erp_dbf, 6, "a_fstx_xok"); - ZFCP_LOG_DEBUG("Xchange underway\n"); + debug_text_event(adapter->erp_dbf, 6, "a_xport_ok"); - /* - * Why this works: - * Both the normal completion handler as well as the timeout - * handler will do an 'up' when the 'exchange port data' - * request completes or times out. Thus, the signal to go on - * won't be lost utilizing this semaphore. - * Furthermore, this 'adapter_reopen' action is - * guaranteed to be the only action being there (highest action - * which prevents other actions from being created). - * Resulting from that, the wake signal recognized here - * _must_ be the one belonging to the 'exchange port - * data' request. - */ down(&adapter->erp_ready_sem); if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { ZFCP_LOG_INFO("error: exchange of port data " @@ -2401,29 +2381,19 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) zfcp_get_busid_by_adapter(adapter)); break; } - if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status)) break; - ZFCP_LOG_DEBUG("host connection still initialising... " - "waiting and retrying...\n"); - /* sleep a little bit before retry */ - sleep = retries < ZFCP_EXCHANGE_PORT_DATA_SHORT_RETRIES ? - ZFCP_EXCHANGE_PORT_DATA_SHORT_SLEEP : - ZFCP_EXCHANGE_PORT_DATA_LONG_SLEEP; - msleep(jiffies_to_msecs(sleep)); - } - - if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, - &adapter->status)) { - ZFCP_LOG_INFO("error: exchange of port data for " - "adapter %s failed\n", - zfcp_get_busid_by_adapter(adapter)); - retval = ZFCP_ERP_FAILED; - } + if (retries < ZFCP_EXCHANGE_PORT_DATA_SHORT_RETRIES) { + sleep = ZFCP_EXCHANGE_PORT_DATA_SHORT_SLEEP; + retries++; + } else + sleep = ZFCP_EXCHANGE_PORT_DATA_LONG_SLEEP; + schedule_timeout(sleep); + } while (1); - return retval; + return ZFCP_ERP_SUCCEEDED; } /* diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 3b0fc1163f5..59587951c84 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -554,6 +554,17 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter, struct fsf_link_down_info *link_down) { + if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &adapter->status)) + return; + + atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); + + if (link_down == NULL) { + zfcp_erp_adapter_reopen(adapter, 0); + return; + } + switch (link_down->error_code) { case FSF_PSQ_LINK_NO_LIGHT: ZFCP_LOG_NORMAL("The local link to adapter %s is down " @@ -634,20 +645,15 @@ zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter, link_down->explanation_code, link_down->vendor_specific_code); - if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, - &adapter->status)) { - atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, - &adapter->status); - switch (link_down->error_code) { - case FSF_PSQ_LINK_NO_LIGHT: - case FSF_PSQ_LINK_WRAP_PLUG: - case FSF_PSQ_LINK_NO_FCP: - case FSF_PSQ_LINK_FIRMWARE_UPDATE: - zfcp_erp_adapter_reopen(adapter, 0); - break; - default: - zfcp_erp_adapter_failed(adapter); - } + switch (link_down->error_code) { + case FSF_PSQ_LINK_NO_LIGHT: + case FSF_PSQ_LINK_WRAP_PLUG: + case FSF_PSQ_LINK_NO_FCP: + case FSF_PSQ_LINK_FIRMWARE_UPDATE: + zfcp_erp_adapter_reopen(adapter, 0); + break; + default: + zfcp_erp_adapter_failed(adapter); } } @@ -919,30 +925,36 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: ZFCP_LOG_INFO("Physical link to adapter %s is down\n", zfcp_get_busid_by_adapter(adapter)); + zfcp_fsf_link_down_info_eval(adapter, + (struct fsf_link_down_info *) + &status_buffer->payload); break; case FSF_STATUS_READ_SUB_FDISC_FAILED: ZFCP_LOG_INFO("Local link to adapter %s is down " "due to failed FDISC login\n", - zfcp_get_busid_by_adapter(adapter)); + zfcp_get_busid_by_adapter(adapter)); + zfcp_fsf_link_down_info_eval(adapter, + (struct fsf_link_down_info *) + &status_buffer->payload); break; case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: ZFCP_LOG_INFO("Local link to adapter %s is down " "due to firmware update on adapter\n", zfcp_get_busid_by_adapter(adapter)); + zfcp_fsf_link_down_info_eval(adapter, NULL); break; default: ZFCP_LOG_INFO("Local link to adapter %s is down " "due to unknown reason\n", zfcp_get_busid_by_adapter(adapter)); + zfcp_fsf_link_down_info_eval(adapter, NULL); }; - zfcp_fsf_link_down_info_eval(adapter, - (struct fsf_link_down_info *) &status_buffer->payload); break; case FSF_STATUS_READ_LINK_UP: ZFCP_LOG_NORMAL("Local link to adapter %s was replugged. " - "Restarting operations on this adapter\n", - zfcp_get_busid_by_adapter(adapter)); + "Restarting operations on this adapter\n", + zfcp_get_busid_by_adapter(adapter)); /* All ports should be marked as ready to run again */ zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING, @@ -2191,13 +2203,10 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action, return -EOPNOTSUPP; } - timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); - if (!timer) - return -ENOMEM; - /* setup new FSF request */ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, - 0, 0, &lock_flags, &fsf_req); + erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0, + 0, &lock_flags, &fsf_req); if (retval < 0) { ZFCP_LOG_INFO("error: Out of resources. Could not create an " "exchange port data request for" @@ -2205,25 +2214,33 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action, zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); - goto out; - } - - if (erp_action) { - erp_action->fsf_req = fsf_req; - fsf_req->erp_action = erp_action; + return retval; } if (data) - fsf_req->data = (unsigned long) data; + fsf_req->data = (unsigned long) data; sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - init_timer(timer); - timer->function = zfcp_fsf_request_timeout_handler; - timer->data = (unsigned long) adapter; - timer->expires = ZFCP_FSF_REQUEST_TIMEOUT; + if (erp_action) { + erp_action->fsf_req = fsf_req; + fsf_req->erp_action = erp_action; + timer = &erp_action->timer; + } else { + timer = kmalloc(sizeof(struct timer_list), GFP_ATOMIC); + if (!timer) { + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + zfcp_fsf_req_free(fsf_req); + return -ENOMEM; + } + init_timer(timer); + timer->function = zfcp_fsf_request_timeout_handler; + timer->data = (unsigned long) adapter; + timer->expires = ZFCP_FSF_REQUEST_TIMEOUT; + } retval = zfcp_fsf_req_send(fsf_req, timer); if (retval) { @@ -2233,23 +2250,22 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action, zfcp_fsf_req_free(fsf_req); if (erp_action) erp_action->fsf_req = NULL; + else + kfree(timer); write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); - goto out; + return retval; } - ZFCP_LOG_DEBUG("Exchange Port Data request initiated (adapter %s)\n", - zfcp_get_busid_by_adapter(adapter)); - - write_unlock_irqrestore(&adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); - wait_event(fsf_req->completion_wq, - fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); - del_timer_sync(timer); - zfcp_fsf_req_free(fsf_req); - out: - kfree(timer); + if (!erp_action) { + wait_event(fsf_req->completion_wq, + fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + del_timer_sync(timer); + zfcp_fsf_req_free(fsf_req); + kfree(timer); + } return retval; } diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 3dcd1bfba3b..66608d13a63 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -179,7 +179,7 @@ zfcp_scsi_slave_alloc(struct scsi_device *sdp) struct zfcp_adapter *adapter; struct zfcp_unit *unit; unsigned long flags; - int retval = -ENODEV; + int retval = -ENXIO; adapter = (struct zfcp_adapter *) sdp->host->hostdata[0]; if (!adapter) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index ab383d1f59e..3cb68af9045 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -325,6 +325,8 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, * translations ( 64/32, 128/32, 255/63 ). */ buf = scsi_bios_ptable(bdev); + if (!buf) + return 0; if(*(__le16 *)(buf + 0x40) == cpu_to_le16(0xaa55)) { struct partition *first = (struct partition * )buf; struct partition *entry = first; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 31e9f40e79a..6aab9dacdee 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -2105,7 +2105,7 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) scmd_id(cmd), scmd_channel(cmd) + 'A', CAM_LUN_WILDCARD, - SCB_LIST_NULL, ROLE_INITIATOR) == 0) + SCB_LIST_NULL, ROLE_INITIATOR)) break; } } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 7fc6454068e..d866213f42b 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -2169,7 +2169,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) if (ahc_match_scb(ahc, pending_scb, scmd_id(cmd), scmd_channel(cmd) + 'A', CAM_LUN_WILDCARD, - SCB_LIST_NULL, ROLE_INITIATOR) == 0) + SCB_LIST_NULL, ROLE_INITIATOR)) break; } } diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 3b4ca55a333..379e8708976 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -2239,7 +2239,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) struct scsi_cmnd *cmd = qc->scsicmd; if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN) - return 1; + goto invalid_fld; /* * 12 and 16 byte CDBs use different offsets to @@ -2301,7 +2301,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) */ if ((tf->command == ATA_CMD_SET_FEATURES) && (tf->feature == SETFEATURES_XFER)) - return 1; + goto invalid_fld; /* * Set flags so that all registers will be written, @@ -2322,6 +2322,11 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) qc->nsect = cmd->bufflen / ATA_SECT_SIZE; return 0; + + invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x00); + /* "Invalid field in cdb" */ + return 1; } /** diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ce9d73a292e..4afef5cdcb1 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -542,17 +542,10 @@ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd) void scsi_next_command(struct scsi_cmnd *cmd) { - struct scsi_device *sdev = cmd->device; - struct request_queue *q = sdev->request_queue; - - /* need to hold a reference on the device before we let go of the cmd */ - get_device(&sdev->sdev_gendev); + struct request_queue *q = cmd->device->request_queue; scsi_put_command(cmd); scsi_run_queue(q); - - /* ok to remove device now */ - put_device(&sdev->sdev_gendev); } void scsi_run_host_queues(struct Scsi_Host *shost) diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 718a2bc4ed5..38a53b5f9e9 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -812,12 +812,10 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) if (!scsi_device_sync(sdev) && !scsi_device_dt(sdev)) return; - /* see if the device has an echo buffer. If it does we can - * do the SPI pattern write tests */ - - len = 0; - if (scsi_device_dt(sdev)) - len = spi_dv_device_get_echo_buffer(sdev, buffer); + /* len == -1 is the signal that we need to ascertain the + * presence of an echo buffer before trying to use it. len == + * 0 means we don't have an echo buffer */ + len = -1; retry: @@ -840,11 +838,23 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) if (spi_min_period(starget) == 8) DV_SET(pcomp_en, 1); } + /* Do the read only INQUIRY tests */ + spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len, + spi_dv_device_compare_inquiry); + /* See if we actually managed to negotiate and sustain DT */ + if (i->f->get_dt) + i->f->get_dt(starget); + + /* see if the device has an echo buffer. If it does we can do + * the SPI pattern write tests. Because of some broken + * devices, we *only* try this on a device that has actually + * negotiated DT */ + + if (len == -1 && spi_dt(starget)) + len = spi_dv_device_get_echo_buffer(sdev, buffer); - if (len == 0) { + if (len <= 0) { starget_printk(KERN_INFO, starget, "Domain Validation skipping write tests\n"); - spi_dv_retrain(sdev, buffer, buffer + len, - spi_dv_device_compare_inquiry); return; } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 72ec59456e6..b55c2a8a547 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1860,9 +1860,11 @@ st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, unlock_page(pages[j]); */ res = 0; out_unmap: - if (res > 0) + if (res > 0) { for (j=0; j < res; j++) page_cache_release(pages[j]); + res = 0; + } kfree(pages); return res; } @@ -1878,8 +1880,6 @@ st_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages, for (i=0; i < nr_pages; i++) { struct page *page = sgl[i].page; - /* XXX: just for debug. Remove when PageReserved is removed */ - BUG_ON(PageReserved(page)); if (dirtied) SetPageDirty(page); /* unlock_page(page); */ diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 770c4324f3d..7ac6ea141ff 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4509,6 +4509,7 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa if (res > 0) { for (j=0; j < res; j++) page_cache_release(pages[j]); + res = 0; } kfree(pages); return res; @@ -4524,8 +4525,6 @@ static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_p for (i=0; i < nr_pages; i++) { struct page *page = sgl[i].page; - /* XXX: just for debug. Remove when PageReserved is removed */ - BUG_ON(PageReserved(page)); if (dirtied) SetPageDirty(page); /* FIXME: cache flush missing for rw==READ diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index d76766c3ce1..7fc0b97173e 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -2086,6 +2086,7 @@ static void sym2_set_dt(struct scsi_target *starget, int dt) tp->tgoal.check_nego = 1; } +#if 0 static void sym2_set_iu(struct scsi_target *starget, int iu) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -2111,7 +2112,7 @@ static void sym2_set_qas(struct scsi_target *starget, int qas) tp->tgoal.qas = 0; tp->tgoal.check_nego = 1; } - +#endif static struct spi_function_template sym2_transport_functions = { .set_offset = sym2_set_offset, @@ -2122,10 +2123,12 @@ static struct spi_function_template sym2_transport_functions = { .show_width = 1, .set_dt = sym2_set_dt, .show_dt = 1, +#if 0 .set_iu = sym2_set_iu, .show_iu = 1, .set_qas = sym2_set_qas, .show_qas = 1, +#endif .get_signalling = sym2_get_signalling, }; diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 79861ee12a2..9d59dc62e6d 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -787,6 +787,9 @@ static const struct usb_device_id cxacru_usb_ids[] = { { /* V = Conexant P = ADSL modem (Hasbani project) */ USB_DEVICE(0x0572, 0xcb00), .driver_info = (unsigned long) &cxacru_cb00 }, + { /* V = Conexant P = ADSL modem (Well PTI-800 */ + USB_DEVICE(0x0572, 0xcb02), .driver_info = (unsigned long) &cxacru_cb00 + }, { /* V = Conexant P = ADSL modem */ USB_DEVICE(0x0572, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00 }, diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 5131d88e8c5..29b5b2a6e18 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -219,6 +219,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) goto done; } } + synchronize_irq(dev->irq); /* FIXME until the generic PM interfaces change a lot more, this * can't use PCI D1 and D2 states. For example, the confusion @@ -392,7 +393,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev) dev->dev.power.power_state = PMSG_ON; - hcd->saw_irq = 0; + clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); if (hcd->driver->resume) { retval = hcd->driver->resume(hcd); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 5e5f65a475a..da24c31ee00 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1315,11 +1315,12 @@ static int hcd_unlink_urb (struct urb *urb, int status) * finish unlinking the initial failed usb_set_address() * or device descriptor fetch. */ - if (!hcd->saw_irq && hcd->self.root_hub != urb->dev) { + if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) + && hcd->self.root_hub != urb->dev) { dev_warn (hcd->self.controller, "Unlink after no-IRQ? " "Controller is probably using the wrong IRQ." "\n"); - hcd->saw_irq = 1; + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); } urb->status = status; @@ -1649,13 +1650,15 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) struct usb_hcd *hcd = __hcd; int start = hcd->state; - if (start == HC_STATE_HALT) + if (unlikely(start == HC_STATE_HALT || + !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) return IRQ_NONE; if (hcd->driver->irq (hcd, r) == IRQ_NONE) return IRQ_NONE; - hcd->saw_irq = 1; - if (hcd->state == HC_STATE_HALT) + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + + if (unlikely(hcd->state == HC_STATE_HALT)) usb_hc_died (hcd); return IRQ_HANDLED; } @@ -1768,6 +1771,8 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + /* till now HC has been in an indeterminate state ... */ if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { dev_err(hcd->self.controller, "can't reset\n"); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 24a62a2ff86..c8a1b350e2c 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -72,7 +72,12 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ * hardware info/state */ const struct hc_driver *driver; /* hw-specific hooks */ - unsigned saw_irq : 1; + + /* Flags that need to be manipulated atomically */ + unsigned long flags; +#define HCD_FLAG_HW_ACCESSIBLE 0x00000001 +#define HCD_FLAG_SAW_IRQ 0x00000002 + unsigned can_wakeup:1; /* hw supports wakeup? */ unsigned remote_wakeup:1;/* sw should use wakeup? */ unsigned rh_registered:1;/* is root hub registered? */ diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 441c26064b4..13f73a836e4 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -121,8 +121,8 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) return 0; } -/* called by khubd or root hub (re)init threads; leaves HC in halt state */ -static int ehci_pci_reset(struct usb_hcd *hcd) +/* called during probe() after chip reset completes */ +static int ehci_pci_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); @@ -141,6 +141,11 @@ static int ehci_pci_reset(struct usb_hcd *hcd) if (retval) return retval; + /* data structure init */ + retval = ehci_init(hcd); + if (retval) + return retval; + /* NOTE: only the parts below this line are PCI-specific */ switch (pdev->vendor) { @@ -154,7 +159,8 @@ static int ehci_pci_reset(struct usb_hcd *hcd) /* AMD8111 EHCI doesn't work, according to AMD errata */ if (pdev->device == 0x7463) { ehci_info(ehci, "ignoring AMD8111 (errata)\n"); - return -EIO; + retval = -EIO; + goto done; } break; case PCI_VENDOR_ID_NVIDIA: @@ -207,9 +213,8 @@ static int ehci_pci_reset(struct usb_hcd *hcd) /* REVISIT: per-port wake capability (PCI 0x62) currently unused */ retval = ehci_pci_reinit(ehci, pdev); - - /* finish init */ - return ehci_init(hcd); +done: + return retval; } /*-------------------------------------------------------------------------*/ @@ -228,14 +233,36 @@ static int ehci_pci_reset(struct usb_hcd *hcd) static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); + unsigned long flags; + int rc = 0; if (time_before(jiffies, ehci->next_statechange)) msleep(10); + /* Root hub was already suspended. Disable irq emission and + * mark HW unaccessible, bail out if RH has been resumed. Use + * the spinlock to properly synchronize with possible pending + * RH suspend or resume activity. + * + * This is still racy as hcd->state is manipulated outside of + * any locks =P But that will be a different fix. + */ + spin_lock_irqsave (&ehci->lock, flags); + if (hcd->state != HC_STATE_SUSPENDED) { + rc = -EINVAL; + goto bail; + } + writel (0, &ehci->regs->intr_enable); + (void)readl(&ehci->regs->intr_enable); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + bail: + spin_unlock_irqrestore (&ehci->lock, flags); + // could save FLADJ in case of Vaux power loss // ... we'd only use it to handle clock skew - return 0; + return rc; } static int ehci_pci_resume(struct usb_hcd *hcd) @@ -251,6 +278,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd) if (time_before(jiffies, ehci->next_statechange)) msleep(100); + /* Mark hardware accessible again as we are out of D3 state by now */ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + /* If CF is clear, we lost PCI Vaux power and need to restart. */ if (readl(&ehci->regs->configured_flag) != FLAG_CF) goto restart; @@ -319,7 +349,7 @@ static const struct hc_driver ehci_pci_hc_driver = { /* * basic lifecycle operations */ - .reset = ehci_pci_reset, + .reset = ehci_pci_setup, .start = ehci_run, #ifdef CONFIG_PM .suspend = ehci_pci_suspend, diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 5bb872c3496..bf03ec0d8ee 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -912,6 +912,7 @@ submit_async ( int epnum; unsigned long flags; struct ehci_qh *qh = NULL; + int rc = 0; qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); epnum = ep->desc.bEndpointAddress; @@ -926,21 +927,28 @@ submit_async ( #endif spin_lock_irqsave (&ehci->lock, flags); + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, + &ehci_to_hcd(ehci)->flags))) { + rc = -ESHUTDOWN; + goto done; + } + qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + if (unlikely(qh == NULL)) { + rc = -ENOMEM; + goto done; + } /* Control/bulk operations through TTs don't need scheduling, * the HC and TT handle it when the TT has a buffer ready. */ - if (likely (qh != NULL)) { - if (likely (qh->qh_state == QH_STATE_IDLE)) - qh_link_async (ehci, qh_get (qh)); - } + if (likely (qh->qh_state == QH_STATE_IDLE)) + qh_link_async (ehci, qh_get (qh)); + done: spin_unlock_irqrestore (&ehci->lock, flags); - if (unlikely (qh == NULL)) { + if (unlikely (qh == NULL)) qtd_list_free (ehci, urb, qtd_list); - return -ENOMEM; - } - return 0; + return rc; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index f0c8aa1ccd5..57e77374d22 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -602,6 +602,12 @@ static int intr_submit ( spin_lock_irqsave (&ehci->lock, flags); + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, + &ehci_to_hcd(ehci)->flags))) { + status = -ESHUTDOWN; + goto done; + } + /* get qh and force any scheduling errors */ INIT_LIST_HEAD (&empty); qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv); @@ -1456,7 +1462,11 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); - status = iso_stream_schedule (ehci, urb, stream); + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, + &ehci_to_hcd(ehci)->flags))) + status = -ESHUTDOWN; + else + status = iso_stream_schedule (ehci, urb, stream); if (likely (status == 0)) itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); spin_unlock_irqrestore (&ehci->lock, flags); @@ -1815,7 +1825,11 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); - status = iso_stream_schedule (ehci, urb, stream); + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, + &ehci_to_hcd(ehci)->flags))) + status = -ESHUTDOWN; + else + status = iso_stream_schedule (ehci, urb, stream); if (status == 0) sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); spin_unlock_irqrestore (&ehci->lock, flags); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 5c0c6c8a7a8..bf1d9abc07a 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -115,7 +115,7 @@ /*-------------------------------------------------------------------------*/ -// #define OHCI_VERBOSE_DEBUG /* not always helpful */ +#undef OHCI_VERBOSE_DEBUG /* not always helpful */ /* For initializing controller (mask in an HCFS mode too) */ #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR @@ -253,6 +253,10 @@ static int ohci_urb_enqueue ( spin_lock_irqsave (&ohci->lock, flags); /* don't submit to a dead HC */ + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + retval = -ENODEV; + goto fail; + } if (!HC_IS_RUNNING(hcd->state)) { retval = -ENODEV; goto fail; diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index e01e77bc324..72e3b12a192 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -53,6 +53,11 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) spin_lock_irqsave (&ohci->lock, flags); + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { + spin_unlock_irqrestore (&ohci->lock, flags); + return -ESHUTDOWN; + } + ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_RESUME: @@ -140,11 +145,19 @@ static int ohci_bus_resume (struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); u32 temp, enables; int status = -EINPROGRESS; + unsigned long flags; if (time_before (jiffies, ohci->next_statechange)) msleep(5); - spin_lock_irq (&ohci->lock); + spin_lock_irqsave (&ohci->lock, flags); + + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { + spin_unlock_irqrestore (&ohci->lock, flags); + return -ESHUTDOWN; + } + + ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { @@ -179,7 +192,7 @@ static int ohci_bus_resume (struct usb_hcd *hcd) ohci_dbg (ohci, "lost power\n"); status = -EBUSY; } - spin_unlock_irq (&ohci->lock); + spin_unlock_irqrestore (&ohci->lock, flags); if (status == -EBUSY) { (void) ohci_init (ohci); return ohci_restart (ohci); @@ -297,8 +310,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) /* handle autosuspended root: finish resuming before * letting khubd or root hub timer see state changes. */ - if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER - || !HC_IS_RUNNING(hcd->state)) { + if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER + || !HC_IS_RUNNING(hcd->state))) { can_suspend = 0; goto done; } @@ -508,6 +521,9 @@ static int ohci_hub_control ( u32 temp; int retval = 0; + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) + return -ESHUTDOWN; + switch (typeReq) { case ClearHubFeature: switch (wValue) { diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 5f22e6590cd..1b09dde068e 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -105,13 +105,36 @@ ohci_pci_start (struct usb_hcd *hcd) static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) { - /* root hub was already suspended */ - return 0; + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + unsigned long flags; + int rc = 0; + + /* Root hub was already suspended. Disable irq emission and + * mark HW unaccessible, bail out if RH has been resumed. Use + * the spinlock to properly synchronize with possible pending + * RH suspend or resume activity. + * + * This is still racy as hcd->state is manipulated outside of + * any locks =P But that will be a different fix. + */ + spin_lock_irqsave (&ohci->lock, flags); + if (hcd->state != HC_STATE_SUSPENDED) { + rc = -EINVAL; + goto bail; + } + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + (void)ohci_readl(ohci, &ohci->regs->intrdisable); + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + bail: + spin_unlock_irqrestore (&ohci->lock, flags); + + return rc; } static int ohci_pci_resume (struct usb_hcd *hcd) { + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); usb_hcd_resume_root_hub(hcd); return 0; } diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index d33ce3982a5..ed550132db0 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -717,6 +717,7 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) * at the source, so we must turn off PIRQ. */ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); uhci->hc_inaccessible = 1; hcd->poll_rh = 0; @@ -733,6 +734,11 @@ static int uhci_resume(struct usb_hcd *hcd) dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); + /* We aren't in D3 state anymore, we do that even if dead as I + * really don't want to keep a stale HCD_FLAG_HW_ACCESSIBLE=0 + */ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + if (uhci->rh_state == UHCI_RH_RESET) /* Dead */ return 0; spin_lock_irq(&uhci->lock); |